Skip to content

5. Los objetos

5.1. Cualquier variable puede convertirse en un objeto dotado de atributos (exemple_14)


<?php

// cualquier variable puede tener atributos por defecto
$obj1->attr1 = "un";
$obj1->attr2 = 100;
// muestra el objeto
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
// modifica el objeto
$obj1->attr2+=100;
// muestra el objeto
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
// asigna el valor de objeto1 a objeto2
$obj2 = $obj1;
// modifica obj2
$obj2->attr2 = 0;
// muestra los dos objetos
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
print "objet2=[$obj2->attr1,$obj2->attr2]\n";
// asigna la referencia de objeto1 a objeto3
$obj3 = &$obj1;
// modifica obj3
$obj3->attr2 = 10;
// muestra los dos objetos
print "objet1=[$obj1->attr1,$obj1->attr2]\n";
print "objet3=[$obj3->attr1,$obj3->attr2]\n";
// ¿Es un objeto un diccionario?
print count($obj1)."\n";
while (list($attribut, $valeur) = each($obj1))
  print "obj1[$attribut]=$valeur\n";
// fin
exit;
?>

Resultados:

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

Comentarios

  • línea 4: la notación $obj->attr designa el atributo attr de la variable $obj. Si no existe, se crea, convirtiendo así a la variable $obj en un objeto con atributos.
  • línea 13: la expresión $obj2=$obj1, cuando $obj1 es un objeto, es una copia de objetos por referencia. Por lo tanto, $obj2 y $obj1 son referencias al mismo objeto. El objeto en sí mismo puede ser modificado por cualquiera de las dos referencias.
  • línea 20: la expresión $obj3=&$obj1 asigna a $obj3 la referencia (la dirección) de la variable $obj1. Si $obj1 es un objeto, como ocurre aquí, la expresión anterior es equivalente a $obj3=$obj1.
  • Líneas 28-29: muestran que un objeto se puede recorrer como un diccionario. Las claves del diccionario son los nombres de los atributos y los valores del diccionario, los valores de esos mismos atributos.
  • Línea 27: la función count se puede aplicar a un objeto, pero no devuelve, como cabría esperar, el número de atributos. Por lo tanto, un objeto presenta similitudes con un diccionario, pero no es uno.

5.2. Una clase Persona sin atributos declarados (exemple_15)


<?php

class Personne {

  // atributos de la clase
  // no declarados: se pueden crear dinámicamente
  
  // método
  function identité() {
    // a priori, utiliza atributos inexistentes
    return "[$this->prénom,$this->nom,$this->âge]";
  }
}

// prueba
// los atributos son públicos y se pueden crear dinámicamente
$p = new Personne();
$p->prénom = "Paul";
$p->nom = "Langevin";
$p->âge = 48;
// llamada a un método
print "personne=" . $p->identité() . "\n";
// fin
exit;
?>

Resultados:

personne=[Paul,Langevin,48]

Comentarios

  • líneas 3-13: definen una clase Persona. Una clase es un molde a partir del cual se crean objetos. Una clase es un conjunto que agrupa atributos y funciones llamadas métodos. No es obligatorio declarar los atributos.
  • Líneas 9-12: el método identity muestra el valor de tres atributos no declarados en la clase. La palabra clave $this designa el objeto al que se aplica el método.
  • línea 17: se crea un objeto $p de tipo Persona. La palabra clave new sirve para crear un nuevo objeto. La operación devuelve una referencia al objeto creado (es decir, una dirección). Son posibles varias formas de escritura: new Persona(), new Persona, new persona. El nombre de la clase no distingue entre mayúsculas y minúsculas.
  • líneas 18-20: se crean los tres atributos necesarios para el método identity en el objeto $p.
  • línea 22: el método identidad de la clase Persona se aplica al objeto $p. En el código (líneas 9-11) del método identidad, $this hace referencia al mismo objeto que $p.

5.3. La clase Persona con atributos declarados (exemple_16)


<?php

class Personne {

  // atributos de la clase
  var $prénom;
  var $nom;
  var $âge;

