5. Objects
5.1. Any variable can become an object with attributes (exemple_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, thereby 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 previous 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 (exemple_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 of type Person named $p 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 object $p. In the code (lines 9–11) of the identity method, $this references the same object as $p.
5.3. The Person class with declared attributes (exemple_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
- lines 6-8: the class attributes are explicitly declared using the var keyword.
5.4. The Person class with a constructor (exemple_17)
The previous examples showed unusual Person classes such as those found in PHP 4. It is not recommended to follow these examples. We now present a Person class that follows the best practices of PHP 5:
<?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 private attributes of the class. 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, you 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 methods set and get (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 will then write:
The code above automatically calls the Person class method named __construct.
- Line 54: This line displays the Person $p as a string. To do this, the Person class method named __toString is used.
5.5. The Person class with validity checks in the constructor (exemple_18)
The constructor of a class 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, these checks should be placed 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 (exemple_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) {
// initialise l'objet courant avec une personne $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 method initWithPersonne allows you to assign the attribute values of another Person object to the current object. Here, it calls the constructor __construct, but this is not mandatory.
5.7. An array of Person objects (exemple_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: $groupe[$i] is an object of type Person. The method __toString is used to display it.
5.8. Creating a class derived from the Person class (exemple_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) {
// initialise l'objet courant avec une personne $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; // 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);
}
// overloading 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 $groupe[$i] will be called. The Person class has a __toString method. The Teacher class has two: the one from its parent class and its own. One might wonder which one will be called. Execution shows that it is the one from the Teacher class 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 (exemple_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) {
// initialise l'objet courant avec une personne $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; // 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; // 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 (exemple_23)
An interface is a structure that defines method prototypes. A class that implements an interface defines the code for all the methods in the interface.
<?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 IExemple 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 IExemple interface. It therefore defines code for the add method (line 13) and the subtract method (line 17).
- Lines 24–34: Same for the Class2 class
- line 37: the calculate method takes three parameters: two integers $a and $b and an object $interface implementing the IExemple interface. We could have written function calculate($a, $b, $interface) without specifying the type IExemple of the parameter $interface. By specifying it, we allow the PHP interpreter to verify that the actual parameter is indeed an object implementing the IExemple interface.
- lines 38–39: use of the add and subtract methods of the $interface object. Because this object implements the IExemple interface, we know it has these two methods.
- lines 44–45: creation of two objects of different types but both implementing the IExemple interface.
- Line 47: The object $c1 of type Class1, which implements the interface IExemple, is passed to the calculate function.
- Line 48: Passes the object $c2 of type Class2, which implements the interface IExemple, to the calculate function.