PHP Tutorial #2: Object-Oriented PHP4 vs Object-Oriented PHP5 (Intermediate)

Posted on February 17, 2009 at 7:41 pm by Collin Klopfenstein.
Categories: PHP Tutorials

Personally, when I write Web applications in PHP, I love to use classes. They just make things easier, if used properly, in my opinion. When I first started writing object-oriented PHP (OOPHP), PHP5 was not released yet. Needless to say, when PHP5 came out, I had to relearn a few things in order to write proper OOPHP. In this article, we’ll be exploring the differences between object-oriented programming (OOP) in PHP4 vs. PHP5.

Intro to OOP

While it is a little beyond the scope I had originally intended for this article, I am going to go into a brief explanation of what exactly object-oriented programming is, and why it’s used.

Object-oriented programming is a way of writing code that is reusable throughout an application. It’s also much more than that. Here are a few of the concepts used in OOP:

Classes

Classes are the basis of all object-oriented programming. They are a “construct used as a blueprint to create objects”. (Wikipedia: Class (computer science))

Objects

Objects are simply instances of a class. Usually when an object is instantiated, a method called the constructor is called, if present.

Attributes

Attributes are variables encapsulated in the class. Generally, without a specific keyword, attributes cannot be accessed without specifying a specific object. When an object is instantiated, each attribute of the object’s class is created as variable inside the object. This might be a little confusing, but we’ll talk about it more in depth shortly.

Methods

Methods are functions encapsulated within a class. As with attributes, they’re not accessible without specifying an object unless they’re declared within the class with a special keyword.

OOP: The PHP4 Way

I chose to start with the PHP4 way of doing things, because, while deprecated, all of this syntax is still completely valid in PHP5. There are, however better ways of doing it in PHP5. If you watch carefully, I’ll distinguish between what is specific to PHP4, and what is still proper in both.

In PHP, like many languages, you have to use class construct to declare your class. For example:

<?php
class Foo {
  // The contents of the class go here
}
?>

This creates a class called Foo. Right now there are no attributes or methods in the class. Let’s look at how we add attributes.

1
2
3
4
5
6
7
8
9
10
<?php
class Foo {
  // Attributes
  var $attr1;
  var $attr2 = 0;
  var $attr3 = "bar";
  var $attr4, $attr5 = 1, $att6 = "blah";
  var $attr7 = $attr2 + 1;  // this line will generate a syntax error.  explanation below
}
?>

As you can see, it’s quite simple and similar to declaring normal variables in PHP. Please note that the preceding ‘var’ is necessary. In PHP4, this declares a public attribute. Unfortunately, in PHP4, there is no way to officially declare private and protected attributes, the difference of course being that private and protected attributes can’t be accessed outside of class methods, but public and protected attributes may be overwritten, while private attributes may not. We’ll talk more about inheritance later. There are, however, naming conventions. Private attributes are prefaced with an underscore (i.e.: $_myPrivAttr), and protected attributes are prefixed with an underscore and a capital T (i.e.: $_TmyProtAttr). No extra action is taken on these naming conventions, but an experienced PHP programmer will see these and know what they mean. I’ve shown all of the different types of attribute declaration above on lines 4-6. You can either declare an attribute with no value, as on line 4, or you can give it a constant value, as on lines 5 and 6. You can also put multiple declarations on one line, as in line 7. However, you can not try to use a variable or function to set the default value of an attribute. The above code, due to line 8, will generate the following message:

Parse error: syntax error, unexpected T_VARIABLE in /Users/collin/class.php on line 8

Now that we’ve explored the do’s and don’t’s of attributes, let’s move on to methods.

As I mentioned before, methods are just functions specific to a class. In PHP4, they’re declared exactly the same as a normal function declaration. For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
class Person {
  // attributes
  var $_first_name, $_last_name;
 
  // methods
  // constructor
  function Person( $f = null, $l = null ) {
    $this->set_first_name( $f );
    $this->set_last_name( $l );
  }
 
