5. Objects
5.1. Any variable can become an object with attributes (example_14)
<?php
// any variable can have attributes by construction
$obj1->attr1 = "un";
$obj1->attr2 = 100;
// displays the
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
// modify object
$obj1->attr2+=100;
// displays the
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
// assigns the value of object1 to object2
$obj2 = $obj1;
// modify obj2
$obj2->attr2 = 0;
// displays both objects
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
print "objet2=[$obj2->attr1,$obj2->attr2]\n";
// assigns the reference from object1 to object3
$obj3 = &$obj1;
// modify obj3
$obj3->attr2 = 10;
// displays both objects
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
print "objet3=[$obj3->attr1,$obj3->attr2]\n";
// is an object a dictionary?
print count($obj1)."\n";
while (list($attribut, $valeur) = each($obj1))
print "obj1[$attribut]=$valeur\n";
// end
exit;
?>
Results:
objet1=[un,100]
objet1=[un,200]
objet1=[un,0]
objet2=[un,0]
objet1=[un,10]
objet3=[un,10]
1
obj1[attr1]=un
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 Personne {
// class attributes
// undeclared - can be created dynamically
// method
function identité() {
// a priori, uses non-existent attributes
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// test
// attributes are public and can be created dynamically
$p = new Personne();
$p->prénom = "Paul";
$p->nom = "Langevin";
$p->âge = 48;
// method call
print "personne=" . $p->identité() . "\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 Personne {
// class attributes
var $prénom;
var $nom;
var $âge;
// method
function identité() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// test
// attributes are public
$p = new Personne();
$p->prénom = "Paul";
$p->nom = "Langevin";
$p->âge = 48;
// method call
print "personne=" . $p->identité() . "\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 Personne {
// class attributes
private $prénom;
private $nom;
private $âge;
// getters and setters
public function getPrénom() {
return $this->prénom;
}
public function getNom() {
return $this->nom;
}
public function getAge() {
return $this->âge;
}
public function setPrénom($prénom) {
$this->prénom = $prénom;
}
public function setNom($nom) {
$this->nom = $nom;
}
public function setAge($age) {
$this->âge = $age;
}
// manufacturer
function __construct($prénom, $nom, $âge) {
// we go through sets
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// method toString
function __toString() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// test
// creation of a person object
$p = new Personne("Paul", "Langevin", 48);
// identity of this person
print "personne=$p\n";
// we change the age
$p->setAge(14);
// identity of the person
print "personne=$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 Personne {
// class attributes
private $prénom;
private $nom;
private $âge;
// getters and setters
public function getPrénom() {
return $this->prénom;
}
public function getNom() {
return $this->nom;
}
public function getAge() {
return $this->âge;
}
public function setPrénom($prénom) {
// first name must be non-empty
if (!preg_match("/^\s*(.+?)\s*$/", $prénom, $champs)) {
throw new Exception("Le prénom doit être non vide");
} else {
$this->prénom = $champs[1];
}
}
public function setNom($nom) {
// name must be non-empty
if (!preg_match("/^\s*(.+?)\s*$/", $nom, $champs)) {
throw new Exception("Le nom doit être non vide");
} else {
$this->nom = $champs[1];
}
}
public function setAge($âge) {
// age must be valid
if (!preg_match("/^\s*(\d+)\s*$/", $âge, $champs)) {
throw new Exception("L'âge doit être un entier positif ou nul");
} else {
$this->âge = $champs[1];
}
}
// manufacturer
function __construct($prénom, $nom, $âge) {
// we go through sets
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// method toString
function __toString() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// test
// creation of a Personne object
$p = new Personne("Paul", "Langevin", 48);
// identity of this person
print "personne=$p\n";
// creation of an erroneous Person object
try {
$p = new Personne("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 Personne {
// class attributes
private $prénom;
private $nom;
private $âge;
// getters and setters
public function getPrénom() {
return $this->prénom;
}
….
// manufacturer
function __construct($prénom, $nom, $âge) {
// we go through sets
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// method
public function initWithPersonne($p) {
// initializes the current object with a person $p
$this->__construct($p->prénom, $p->nom, $p->âge);
}
// method toString
function __toString() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// test
// creation of a Personne object
$p = new Personne("Paul", "Langevin", 48);
// identity of this person
print "personne=$p\n";
// creation of a second person
$p2 = new Personne("Laure", "Adeline", 67);
// initialization of the first with the values of the second
$p->initWithPersonne($p2);
// check
print "personne=$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 Personne {
// class attributes
private $prénom;
private $nom;
private $âge;
// getters and setters
public function getPrénom() {
return $this->prénom;
}
...
// manufacturer
function __construct($prénom, $nom, $âge) {
// we go through sets
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// method
public function initWithPersonne($p) {
….
}
// method toString
function __toString() {
...
}
}
// test
// create an array of Personne objects
$groupe = array(new Personne("Paul", "Langevin", 48), new Personne("Sylvie", "Lefur", 70));
// identity of these persons
for ($i = 0; $i < count($groupe); $i++)
print "groupe[$i]=$groupe[$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 Personne {
// class attributes
private $prénom;
private $nom;
private $âge;
// getters and setters
public function getPrénom() {
return $this->prénom;
}
...
// manufacturer
function __construct($prénom, $nom, $âge) {
// we go through sets
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// method
public function initWithPersonne($p) {
// initializes the current object with a person $p
$this->__construct($p->prénom, $p->nom, $p->âge);
}
// method toString
function __toString() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// a class derived from Personne
class Enseignant extends Personne {
// attributes
private $discipline; // d// subject taught
// getter and setter
public function getDiscipline() {
return $this->discipline;
}
public function setDiscipline($discipline) {
$this->discipline = $discipline;
}
// manufacturer
public function __construct($prénom, $nom, $âge, $discipline) {
// parent attributes
parent::__construct($prénom, $nom, $âge);
// other attributes
$this->setDiscipline($discipline);
}
// overloads the __toString function of the parent class
public function __toString() {
return "[" . parent::__toString() . ",$this->discipline]";
}
}
// test
// creation of an array of Personne and derived objects
$groupe = array(new Enseignant("Paul", "Langevin", 48, "anglais"), new Personne("Sylvie", "Lefur", 70));
// identity of these persons
for ($i = 0; $i < count($groupe); $i++)
print "groupe[$i]=$groupe[$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 Personne {
// class attributes
private $prénom;
private $nom;
private $âge;
// getters and setters
public function getPrénom() {
return $this->prénom;
}
...
// manufacturer
function __construct($prénom, $nom, $âge) {
// we go through sets
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// method
public function initWithPersonne($p) {
// initializes the current object with a person $p
...
}
// method toString
function __toString() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
// a class derived from personne
class Enseignant extends Personne {
// attributes
private $discipline; // d// subject taught
// getter and setter
...
// manufacturer
public function __construct($prénom, $nom, $âge, $discipline) {
// parent attributes
parent::__construct($prénom, $nom, $âge);
// other attributes
$this->setDiscipline($discipline);
}
// overloads the _identité__toString function of the parent class
public function __toString() {
return "[" . parent::__toString() . ",$this->discipline]";
}
}
// a class derived from Personne
class Etudiant extends Personne {
// attributes
private $formation; // d// subject taught
// getter and setter
public function getFormation() {
return $this->formation;
}
public function setFormation($formation) {
$this->formation = $formation;
}
// manufacturer
public function __construct($prénom, $nom, $âge, $formation) {
// parent attributes
parent::__construct($prénom, $nom, $âge);
// other attributes
$this->setFormation($formation);
}
// overloads the __toString function of the parent class
public function __toString() {
return "[" . parent::__toString() . ",$this->formation]";
}
}
// test
// creation of a table of person objects and derivatives
$groupe = array(new Enseignant("Paul", "Langevin", 48, "anglais"), new Personne("Sylvie", "Lefur", 70), new Etudiant("Steve", "Boer", 23, "iup2 qualité"));
// identity of these persons
for ($i = 0; $i < count($groupe); $i++)
print "groupe[$i]=$groupe[$i]\n";
// end
exit;
?>
Results:
groupe[0]=[[Paul,Langevin,48],anglais]
groupe[1]=[Sylvie,Lefur,70]
groupe[2]=[[Steve,Boer,23],iup2 qualité]
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 IExemple {
function ajouter($i, $j);
function soustraire($i, $j);
}
// interface implementation 1
class Classe1 implements IExemple {
public function ajouter($a, $b) {
return $a + $b + 10;
}
public function soustraire($a, $b) {
return $a - $b + 20;
}
}
// interface implementation 2
class Classe2 implements IExemple {
public function ajouter($a, $b) {
return $a + $b + 100;
}
public function soustraire($a, $b) {
return $a - $b + 200;
}
}
// function
function calculer($a, $b, IExemple $interface) {
print $interface->ajouter($a, $b)."\n";
print $interface->soustraire($a, $b)."\n";
}
// ------------------- hand
// creation of 2 objects of type Class1 and Class2
$c1 = new Classe1();
$c2 = new Classe2();
// call the calculate function
calculer(4, 3, $c1);
calculer(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.