Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

developerWorks Community:

  • Close [x]

Learning PHP, Part 3: Authentication, objects, exceptions, and streaming

Nicholas Chase is the founder and creator of NoTooMi. In addition to technical writing for large corporations, he has been involved in website development for companies such as Lucent Technologies, Sun Microsystems, Oracle, and the Tampa Bay Buccaneers. He has been a high school physics teacher, a low-level-radioactive waste facility manager, an online science fiction magazine editor, a multimedia engineer, an Oracle instructor, and the chief technology officer of an interactive communications company. He is the author of several books, including XML Primer Plus (Sams 2002).

Summary:  This tutorial is Part 3 of a three-part "Learning PHP" series teaching you how to use PHP through building a simple workflow application. In this tutorial, you will learn about using HTTP authentication, streaming files, and how to create objects and exceptions.

03 Jan 2013 - Nicholas Chase updated content throughout this tutorial to reflect current PHP technology.

View more content in this series

Date:  03 Jan 2013 (Published 12 Jul 2005)
Level:  Intermediate PDF:  A4 and Letter (792 KB | 36 pages)Get Adobe® Reader®

Comments:  

Using objects

In this section, you explore the use of objects. So far, almost everything you've done has been procedural, meaning you have a script that pretty much runs from beginning to end. Now you will move away from that.

What are objects, anyway?

The central concept of object-oriented programming is the idea that you can represent "things" as a self-sufficient bundle. For example, an electric kettle has properties, such as its color and maximum temperature, and capabilities, such as heating the water and turning itself off.

If you were to represent that kettle as an object, it would also have properties, such as color and maximumTemperature, and capabilities—or methods—such as heatWater() and turnOff(). If you were writing a program that interfaced with the kettle, you would simply call the kettle object's heatWater() method, rather than worrying about how it's actually done.

To make things a bit more relevant, you're going to create an object that represents a file to be downloaded. It will have properties, such as the name and type of the file, and methods, such as download().

Having said all that, however, I need to point out that you don't actually define an object. Instead, you define a class of objects. A class acts as a kind of "template" for objects of that type. You then create an instance of that class, and that instance is the object.

Let's start by creating the actual class.


Creating the WFDocument class

The first step in dealing with objects is to create the class on which they are based. You could add this definition to the scripts.txt file, but you're trying to make the code more maintainable, not less. So, create a separate file, WFDocument.php, and save it in the main directory. Add the code in Listing 14.


Listing 14. The basic document Object
<?php

include_once("scripts.txt");

class WFDocument {

   function download($filename, $filetype) {

      $filepath = UPLOADEDFILES.$filename;

      if($stream = fopen($filepath, "rb")){
        $file_contents = stream_get_contents($stream);
        header("Content-type: ".$filetype);
        print($file_contents);
      }
   }
}

?>

First, you need the UPLOADEDFILES constant, so you include the scripts.txt file. Next, you create the actual class. The WFDocument class has only a single method, download(), which is the same as the code in download_file.php, with the exception of receiving the file name and type as inputs to the function rather than directly extracting them from the $_GET array.

Now let's look at instantiating this class.


Calling the WFDocument-type object

You actually already instantiated several objects when you worked with DOM in Part 2 of this series, but little was said about why or how. I will remedy that now.

Open the download_file.php page and change the code so it reads as in Listing 15.


Listing 15. Sending the file information to the function
<?php

   include ("../WFDocument.php");

   $filetype = $_GET['filetype'];
   $filename = $_GET['file'];

   $wfdocument = new WFDocument();
   $wfdocument->download($filename, $filetype);

?>

First, rather than include the scripts.txt file, you include the definition of the WFDocument class, which you put into the WFDocument.php file. (Some developers find it useful to simply create a page that includes all their classes, then include that page rather than including individual classes all over the place.)

Now you're ready to create a new object, which you do using the new keyword. This line creates a new object of the type WFDocument and assigns it to the $wfdocument variable.

Once you have a reference to that object, you can call any of its public methods. In this case, there's only one method, download(), and you call it using the -> operator. Basically, this symbol says, "Use the method (or property) that belongs to this object."

Save the file and test it by clicking one of the links on your page. The code is exactly the same as it was before. The only difference is how you call it.


Creating properties

Methods are only part of the story. The whole point of an object is that it's encapsulated. It should contain all its own information, so rather than feed the name and file type to the download() method, you can set them as properties on the object. First you have to create them in the class (see Listing 16).


Listing 16. Using object properties
<?php
include_once("../scripts.txt");

class WFDocument {

   public $filename;
   public $filetype;

   function download() {

      $filepath = UPLOADEDFILES.$this->filename;

      if($stream = fopen($filepath, "rb")){
        $file_contents = stream_get_contents($stream);
        header("Content-type: ".$this->filetype);
        print($file_contents);
      }
   }
}

?>

Notice that you declare the variables outside the function; they're part of the class and not the function. You also declare them as public, which means you can access them from outside the class itself. You can also set a property as private, which means you can use it only within the class itself, or protected, which means you can use it only within the class or any classes based on this one. (If you're unfamiliar with this idea, hang on for a little while. I will talk more about this concept, inheritance, in Creating a custom exception.)