  // método
  function identité() {
    return "[$this->prénom,$this->nom,$this->âge]";
  }
}
// prueba
// los atributos son públicos
$p = new Personne();
$p->prénom = "Paul";
$p->nom = "Langevin";
$p->âge = 48;
// llamada a un método
print "personne=" . $p->identité() . "\n";
// fin
exit;
?>

Resultados:

personne=[Paul,Langevin,48]

Comentarios

  • líneas 6-8: los atributos de la clase se declaran explícitamente con la palabra clave var.

5.4. La clase Persona con un constructor (exemple_17)

Los ejemplos anteriores mostraban clases Persona poco habituales, como las que se podían encontrar en PHP 4. No se recomienda seguir estos ejemplos. A continuación, presentamos una clase Persona que se ajusta a las buenas prácticas de PHP 5:


<?php

class Personne {

// atributos de la clase
  private $prénom;
  private $nom;
  private $âge;

// getters y 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;
  }

// constructor
  function __construct($prénom, $nom, $âge) {
    // se pasa por los set
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

// método toString
  function __toString() {
    return "[$this->prénom,$this->nom,$this->âge]";
  }

}

// prueba
// creación de un objeto persona
$p = new Personne("Paul", "Langevin", 48);
// identidad de esta persona
print "personne=$p\n";
// cambio de edad
$p->setAge(14);
// identidad de la persona
print "personne=$p\n";
// fin
exit;
?>

Resultados:

personne=[Paul,Langevin,48]
personne=[Paul,Langevin,14]

Comentarios

  • líneas 3-48: la clase Persona
  • líneas 6-8: los atributos privados (private) de la clase. Estos atributos solo son visibles dentro de la clase. Otras palabras clave que se pueden utilizar son:
  • public: convierte el atributo en un atributo público visible desde fuera de la clase
  • protected: convierte el atributo en un atributo protegido, visible desde el interior de la clase y de las clases derivadas de esta.
  • Dado que los atributos son privados, no se puede acceder a ellos desde fuera de la clase. Por lo tanto, no se puede escribir el siguiente código:
$p=new Personne() ;
$p->nom="Landru" ;

Aquí nos encontramos fuera de la clase Persona. Como el atributo nombre es privado, la línea 2 es incorrecta. Para inicializar los campos privados del objeto $p, hay dos formas:

  • (continuación)
    • utilizar los métodos públicos set y get (el nombre de estos métodos puede ser cualquiera) de las líneas 11-33. Entonces se podrá escribir:
$p=new Personne() ;
$p->setNom("Landru") ;
  • (continuación)
    • utilizar el constructor de las líneas 36-41. Entonces se escribirá:
$p=new Personne("Michel","Landru",44) ;

La escritura anterior llama automáticamente al método de la clase Persona denominado __construct.

  • Línea 54: esta línea muestra la persona $p en forma de cadena de caracteres. Para ello, se utiliza el método de la clase Persona denominado __toString.

5.5. La clase Persona con control de validez en el constructor (exemple_18)

El constructor de una clase es el lugar adecuado para verificar que los valores de inicialización del objeto sean correctos. Pero un objeto también puede inicializarse mediante sus métodos set o equivalentes. Para evitar colocar las mismas verificaciones en dos lugares diferentes, estas se incluirán en los métodos set. Si un valor de inicialización de un objeto resulta incorrecto, se lanzará una excepción. He aquí un ejemplo:


<?php

class Personne {

// atributos de la clase
  private $prénom;
  private $nom;
  private $âge;
  
// getters y 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) {
    // el nombre no puede estar vacío
    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) {
    // el apellido no puede estar vacío
    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) {
    // la edad debe ser válida
    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];
    }
  }

// constructor
  function __construct($prénom, $nom, $âge) {
    // se pasa por los setters
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

  // método toString
  function __toString() {
    return "[$this->prénom,$this->nom,$this->âge]";
  }
}

