5. Objects
5.1. Any variable can become an object with attributes (example_14)
<?php
// any variable can have attributes by design
$obj1->attr1 = "one";
$obj1->attr2 = 100;
// displays the object
print "object1=[$obj1->attr1,$obj1->attr2]\n";
// Modifies the object
$obj1->attr2+=100;
// display the object
print "object1=[$obj1->attr1,$obj1->attr2]\n";
// assigns the value of object1 to object2
$obj2 = $obj1;
// modifies obj2
$obj2->attr2 = 0;
// displays both objects
print "object1=[$obj1->attr1,$obj1->attr2]\n";
print "object2=[$obj2->attr1,$obj2->attr2]\n";
// assigns the reference of object1 to object3
$obj3 = &$obj1;
// modifies obj3
$obj3->attr2 = 10;
// displays both objects
print "object1=[$obj1->attr1,$obj1->attr2]\n";
print "object3=[$obj3->attr1,$obj3->attr2]\n";
// Is an object a dictionary?
print count($obj1)."\n";
while (list($attribute, $value) = each($obj1))
print "obj1[$attribute]=$value\n";
// end
exit;
?>
Results:
object1=[one,100]
object1=[one,200]
object1=[one,0]
object2=[one,0]
object1=[one,10]
object3=[one,10]
1
obj1[attr1] = one
obj1[attr2] = 10
Comments
- line 4: the notation $obj->attr refers to the attr attribute of the variable $obj. If it does not exist, it is created, thus making the variable $obj an object with attributes.
- line 13: the expression $obj2 = $obj1, when $obj1 is an object, is a copy of objects by reference. Thus, $obj2 and $obj1 are references to the same object. The object itself can be modified by either reference.
- Line 20: The expression $obj3=&$obj1 assigns the reference (address) of the variable $obj1 to $obj3. If $obj1 is an object, as is the case here, the preceding expression is equivalent to $obj3=$obj1.
- Lines 28–29: demonstrate that an object can be traversed like a dictionary. The keys of the dictionary are the names of the attributes, and the values of the dictionary are the values of those same attributes.
- Line 27: The count function can be applied to an object but does not, as one might expect, return the number of attributes. Therefore, an object shares similarities with a dictionary but is not one.
5.2. A Person class with no declared attributes (example_15)
<?php
class Person {
// class attributes
// not declared - can be created dynamically
// method
function identity() {
// At first glance, this uses non-existent attributes
return "[$this->firstName, $this->lastName, $this->age]";
}
}
// test
// attributes are public and can be created dynamically
$p = new Person();
$p->firstName = "Paul";
$p->lastName = "Langevin";
$p->age = 48;
// calling a method
print "person=" . $p->identity() . "\n";
// end
exit;
?>
Results:
Comments
- lines 3–13: define a Person class. A class is a template used to create objects. A class is a collection of attributes and functions called methods. Attributes do not have to be declared.
- Lines 9–12: The identity method displays the values of three attributes not declared in the class. The keyword $this refers to the object to which the method is applied.
- Line 17: An object $p of type Person is created. The keyword new is used to create a new object. The operation returns a reference to the created object (i.e., an address). Various notations are possible: new Person(), new Person, new person. The class name is case-insensitive.
- Lines 18–20: The three attributes required by the identity method are created in the $p object.
- line 22: the identity method of the Person class is applied to the $p object. In the code (lines 9–11) of the identity method, $this refers to the same object as $p.
5.3. The Person class with declared attributes (example_16)
<?php
class Person {
// class attributes
var $last_name;
var $lastName;
var $age;
// method
function identity() {
return "[$this->firstName,$this->lastName,$this->age]";
}
}
// test
// attributes are public
$p = new Person();
$p->firstName = "Paul";
$p->lastName = "Langevin";
$p->age = 48;
// calling a method
print "person=" . $p->identity() . "\n";
// end
exit;
?>
Results:
Comments
5.4. The Person class with a constructor (example_17)
The previous examples showed exotic Person classes as they might have been found in PHP 4. It is not recommended to follow these examples. We now present a Person class that follows PHP 5 best practices:
<?php
class Person {
// class attributes
private $last_name;
private $last_name;
private $age;
// getters and setters
public function getFirstName() {
return $this->first_name;
}
public function getLastName() {
return $this->lastName;
}
public function getAge() {
return $this->age;
}
public function setFirstName($firstName) {
$this->firstName = $firstName;
}
public function setLastName($lastName) {
$this->lastName = $lastName;
}
public function setAge($age) {
$this->age = $age;
}
// constructor
function __construct($firstName, $lastName, $age) {
// we use the set methods
$this->setFirstName($firstName);
$this->setLastName($lastName);
$this->setAge($age);
}
// toString method
function __toString() {
return "[$this->first_name, $this->last_name, $this->age]";
}
}
// test
// create a Person object
$p = new Person("Paul", "Langevin", 48);
// identity of this person
print "person=$p\n";
// changing the age
$p->setAge(14);
// person's identity
print "person=$p\n";
// end
exit;
?>
Results:
Comments
- lines 3-48: the Person class
- lines 6-8: the class's private attributes. These attributes are only visible within the class. Other keywords that can be used are:
- public: makes the attribute a public attribute visible from outside the class
- protected: makes the attribute a protected attribute visible from within the class and its derived classes.
- Because the attributes are private, they cannot be accessed from outside the class. Therefore, we cannot write the following code:
Here, we are outside the Person class. Since the name attribute is private, line 2 is incorrect. To initialize the private fields of the $p object, there are two ways:
- (continued)
- use the public set and get methods (the names of these methods can be anything) from lines 11–33. We can then write:
- (continued)
- Use the constructor from lines 36–41. We would then write:
The code above automatically calls the Person class method called __construct.
- Line 54: This line displays the Person $p as a string. To do this, the Person class method called __toString is used.
5.5. The Person class with validity checks in the constructor (example_18)
A class’s constructor is the right place to verify that the object’s initialization values are correct. However, an object can also be initialized via its set methods or equivalents. To avoid duplicating the same checks in two different places, we’ll place them within the set methods. If an object’s initialization value is found to be incorrect, an exception will be thrown. Here is an example:
<?php
class Person {
// class attributes
private $first_name;
private $last_name;
private $age;
// getters and setters
public function getFirstName() {
return $this->firstName;
}
public function getLastName() {
return $this->lastName;
}
public function getAge() {
return $this->age;
}
public function setFirstName($firstName) {
// the first name must not be empty
if (!preg_match("/^\s*(.+?)\s*$/", $firstName, $fields)) {
throw new Exception("The first name must not be empty");
} else {
$this->firstName = $fields[1];
}
}
public function setLastName($lastName) {
// the last name must not be empty
if (!preg_match("/^\s*(.+?)\s*$/", $name, $fields)) {
throw new Exception("The name must not be empty");
} else {
$this->name = $fields[1];
}
}
public function setAge($age) {
// the age must be valid
if (!preg_match("/^\s*(\d+)\s*$/", $age, $fields)) {
throw new Exception("The age must be a positive integer or zero");
} else {
$this->age = $fields[1];
}
}
// constructor
function __construct($first_name, $last_name, $age) {
// we use the set methods
$this->setFirstName($firstName);
$this->setLastName($lastName);
$this->setAge($age);
}
// toString method
function __toString() {
return "[$this->first_name, $this->last_name, $this->age]";
}
}
// test
// Create a Person object
$p = new Person("Paul", "Langevin", 48);
// identity of this person
print "person=$p\n";
// Creating an incorrect Person object
try {
$p = new Person("xx", "yy", "zz");
} catch (Exception $e) {
print $e->getMessage();
}
// end
exit;
?>
Results:
Comments
- lines 23-30: initialization of the first_name attribute and verification of the initialization value
- line 25: use of a regular expression. The first name is a sequence of one or more characters, possibly followed or preceded by spaces.
- line 26: if the last name is empty, an exception is thrown; otherwise, the first name is stored (line 28)
- line 66: use of the Person class constructor
- line 68: use of the __toString method of the Person class
- Lines 70–74: Handling any exception thrown by the Person class constructor.
5.6. Adding a method that acts as a second constructor (example_19)
In PHP 5, it is not possible to have multiple constructors with different parameters that would allow an object to be constructed in various ways. We can therefore use methods that act as constructors:
<?php
class Person {
// class attributes
private $first_name;
private $lastName;
private $age;
// getters and setters
public function getFirstName() {
return $this->firstName;
}
….
// constructor
function __construct($firstName, $lastName, $age) {
// we use the set methods
$this->setFirstName($firstName);
$this->setLastName($lastName);
$this->setAge($age);
}
// method
public function initWithPerson($p) {
// initializes the current object with a person $p
$this->__construct($p->firstName, $p->lastName, $p->age);
}
// toString method
function __toString() {
return "[$this->firstName, $this->lastName, $this->age]";
}
}
// test
// Create a Person object
$p = new Person("Paul", "Langevin", 48);
// identity of this person
print "person=$p\n";
// creating a second person
$p2 = new Person("Laure", "Adeline", 67);
// Initialize the first with the values from the second
$p->initWithPerson($p2);
// verification
print "person=$p\n";
// end
exit;
?>
Results:
Comments
- lines 26-29: The initWithPerson method allows you to assign the attribute values of another Person object to the current object. Here, it calls the __construct constructor, but this is not mandatory.
5.7. An array of Person objects (example_20)
The following example shows that you can have arrays of objects.
<?php
class Person {
// class attributes
private $first_name;
private $lastName;
private $age;
// getters and setters
public function getFirstName() {
return $this->firstName;
}
...
// constructor
function __construct($firstName, $lastName, $age) {
// we use the set methods
$this->setFirstName($firstName);
$this->setLastName($lastName);
$this->setAge($age);
}
// method
public function initWithPerson($p) {
….
}
// toString method
function __toString() {
...
}
}
// test
// Create an array of Person objects
$group = array(new Person("Paul", "Langevin", 48), new Person("Sylvie", "Lefur", 70));
// identities of these people
for ($i = 0; $i < count($group); $i++)
print "group[$i]=$group[$i]\n";
// end
exit;
?>
Results:
Comments
- line 39: creation of an array of 2 people
- line 42: iterating through the array
- line 43: $group[$i] is an object of type Person. The __toString method is used to display it.
5.8. Creating a class derived from the Person class (example_21)
<?php
class Person {
// class attributes
private $first_name;
private $last_name;
private $age;
// getters and setters
public function getFirstName() {
return $this->first_name;
}
...
// constructor
function __construct($firstName, $lastName, $age) {
// we use the set methods
$this->setFirstName($firstName);
$this->setLastName($lastName);
$this->setAge($age);
}
// method
public function initWithPerson($p) {
// initializes the current object with a person $p
$this->__construct($p->firstName, $p->lastName, $p->age);
}
// toString method
function __toString() {
return "[$this->firstName, $this->lastName, $this->age]";
}
}
// a class derived from Person
class Teacher extends Person {
// attributes
private $subject; // subject taught
// getter and setter
public function getSubject() {
return $this->subject;
}
public function setDiscipline($discipline) {
$this->discipline = $discipline;
}
// constructor
public function __construct($firstName, $lastName, $age, $discipline) {
// parent attributes
parent::__construct($firstName, $lastName, $age);
// other attributes
$this->setSubject($subject);
}
// Override the __toString function of the parent class
public function __toString() {
return "[" . parent::__toString() . ",$this->discipline]";
}
}
// test
// Create an array of Person objects and derived classes
$group = array(new Teacher("Paul", "Langevin", 48, "English"), new Person("Sylvie", "Lefur", 70));
// identities of these people
for ($i = 0; $i < count($group); $i++)
print "group[$i] = $group[$i]\n";
// end
exit;
?>
Results:
Comments
- lines 3-35: the Person class
- line 38: the Teacher class extends the Person class. The derived Teacher class inherits the attributes and methods of its parent class.
- line 41: the Teacher class adds a new attribute, subject, which is specific to it
- line 55: the Teacher class constructor takes 4 parameters
- 3 to initialize its parent class (first_name, last_name, age)
- 1 for its own initialization (subject)
- line 57: the derived class has access to the methods and constructors of its parent class via the keyword parent::. Here, we pass the parameters (first_name, last_name, age) to the parent class’s constructor.
- line 64: the __toString method of the derived class uses the __toString method of the parent class.
- line 71: an array containing a Teacher object and a Person object.
- line 74: we loop through the elements of the array
- line 75: the __toString method of each element $group[$i] will be called. The Person class has a __toString method. The Teacher class has two: that of its parent class and its own. One might wonder which one will be called. Execution shows that it was the Teacher class’s method that was called. This is always the case: when a method is called on an object, it is searched for in the following order: in the object itself, in its parent class if it has one, then in the parent class of the parent class, and so on… The search stops as soon as the method is found.
5.9. Creating a second class derived from the Person class (example_22)
The following example creates a Student class derived from the Person class:
<?php
class Person {
// class attributes
private $lastName;
private $lastName;
private $age;
// getters and setters
public function getFirstName() {
return $this->firstName;
}
...
// constructor
function __construct($firstName, $lastName, $age) {
// we use the set methods
$this->setFirstName($firstName);
$this->setLastName($lastName);
$this->setAge($age);
}
// method
public function initWithPerson($p) {
// initializes the current object with a person $p
...
}
// toString method
function __toString() {
return "[$this->firstName,$this->lastName,$this->age]";
}
}
// a class derived from Person
class Teacher extends Person {
// attributes
private $subject; // subject taught
// getters and setters
...
// constructor
public function __construct($firstName, $lastName, $age, $subject) {
// parent attributes
parent::__construct($firstName, $lastName, $age);
// other attributes
$this->setSubject($subject);
}
// Override the parent class's __toString() method
public function __toString() {
return "[" . parent::__toString() . ",$this->discipline]";
}
}
// A class derived from Person
class Student extends Person {
// attributes
private $program; // subject taught
// getter and setter
public function getEducation() {
return $this->education;
}
public function setFormation($formation) {
$this->training = $training;
}
// constructor
public function __construct($firstName, $lastName, $age, $education) {
// parent attributes
parent::__construct($firstName, $lastName, $age);
// other attributes
$this->setEducation($education);
}
// Override the __toString function of the parent class
public function __toString() {
return "[" . parent::__toString() . ",$this->formation]";
}
}
// test
// Create an array of Person objects and derived classes
$group = array(new Teacher("Paul", "Langevin", 48, "English"), new Person("Sylvie", "Lefur", 70), new Student("Steve", "Boer", 23, "iup2 quality"));
// identities of these people
for ($i = 0; $i < count($group); $i++)
print "group[$i]=$group[$i]\n";
// end
exit;
?>
Results:
group[0]=[[Paul,Langevin,48],English]
group[1] = [Sylvie, Lefur, 70]
group[2]=[[Steve,Boer,23],iup2 quality]
5.10. Interfaces (example_23)
An interface is a structure that defines method prototypes. A class that implements an interface defines the code for all of the interface's methods.
<?php
// an interface
interface IExample {
function add($i, $j);
function subtract($i, $j);
}
// Implementation 1 of the interface
class Class1 implements IExample {
public function add($a, $b) {
return $a + $b + 10;
}
public function subtract($a, $b) {
return $a - $b + 20;
}
}
// Implementation 2 of the interface
class Class2 implements IExample {
public function add($a, $b) {
return $a + $b + 100;
}
public function subtract($a, $b) {
return $a - $b + 200;
}
}
// function
function calculate($a, $b, IExample $interface) {
print $interface->add($a, $b)."\n";
print $interface->subtract($a, $b)."\n";
}
// ------------------- main
// Create 2 objects of type Class1 and Class2
$c1 = new Class1();
$c2 = new Class2();
// call the calculate function
calculate(4, 3, $c1);
calculate(14, 13, $c2);
?>
Results
Comments
- Lines 4–8: The IExample interface defines two methods: the add function (line 5) and the subtract function (line 7). The interface does not define the code for these methods. The classes that implement the interface will do so.
- Line 11: The Class1 class implements the IExample interface. It therefore defines code for the add method (line 13) and the subtract method (line 17).
- Lines 24–34: The same applies to the Class2 class.
- Line 37: The
*calculermethod takes three parameters: two integers,*$a*and$b*, and an object*$interfacethat implements the*IExempleinterface. We could have writtenfunction calculate($a, $b, $interface)without specifying theIExampletype of the*$interface*parameter. By specifying it, we allow the PHP interpreter to verify that the actual parameter is indeed an object implementing the*IExample* interface. - lines 38–39: use of the add and subtract methods of the $interface object. Because it implements the IExample interface, we know it has these two methods.
- Lines 44–45: Creation of two objects of different types, both of which implement the IExample interface.
- Line 47: We pass the object $c1 of type Class1, which implements the IExample interface, to the calculate function.
- Line 48: The object $c2 of type Class2, which implements the IExample interface, is passed to the calculate function.