  function first_name( ) {
    return $this->_first_name;
  }
 
  function last_name( ) {
    return $this->_last_name;
  }
 
  function set_first_name( $f = null ) {
    if ( $f )
      $this->_first_name = $f;
  }
 
  function set_last_name( $l = null ) {
    if ( $l )
      $this->_last_name = $l;
  }
}
 
$p = new Person( 'Collin' );
$p->set_last_name( 'Klopfenstein' );
 
print_r( $p );
?>

Let’s walk through the above example, shall we? First, you can see we’ve declared our class (line 2), and our attributes (line 4). Then we have a method called Person (line 8). There is a reason this method shares its name with the class. It is the constructor. This means PHP automatically calls this function whenever an object of Person is instantiated. Notice, we’ve given the method two arguments. We’ve chosen to default each argument to null in the event that we don’t know our person’s first and last name before instantiation. In the constructor, we’re simply calling two other methods in the class to set the first and last name. Any time that you are accessing class methods or attributes from within a class method, just like outside of the class, you must reference the object. How do you do this within a class method? You use $this.

You might be wondering why we made the first_name( ) and last_name( ) methods. Well, if you look back up to line 4, you’ll notice we used the private naming convention for both attributes. This means that, while in PHP4 PHP will not try to stop us, we should not attempt to access these attributes outside of the class. Instead we call first_name( ) and last_name( ), which return the value stored in their respective attributes. These aptly-named methods are often referred to as “getters”, as they are used to get the value of an attribute. We also have “setter” methods (set_first_name( $f ) and set_last_name( $l )). We use these functions to set the $_first_name and $_last_name attributes of our class.

Now take a look at line 32. We’ve talked about instantiation in the last few examples. Now you get to see what it looks like. This is how you create an object from a class. It’s also perfectly acceptable, if the constructor allows you to not pass any arguments as ours does, to do this instead:

32
$p = new Person;

Have you noticed the ->? Wondering what it is? Whether in a class method ($this->) or outside of the object (in this case $p->), that is how we reference an attribute or method of an object.

The last line of our example code, line 35, is calling a very useful function. print_r prints our information about a variable (most useful on an array or object) in human-readable form. Based on our code, this function call will output the following:

Person Object
(
    [_first_name] => Collin
    [_last_name] => Klopfenstein
)

This kind of information is VERY useful in debugging.

OOPHP: The PHP5 Way

Now that we’ve seen the basics of writing object-oriented PHP, let’s look at the differences in the current version, PHP5. You’ll recall that in PHP4, we don’t have any way to officially declare whether an attribute or method is public, private, or protected. In PHP5, however, we do have this luxury. Let’s begin converting our OOPHP4 to OOPHP5.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php
class Person {
  // attributes
  private $_first_name, $_last_name;
 
  // methods
  // constructor
  public function Person( $f = null, $l = null ) {
    $this->set_first_name( $f );
    $this->set_last_name( $l );
  }
 
  public function first_name( ) {
    return $this->_first_name;
  }
 
  public function last_name( ) {
    return $this->_last_name;
  }
 
  public function set_first_name( $f = null ) {
    if ( $f )
      $this->_first_name = $f;
  }
 
  public function set_last_name( $l = null ) {
    if ( $l )
      $this->_last_name = $l;
  }
}
 
$p = new Person( 'Collin' );
$p->set_last_name( 'Klopfenstein' );
 
print $p->_last_name;
 
print_r( $p );
?>

So far, we’ve only changed the declaration types. We want out attributes to be private, so we declared them as such. To demonstrate what declaring an attribute does, I’ve tried to print out one of our attributes, $_last_name. Here’s what will output:

Fatal error: Cannot access private property Person::$_last_name in /Users/collin/class.php on line 35

If we take that line out, you’ll notice print_r( $p ) also has some different output for you:

Person Object
(
    [_first_name:private] => Collin
    [_last_name:private] => Klopfenstein
)