// prueba
// creación de un objeto Persona
$p = new Personne("Paul", "Langevin", 48);
// identidad de esta persona
print "personne=$p\n";
// creación de un objeto Persona erróneo
try {
  $p = new Personne("xx", "yy", "zz");
} catch (Exception $e) {
  print $e->getMessage();
}
// fin
exit;
?>

Resultados:

personne=[Paul,Langevin,48]
L'âge doit être un entier positif ou nul

Comentarios

  • líneas 23-30: inicialización del atributo «prénom» y comprobación del valor de inicialización
  • línea 25: uso de una expresión regular. El nombre es una secuencia de uno o varios caracteres, que puede ir precedida o seguida de espacios.
  • línea 26: si el apellido está vacío, se lanza una excepción; de lo contrario, se almacena el nombre (línea 28)
  • línea 66: uso del constructor de la clase Persona
  • línea 68: uso del método __toString de la clase Persona
  • líneas 70-74: gestión de la posible excepción lanzada por el constructor de la clase Persona.

5.6. Añadido de un método que actúa como segundo constructor (exemple_19)

En PHP 5, no es posible tener varios constructores con parámetros diferentes que permitan construir un objeto de diversas formas. Por lo tanto, se pueden utilizar métodos que actúan como constructores:


<?php

class Personne {

// atributos de la clase
  private $prénom;
  private $nom;
  private $âge;
  
// getters y setters
  public function getPrénom() {
    return $this->prénom;
  }

….

// constructor
  function __construct($prénom, $nom, $âge) {
    // se pasa por los set
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

  // método
  public function initWithPersonne($p) {
    // inicializa el objeto actual con una persona $p
    $this->__construct($p->prénom, $p->nom, $p->âge);
  }

  // método toString
  function __toString() {
    return "[$this->prénom,$this->nom,$this->âge]";
  }

}

// prueba
// creación de un objeto Persona
$p = new Personne("Paul", "Langevin", 48);
// identidad de esta persona
print "personne=$p\n";
// creación de una segunda persona
$p2 = new Personne("Laure", "Adeline", 67);
// inicialización de la primera con los valores de la segunda
$p->initWithPersonne($p2);
// verificación
print "personne=$p\n";
// fin
exit;
?>

Resultados:

personne=[Paul,Langevin,48]
personne=[Laure,Adeline,67]

Comentarios

  • líneas 26-29: el método initWithPersonne permite asignar al objeto actual los valores de los atributos de otro objeto Persona. Aquí, recurre al constructor __construct, pero no es obligatorio.

5.7. Una matriz de objetos Persona (exemple_20)

El siguiente ejemplo muestra que se pueden tener matrices de objetos.


<?php

class Personne {

// atributos de la clase
  private $prénom;
  private $nom;
  private $âge;
  
// getters y setters
  public function getPrénom() {
    return $this->prénom;
  }

...

// constructor
  function __construct($prénom, $nom, $âge) {
    // se pasa por los set
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

  // método
  public function initWithPersonne($p) {
….
  }

  // método toString
  function __toString() {
    ...
  }

}

// prueba
// creación de una tabla de objetos Persona
$groupe = array(new Personne("Paul", "Langevin", 48), new Personne("Sylvie", "Lefur", 70));

// identidad de estas personas
for ($i = 0; $i < count($groupe); $i++)
  print "groupe[$i]=$groupe[$i]\n";
// fin
exit;
?>

Resultados:

groupe[0]=[Paul,Langevin,48]
groupe[1]=[Sylvie,Lefur,70]

Comentarios

  • línea 39: creación de una tabla de 2 personas
  • línea 42: recorrido por la tabla
  • línea 43: $groupe[$i] es un objeto de tipo Persona. El método __toString se utiliza para mostrarlo.

5.8. Creación de una clase derivada de la clase Persona (exemple_21)


<?php

class Personne {

// atributos de la clase
  private $prénom;
  private $nom;
  private $âge;
  
// getters y setters
  public function getPrénom() {
    return $this->prénom;
  }
...

// constructor
  function __construct($prénom, $nom, $âge) {
    // se pasa por los set
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

  // método
  public function initWithPersonne($p) {
    // inicializa el objeto actual con una persona $p
    $this->__construct($p->prénom, $p->nom, $p->âge);
  }

  // método toString
  function __toString() {
    return "[$this->prénom,$this->nom,$this->âge]";
  }

}

// una clase derivada de Persona
class Enseignant extends Personne {

