Вы находитесь на странице: 1из 7

Object-Oriented PHP Part 2: Relationships

Posted Monday 21st August, 2006


Following on from my posts Object-Oriented Concepts and Object-Oriented Javascript, Im going
to take a look at OOP in PHP.
In Part 1: Definition we took a look at defining objects and classes in PHP. In part 2 Im going to look
at the most important part of any object-oriented system - the relationships.
Relationships
The relationships you use dictate the way objects interact with each other. Heres how to model them in
PHP.
Inheritance
Inheritance allows us to define a class that inherits all the attributes and methods of another class. To
do this in PHP4 and PHP5, we need to employ the extends keyword. Heres an example based
around HTML form elements:
class formElement
{
var $str_id;
var $str_name;
var $str_class;
function isRequired()
{
// Validation code here
}
}
class dateInput extends formElement
{
var $str_value;
// Specific validation for dateInput
function isValidDate()
{
// Validation code here
}
}
In the above example, the class dateInput is inheriting all the attributes and methods of the class
formElement. This means we could do all of the following:
// Instantiate our class as an object
$myDate = new dateInput();
$myDate->str_id = 'mydate';
$myDate->str_name = 'mydate';
$myDate->str_value = '2006/06/09';
$myDate->isRequired();
$myDate->isValidDate();
Some languages allow multiple inheritance; allowing you to inherit from more than one class.
Unfortunately, this is not the case in PHP.
If your parent class has a constructor, PHP wont evaluate it when you instantiate the child class. If you
wish the constructor to be run, youll need to call in as if it were any other method within the class.
Heres an example of what I mean:
PHP4
class fruit
{
// Constructor
function fruit()
{
}
}
class apple extends fruit
{
function apple()
{
// Call the constructor of our parent class
$this->fruit();
}
}
PHP5
class fruit
{
// Constructor
function __construct()
{
}
}
class apple extends fruit
{
function __construct()
{
// Call the constructor of our parent class
// using the scope resolution operator -
// we'll talk about this later.
parent::__construct();
}
}
In the PHP5 example youll notice we dont use the $this keyword. This is simply because $this
could evaluate to either apple or fruit because the constructor method for each is called
__construct. To get around this we use the scope resolution operator which I will talk about a little
later on.
Composition - Association and Aggregation
Association and aggregation differ from inheritance because rather than passing the methods and
properties of a class to another class, they involve instantiating whole objects and using them as
properties, or passed-in parameters, in another class.
This might sound complicated but its really very simple in practice. Im going to borrow some of the
examples in my Object-Oriented Concepts post and adapt them for PHP:
Association
class brick
{
var $sample_attribute;
}
class wall
{
var $brick1;
var $brick2;
var $brick3;
var $brick4;
// Constructor
function wall()
{
$this->brick1 = new brick();
$this->brick2 = new brick();
$this->brick3 = new brick();
$this->brick4 = new brick();
}
}
In the above example we have a class wall which has four brick attributes. To associate our brick
class we instantiate it as the $brick attributes of the wall class.
We can now access the $sample_attribute of each brick within our wall class like so:
echo $this->brick1->sample_attribute;
echo $this->brick2->sample_attribute;
echo $this->brick3->sample_attribute;
echo $this->brick4->sample_attribute;
Or from outside an instantiated object like so:
$myWall = new wall();
echo $myWall->brick1->sample_attribute;
echo $myWall->brick2->sample_attribute;
echo $myWall->brick3->sample_attribute;
echo $myWall->brick4->sample_attribute;
As you can see, this type of relationship has the potential to be highly useful - however, if you wish to
share an object between other classes (for instance, a database connection object) we run into a
problem. In our example you can see that the brick objects are encapsulated within our wall class
which means they are only accessible within our myWall object. To get around this problem we could
use aggregation.
Aggregation basically involves passing an instantiated object into a class so that the class can use our
object. Once again, Ill poach one of my earlier examples to illustrate what I mean. To save on code
snippets, Im only going to use PHP4 syntax for the moment:
Aggregation
class person
{
}
class car
{
var $driver;
// Constructor
function car(&$driver)
{
$this->driver = (object) $driver;
}
}
// Instantiate our person object
$me = new person();
// Now pass it in as $driver
$myMotor = new car($me);
In this example we instantiate our class person as an object ($me). We then pass the $me object into
the car class so that it is used as the $driver attribute in the $myMotor object. If we were to destroy
the $myMotor object, we wouldnt destroy the $me object; which means we could carry on using it for
other things. In fact, even though were using the $me object within our $myMotor object, we could
still use it in other objects like so:
class van
{
var $driver;
// Constructor
function van(&$driver)
{
$this->driver = (object) $driver;
}
}
// Our $me object already exists
// so pass it in as $driver
$myVan = new van($me);
If you look at our example youll notice the ampersand symbol (&) before the parameter declaration of
our constructor method. This tells PHP that the parameter is passed by reference. This is the key to the
aggregation relationship.
References
PHP references allow you to define two variables that refer to the same content. To do this we use the &
operator. Heres an example:
In this example $a and $b point to the same content.
The same syntax can be used with functions, that return references, and with the new operator:
$bar =& new fooclass();
$foo =& find_var($bar);
If we dont use the & operator when were instantiating an object, PHP creates a copy of said object. If
you use $this in the class it will operate on the current instance of the class. The assignment without
& will copy the instance (i.e. the object) and $this will operate on the copy, which is not always what
is desired. Usually you want to have a single instance to work with, due to performance and memory
consumption issues.
Basically, its a good idea to always assign a reference when instantiating an object unless you have a
specific case not to.
Note: Since PHP5, in fact, new returns references automatically so using =& in this context is
deprecated and produces E_STRICT level messages.
There is another way that references help us when developing object-oriented solutions in PHP; by
allowing method parameters to be passed by reference as we did in our aggregation example above.
Passing by reference basically allows us to use or modify a variable within a method (function). Heres
a good example from the PHP documentation:
function foo(&$var)
{
$var++;
}
$a=5;
foo($a);
// $a is 6 here
In the aggregation example were passing an entire object as a parameter. If we passed the parameter
without the reference we would be creating a copy of the object that was only available within the
function. By adding the reference were simply telling the function that the parameter is another name
for our original object.
Summary
Although these relationships can appear simple to begin with, its all too easy to overlook their hidden
power. Used in the right way, relationships can help to build highly powerful, easily extendable
applications with relatively little fuss.
Deciding which relationship to use can be tricky; and its certainly not something youll get right
everytime. However, rest assured, if you experiment and use them regularly, youll find it easier to
solve problems that are presented to you.
In the next post, Ill be taking a look at extending our relationships a little further using visibility and
polymorphism.
Click here to continue on to Part 3: Taking Relationships Further