Finally, to reference an object property, you must know which object owns the property. Within an object itself, you can just use the keyword $this, which refers to the object itself. This way, you can use $this->filename to refer to the filename property of the object executing this code.

Now let's look at setting values for these properties.


Setting properties

Rather than pass information to an object, you want to actually set the properties of the object (see Listing 17).


Listing 17. Setting object properties
<?php

   include ("../WFDocument.php");

   $filetype = $_GET['filetype'];
   $filename = $_GET['file'];

   $wfdocument = new WFDocument();
   $wfdocument->filename = $filename;
   $wfdocument->filetype = $filetype;
   $wfdocument->download();

?>

Notice the notation here. You're using the object name, $wfdocument, the -> operator, and the name of the property. Once these properties are set, they're available from inside the object, so you don't have to pass them to the download() method.

Now, having done all that, there is actually a better way to handle this kind of thing, so let's look at an alternative.


Hiding properties

Although it's certainly possible to set the value of a property directly, as you did in the previous section, it's not the best way to handle things. Instead, the general practice is to hide the actual properties from the public and use getters and setters to get and set their values, as in Listing 18.


Listing 18. Using private properties
<?php

include_once("../scripts.txt");

class WFDocument {

   private $filename;
   private $filetype;

      function setFilename($newFilename){
      $this->filename = $newFilename;
   }
   function getFilename(){
      return $this->filename;
   }

   function setFiletype($newFiletype){
      $this->filetype = $newFiletype;
   }
   function getFiletype(){
      return $this->filetype;
   }

   function download() {

      $filepath = UPLOADEDFILES.$this->getFilename();

      if($stream = fopen($filepath, "rb")){
        $file_contents = stream_get_contents($stream);
        header("Content-type: ".$this->getFiletype());
        print($file_contents);
      }
   }
}

?>

First, you define the properties as private. That means that if you try to set them directly, as you did earlier, you'll get an error. But you still have to set these values, so instead you use the getFilename(), setFilename(), getFiletype(), and setFiletype() methods. Notice that you use them here in the download() method, just as you would have used the original property.

Using getters and setters is handy because it gives you more control over what's happening to your data. For example, you might want to perform certain validation checks before you allow a particular value to be set for a property.


Calling hidden properties

Now that you've hidden the properties, you need to go back and modify the download_file.php page so you don't get an error (see Listing 19).


Listing 19. Using setters
<?php

   include ("../WFDocument.php");

   $filetype = $_GET['filetype'];
   $filename = $_GET['file'];

   $wfdocument = new WFDocument();
   $wfdocument->setFilename($filename);
   $wfdocument->setFiletype($filetype);
   $wfdocument->download();

?>

Handy as this approach is, there are easier ways to set properties on an object.


Creating a constructor

If an object has a constructor, it gets called every time you create a new instance of that particular class. For example, you can create a simple constructor, as in Listing 20.


Listing 20. A simple constructor
...
   function getFiletype(){
      return $this->filetype;
   }

      function __construct(){
      echo "Creating new WFDocument";
   }

   function download() {

      $filepath = UPLOADEDFILES.$this->filename;
...

If you try to run this script as is, you'll see an error because the object outputs the text (Creating new WFDocument) before it outputs the headers, as you can see in Figure 8.


Figure 8. Error after running script
Screen capture of the error after running script

So, even though you never explicitly called the __construct() method, the application called it as soon as the object was instantiated. You can use that to your advantage by adding information to the constructor.


Creating an object with information

One of the most common uses for a constructor is to provide a way to initialize various values when you create the object. For example, you can set up the WFDocument class so that you set the filename and filetype properties when you create the object (see Listing 21).


Listing 21. A more complex constructor
...
   function getFiletype(){
      return $this->filetype;
   }

   function __construct($filename = "", $filetype = ""){
      $this->setFilename($filename);
      $this->setFiletype($filetype);
   }

   function download() {

      $filepath = UPLOADEDFILES.$this->filename;

...

When you create the object, PHP carries out any instructions in the constructor before moving on. In this case, that constructor is looking for the filename and filetype. If you don't supply them, you still won't get an error, because you specified default values to use if no value is given when the function is called.

But how do you explicitly call the __construct() function?


Creating the object: Calling the constructor

You don't actually call the constructor method explicitly. Instead, you call it implicitly every time you create an object. That means you use that specific moment to pass information for the constructor (see Listing 22).


Listing 22. Using a constructor
<?php

   include ("../WFDocument.php");

   $filetype = $_GET['filetype'];
   $filename = $_GET['file'];

   $wfdocument = new WFDocument($filename, $filetype);
   $wfdocument->download();

?>

Any information passed to the class when you create the new object gets passed to the constructor. This way, you can simply create the object and use it to download the file.

5 of 11 | Previous | Next

Comments



static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Open source, Linux, XML
ArticleID=133669
TutorialTitle=Learning PHP, Part 3: Authentication, objects, exceptions, and streaming
publish-date=01032013
author1-email=ibmquestions@nicholaschase.com
author1-email-cc=