  // atributos
  private $discipline;   // materia impartida

  // getter y setter

  public function getDiscipline() {
    return $this->discipline;
  }

  public function setDiscipline($discipline) {
    $this->discipline = $discipline;
  }

  // constructor

  public function __construct($prénom, $nom, $âge, $discipline) {
    // atributos del padre
    parent::__construct($prénom, $nom, $âge);
    // otros atributos
    $this->setDiscipline($discipline);
  }

  // sobrecarga de la función __toString de la clase padre
  public function __toString() {
    return "[" . parent::__toString() . ",$this->discipline]";
  }

}

// prueba
// creación de una tabla de objetos Persona y derivados
$groupe = array(new Enseignant("Paul", "Langevin", 48, "anglais"), new Personne("Sylvie", "Lefur", 70));

// identidad de estas personas
for ($i = 0; $i < count($groupe); $i++)
  print "groupe[$i]=$groupe[$i]\n";
// fin
exit;
?>

Resultados:

groupe[0]=[[Paul,Langevin,48],anglais]
groupe[1]=[Sylvie,Lefur,70]

Comentarios

  • líneas 3-35: la clase Persona
  • línea 38: la clase Profesor deriva (extends) de la clase Persona. La clase derivada Profesor hereda los atributos y métodos de su clase madre.
  • línea 41: la clase Profesor añade un nuevo atributo «disciplina» propio de esta
  • línea 55: el constructor de la clase Profesor recibe 4 parámetros
    • 3 para inicializar su clase padre (nombre, apellidos, edad)
    • 1 para su propia inicialización (disciplina)
  • línea 57: la clase derivada tiene acceso a los métodos y constructores de su clase padre mediante la palabra clave parent ::. Aquí se pasan los parámetros (nombre, apellidos, edad) al constructor de la clase padre.
  • línea 64: el método __toString de la clase derivada utiliza el método __toString de la clase padre.
  • línea 71: una matriz que contiene un objeto Enseignant y un objeto Personne.
  • línea 74: se recorre los elementos de la matriz
  • línea 75: se llamará al método __toString de cada elemento $groupe[$i]. La clase Persona tiene un método __toString. La clase Profesor tiene dos: el de su clase padre y el propio. Cabe preguntarse cuál se llamará. La ejecución muestra que se ha llamado al de la clase Profesor. Siempre es así: cuando se llama a un método en un objeto, se busca este en el siguiente orden: en el propio objeto, en su clase padre si tiene una, luego en la clase padre de la clase padre, etc. La búsqueda se detiene en cuanto se encuentra el método.

5.9. Creación de una segunda clase derivada de la clase Persona (exemple_22)

El siguiente ejemplo crea una clase Estudiante derivada de la clase Persona:


<?php

class Personne {

// atributos de la clase
  private $prénom;
  private $nom;
  private $âge;

// getters y setters
  public function getPrénom() {
    return $this->prénom;
  }
...

// constructor
  function __construct($prénom, $nom, $âge) {
    // se pasa por los set
    $this->setPrénom($prénom);
    $this->setNom($nom);
    $this->setAge($âge);
  }

  // método
  public function initWithPersonne($p) {
    // inicializa el objeto actual con una persona $p
    ...
  }

  // método toString
  function __toString() {
    return "[$this->prénom,$this->nom,$this->âge]";
  }

}

// una clase derivada de persona
class Enseignant extends Personne {

  // atributos
  private $discipline;   // materia impartida

  // getter y setter
...

  // constructor

  public function __construct($prénom, $nom, $âge, $discipline) {
    // atributos del padre
    parent::__construct($prénom, $nom, $âge);
    // otros atributos
    $this->setDiscipline($discipline);
  }