Notice the :private. This is PHP’s way of telling print_r( $p ) that $_first_name and $_last_name are private variables. You’ve been warned.

Now let’s look at the difference with constructors/destructors in PHP. PHP4 does not have destructors by default. There are ways of accomplishing this in PHP4, but that is beyond the scope of this article. I suggest you try googling “PHP4 Destructor”. Anyway, now we’ll take our partially-converted code and change the constructor to a PHP5 constructor, add a destructor, and remove that pesky print accessing a private variable. Here’s how it looks now:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?php
class Person {
  // attributes
  private $_first_name, $_last_name;
 
  // methods
  // constructor
  public function __construct( $f = null, $l = null ) {
    $this->set_first_name( $f );
    $this->set_last_name( $l );
  }
 
  public function __destruct( ) {
    unset( $this->_first_name );
    unset( $this->_last_name );
  }
 
  public function first_name( ) {
    return $this->_first_name;
  }
 
  public function last_name( ) {
    return $this->_last_name;
  }
 
  public function set_first_name( $f = null ) {
    if ( $f )
      $this->_first_name = $f;
  }
 
  public function set_last_name( $l = null ) {
    if ( $l )
      $this->_last_name = $l;
  }
}
 
$p = new Person( 'Collin' );
$p->set_last_name( 'Klopfenstein' );
 
print_r( $p );
?>

Alright, this is now up to PHP5 snuff. By no means do you HAVE to have a destructor, or even a constructor, but constructors can be VERY useful. You can see on line 8 that the constructor has changed from “Person” to “__construct”. We’ve also added a method called “__destruct”. This function is called when the object is destroyed. Now that we know how to write OOPHP4 and OOPHP5, let’s move on to a new concept.

Inheritance

Inheritance is the act of one class inheriting attributes and methods of another class upon instantiation. For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
class Foo {
  public $pub;
  private $priv;
  protected $prot;
 
  public function __construct( ) {
    $this->pub = "I'm public!";
    $this->priv = "I'm private!";
    $this->prot = "I'm protected!";
  }
}
 
class Bar extends Foo {
  public $pub;
  protected $prot;
 
  public function __construct( ) {
    $this->pub = "Bar Pub!";
    $this->prot = "Bar Prot";
  }
}
 
$bar = new Bar;
 
print_r( $bar );
?>

There should be nothing new here other than extends Foo in the class declaration of Bar on line 13. This just tells PHP that you want Bar to inherit all of Foo’s inheritable attributes and methods. Based on what you’ve read in this article, can you figure out which attributes Bar will end up with and what their values will be? Here’s your answer:

Bar Object
(
    [pub] => Bar Pub!
    [prot:protected] => Bar Prot!
    [priv:private] =>
)

You’re probably wondering why it is that $priv is not defined, right? I mean, it was defined in the constructor of Foo, right? Right. The constructor, being a public method, is overridable. With inheritance, if an attribute or method is declared as public or protected, it’s overridable. This means that Bar’s constructor overrides Foo’s constructor, rather than inheriting it. But have no fear. There is, however, a way to call the parent class constructor. Here it is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
class Foo {
  public $pub;
  private $priv;
  protected $prot;
 
  public function __construct( ) {
    $this->pub = "I'm public!";
    $this->priv = "I'm private!";
    $this->prot = "I'm protected!";
  }
}
 
class Bar extends Foo {
  public $pub;
  protected $prot;
 
  public function __construct( ) {
    parent::__construct( );
 
    $this->pub = "Bar Pub!";
    $this->prot = "Bar Prot";
  }
}
 
$bar = new Bar;
 
print_r( $bar );
?>

Now your output will be this:

Bar Object
(
    [pub] => Bar Pub!
    [prot:protected] => Bar Prot
    [priv:private] => I'm private!
)

Conclusion

Alright, so that’s pretty much it. If you have any questions, comments, concerns or criticism, just leave a comment. Thanks for reading!


Tags

You can leave a comment, or send a trackback from your own site.


Leave a Reply