  // sobrescrito de la función _identité__toString de la clase padre
  public function __toString() {
    return "[" . parent::__toString() . ",$this->discipline]";
  }

}

// una clase derivada de Persona
class Etudiant extends Personne {

  // atributos
  private $formation;   // materia impartida

  // getter y setter

  public function getFormation() {
    return $this->formation;
  }

  public function setFormation($formation) {
    $this->formation = $formation;
  }

  // constructor

  public function __construct($prénom, $nom, $âge, $formation) {
    // atributos del padre
    parent::__construct($prénom, $nom, $âge);
    // otros atributos
    $this->setFormation($formation);
  }

  // sobrecarga de la función __toString de la clase padre
  public function __toString() {
    return "[" . parent::__toString() . ",$this->formation]";
  }

}

// prueba
// creación de una tabla de objetos persona y derivados
$groupe = array(new Enseignant("Paul", "Langevin", 48, "anglais"), new Personne("Sylvie", "Lefur", 70), new Etudiant("Steve", "Boer", 23, "iup2 qualité"));

// identidad de estas personas
for ($i = 0; $i < count($groupe); $i++)
  print "groupe[$i]=$groupe[$i]\n";
// fin
exit;
?>

Resultados:

groupe[0]=[[Paul,Langevin,48],anglais]
groupe[1]=[Sylvie,Lefur,70]
groupe[2]=[[Steve,Boer,23],iup2 qualité]

5.10. Las interfaces (exemple_23)

Una interfaz es una estructura que define prototipos de métodos. Una clase que implementa una interfaz define el código de todos los métodos de la interfaz.


<?php

// una interfaz
interface IExemple {
  function ajouter($i, $j);

  function soustraire($i, $j);
}

// implementación 1 de la interfaz
class Classe1 implements IExemple {

  public function ajouter($a, $b) {
    return $a + $b + 10;
  }

  public function soustraire($a, $b) {
    return $a - $b + 20;
  }

}

// implementación 2 de la interfaz
class Classe2 implements IExemple {

  public function ajouter($a, $b) {
    return $a + $b + 100;
  }

  public function soustraire($a, $b) {
    return $a - $b + 200;
  }

}

// función
function calculer($a, $b, IExemple $interface) {
  print $interface->ajouter($a, $b)."\n";
  print $interface->soustraire($a, $b)."\n";
}

// ------------------- main
// creación de 2 objetos de tipo Clase1 y Clase2
$c1 = new Classe1();
$c2 = new Classe2();
// llamada a la función calcular
calculer(4, 3, $c1);
calculer(14, 13, $c2);
?>

Resultados

17
21
127
201

Comentarios

  • líneas 4-8: la interfaz IExemple define dos métodos: la función añadir (línea 5) y la función restar (línea 7). La interfaz no define el código de estos métodos. Son las clases que implementan la interfaz las que lo harán.
  • línea 11: la clase Classe1 implementa la interfaz IExemple. Por lo tanto, define un código para los métodos «añadir» (línea 13) y «restar» (línea 17).
  • líneas 24-34: lo mismo para la clase Classe2
  • línea 37: el método calculer admite tres parámetros: dos enteros $a y $b y un objeto $interface que implementa la interfaz IExemple. Se podría haber escrito function calculer($a,$b,$interface) sin indicar el tipo IExemple del parámetro $interface. Al indicarlo, se permite que el intérprete PHP verifique que el parámetro efectivo es efectivamente un objeto que implementa la interfaz IExemple.
  • líneas 38-39: uso de los métodos «añadir» y «restar» del objeto $interface. Dado que este implementa la interfaz IExemple, sabemos que dispone de estos dos métodos.
  • líneas 44-45: creación de dos objetos de tipos diferentes, pero que implementan ambos la interfaz IExemple.
  • línea 47: se pasa a la función calcular el objeto $c1 de tipo Classe1 que implementa la interfaz IExemple.
  • línea 48: se pasa a la función «calcular» el objeto $c2 de tipo Classe2, que implementa la interfaz IExemple.