1. Code
  2. Coding Fundamentals
  3. OOP

Programación Orientada a Objetos en PHP para Principiantes

Para muchos programadores de PHP, la programación orientada a objetos es un tema aterrador, lleno de sintaxis complicada y otros obstáculos. Como lo detalla mi libro "Pro PHP and jQuery", aprenderás los conceptos detrás de la programación orientada a objetos (POO), un estilo de programación en el que las acciones relacionadas se agrupan en clases; para lograr la creación de un código más compacto y eficáz. Entendiendo La Programación Orientada a Objetos Programación Orientada a Objetos es un estilo de programación que le permite a los desarrolladores agrupar tareas similares en clases. Esto nos ayuda a mantener el código de acuerdo al principo de "No te repitas" (NTR) facilitándo también su mantenimiento. "Programación Orientada a Objetos es un estilo de programación que permite a los desarrolladores agrupar tareas similares en clases." Uno de los mayores beneficios de la programación NTR es que; si alguna parte de la información cambia en tu programa, generalmente solo un cambio es requerido para actualizar el código. Una de las más grandes pesadillas para los desarrolladores es el mantenimiento de código donde los datos son declarados uno tras otro, es decir, cualquier cambio al programa se convierte en un juego infinitamente más frustrante de ¿Donde está Waldo?, mientras continuan persiguiendo datos y funcionalidad duplicada. La POO es intimidante para muchos desarrolladores porque introduce nueva sintaxis, y a primera vista, pareciera ser mucho más compleja que simple programación procedimental, o lineal. Sin embargo, observando más de cerca, la POO es al final un enfoque más simple y sencillo a la programación. Comprendiendo Objetos y Clases Antes de profundizar en los puntos más avanzados de la POO, un entendimiento básico de las diferencias entre objetos y clases es necesario. Esta sección tratará los componetes básicos de las clases, sus diferentes capacidades y algunos de sus usos Reconociendo las Diferencias Entre Objetos y Clases Fotos por: Istant Jefferson y John Wardell Programadores comienzan hablando de objetos y clases, como si estos fueran términos intercambiables Sin embargo, esto no es cierto. A primera instancia, hay confusión en la POO: programadores con experiencia comienzan a hablar acerca de objetos y clases, y parecieran ser terminos intercambiables. Sin embargo, este no es el caso, aunque la diferencia puede ser dificil de apreciar al principio. Una clase, por ejemplo, es como los planos de una casa. Define la forma de la casa en papel, con las relaciones entre diferentes partes de la casa planeadas y definidas de manera precisa, aun cuando la casa no existe. En cambio, un objeto es la casa construida de acuerdo a el plano. los datos almacenados en el objeto son como la madera, los cables y el concreto que conforman la casa: si no son colocados de acuerdo al plano, solo formarán un montón de cosas inútiles. No obstante, cuando todo se junta, se convierte en una organizada y útil casa. Las Clases forman la estructura de los datos y las acciones y usan esa información para construir objetos. Más de un objeto puede ser construido de la misma clase al mismo tiempo, cada uno de manera independiente de los otros. Continuando con nuestra analogia de construcción, es similar al modo en que una subdivision puede ser construida del mismo plano: 150 casas diferetes que lucen iguales pero tienen diferentes familias y decoraciones en el interior. Estrcturación de una Clase La sintaxis para crear una clase es bastante sencilla: se declara una clase usando la palabra reservada class , seguida del nombre de la clase y un par de corchetes ({}): php
Scroll to top

Spanish (Español) translation by Viviana Brito (you can also view the original English article)

Para muchos programadores de PHP, la programación orientada a objetos es un tema aterrador, lleno de sintaxis complicada y otros obstáculos. Como lo detalla mi libro "Pro PHP and jQuery", aprenderás los conceptos detrás de la programación orientada a objetos (POO), un estilo de programación en el que las acciones relacionadas se agrupan en clases; para lograr la creación de un código más compacto y eficáz.

Entendiendo La Programación Orientada a Objetos

Programación Orientada a Objetos es un estilo de programación que le permite a los desarrolladores agrupar tareas similares en clases. Esto nos ayuda a mantener el código de acuerdo al principo de "No te repitas" (NTR) facilitándo también su mantenimiento.

"Programación Orientada a Objetos es un estilo de programación que permite a los desarrolladores agrupar tareas similares en clases."

Uno de los mayores beneficios de la programación NTR es que; si alguna parte de la información cambia en tu programa, generalmente solo un cambio es requerido para actualizar el código. Una de las más grandes pesadillas para los desarrolladores es el mantenimiento de código donde los datos son declarados uno tras otro, es decir, cualquier cambio al programa se convierte en un juego infinitamente más frustrante de ¿Donde está Waldo?, mientras continuan persiguiendo datos y funcionalidad duplicada.

La POO es intimidante para muchos desarrolladores porque introduce nueva sintaxis, y a primera vista, pareciera ser mucho más compleja que simple programación procedimental, o lineal. Sin embargo, observando más de cerca, la POO es al final un enfoque  más simple y sencillo a la programación.

Comprendiendo Objetos y Clases

Antes de profundizar en los puntos más avanzados de la POO, un entendimiento básico de las diferencias entre objetos y clases es necesario. Esta sección tratará los componetes básicos de las clases, sus diferentes capacidades y algunos de sus usos

Reconociendo las Diferencias Entre Objetos y Clases

Fotos por: Istant Jefferson y John Wardell

Programadores comienzan hablando de objetos y clases, como si estos fueran términos intercambiables Sin embargo, esto no es cierto.

A primera instancia, hay confusión en la POO: programadores con experiencia comienzan a hablar acerca de objetos y clases, y parecieran ser terminos intercambiables. Sin embargo, este no es el caso, aunque la diferencia puede ser dificil de apreciar al principio.

Una clase, por ejemplo, es como los planos de una casa. Define la forma de la casa en papel, con las relaciones entre diferentes partes de la casa planeadas y definidas de manera precisa, aun cuando la casa no existe.

En cambio, un objeto es la casa construida de acuerdo a el plano. los datos almacenados en el objeto son como la madera, los cables y el concreto que conforman la casa: si no son colocados de acuerdo al plano, solo formarán un montón de cosas inútiles. No obstante, cuando todo se junta, se convierte en una organizada y útil casa.

Las Clases forman la estructura de los datos y las acciones y usan esa información para construir objetos. Más de un objeto puede ser construido de la misma clase al mismo tiempo, cada uno de manera independiente de los otros. Continuando con nuestra analogia de construcción, es similar al modo en que una subdivision puede ser construida del mismo plano: 150 casas diferetes que lucen iguales pero tienen diferentes
familias y decoraciones en el interior.

Estrcturación de una Clase

La sintaxis para crear una clase es bastante sencilla: se declara una clase usando la palabra reservada class , seguida del nombre de la clase y un par de corchetes ({}):

1
<?php
2
3
class MyClass
4
{
5
  // Class properties and methods go here

6
}
7
8
?>

Después de la creación, una nueva clase puede ser instanciada y almacenada en una variable usando la palabra reservada new:

1
$obj = new MyClass;

para ver el contenido de la clase, usa var_dump():

1
var_dump($obj);

Prueba este proceso colocando todo el código anterior en un archivo nuevo llamado test.php en tu carpeta [local] de prueba:

1
<?php
2
3
class MyClass
4
{
5
  // Class properties and methods go here

6
}
7
8
$obj = new MyClass;
9
10
var_dump($obj);
11
12
?>

Carga la página en tu navegador colocando la dirección http://localhost/test.php y debería mostrarse lo siguiente:

1
object(MyClass)#1 (0) { }

En su forma más simple, has completado tu primer script de POO.

Definiendo Propiedades de una Clase

Para agregar datos a una clase; propiedades o variables específicas de la clase, son utilizadas. Estas trabajan igual que variables regulares, solo que están unidas al objeto y por lo tanto solo puede accederse a ellas usando el objeto

Para agregar una propiedad a MyClass, añade el siguiente scipt de código:

1
<?php
2
3
class MyClass
4
{
5
  public $prop1 = "I'm a class property!";
6
}
7
8
$obj = new MyClass;
9
10
var_dump($obj);
11
12
?>

La palabra reservada public determina la visibilidad de la propiedad, de la cual aprenderás más adelante en este capítulo. Después, la propiedad es llamada usando la sintaxis estándar de variable, y se le asigna un valor (aunque las propiedades de clase no necesitan un valor inicial).

Para leer esta propiedad y mostrarla en el navegador, referencia el objeto desde el cual leer y la propiedad a ser leída:

1
echo $obj->prop1;

Dado que pueden existir múltiples instancias de una clase, si el objeto individual no está referenciado, el script sería incapaz de determinar de qué objeto leer. El uso de la flecha (->) es una construcción de la POO que accede a las propiedades y métodos contenidos de un objeto dado.

Modifica el script en test.php para leer la propiedad en lugar de volcar el contenido entero de la clase modificando el código como se muestra: 

1
<?php
2
3
class MyClass
4
{
5
  public $prop1 = "I'm a class property!";
6
}
7
8
$obj = new MyClass;
9
10
echo $obj->prop1; // Output the property

11
12
?>

Recargando tu navegador ahora mostrará la siguiente salida:

1
I'm a class property!

Definiendo Métidos de Clase

Los Métodos son funciones específicas de la clase Las acciones individuales que un objeto será capaz de realizar son definidas en el interior de la clase como métodos

Por ejemplo, para crear métodos que establecerán(set) y devolverán(get) el valor de la la propiedad de clase $prop1, añade el siguiente código

1
<?php
2
3
class MyClass
4
{
5
  public $prop1 = "I'm a class property!";
6
7
  public function setProperty($newval)
8
  {
9
      $this->prop1 = $newval;
10
  }
11
12
  public function getProperty()
13
  {
14
      return $this->prop1 . "<br />";
15
  }
16
}
17
18
$obj = new MyClass;
19
20
echo $obj->prop1;
21
22
?>

Nota — POO permite que los objetos se referencien a sí mismos usando $this. Cuando se trabaja dentro de un método, usa $this de la misma forma que utilizarías el nombre del objeto fuera de la clase

Para usar estos métodos, llámalos tal y como a las funciones nomales, pero primero, referencia el objeto al que pertenecen. Lee la propiedad de MyClass, cambia su valor, y léelo de nuevo haciendo las modificaciones mostradas abajo:

1
<?php
2
3
class MyClass
4
{
5
  public $prop1 = "I'm a class property!";
6
7
  public function setProperty($newval)
8
  {
9
      $this->prop1 = $newval;
10
  }
11
12
  public function getProperty()
13
  {
14
      return $this->prop1 . "<br />";
15
  }
16
}
17
18
$obj = new MyClass;
19
20
echo $obj->getProperty(); // Get the property value

21
22
$obj->setProperty("I'm a new property value!"); // Set a new one

23
24
echo $obj->getProperty(); // Read it out again to show the change

25
26
?>

Recarga tu navegador, y verás lo siguiente:

1
I'm a class property!

2
I'm a new property value!

"El poder de la POO se hace patente cuando se usan múltiples instancias de la
misma clase."

1
<?php
2
3
class MyClass
4
{
5
  public $prop1 = "I'm a class property!";
6
7
  public function setProperty($newval)
8
  {
9
      $this->prop1 = $newval;
10
  }
11
12
  public function getProperty()
13
  {
14
      return $this->prop1 . "<br />";
15
  }
16
}
17
18
// Create two objects

19
$obj = new MyClass;
20
$obj2 = new MyClass;
21
22
// Get the value of $prop1 from both objects

23
echo $obj->getProperty();
24
echo $obj2->getProperty();
25
26
// Set new values for both objects

27
$obj->setProperty("I'm a new property value!");
28
$obj2->setProperty("I belong to the second instance!");
29
30
// Output both objects' $prop1 value

31
echo $obj->getProperty();
32
echo $obj2->getProperty();
33
34
?>

Cuando cargas los resultados en tu navegador, se leen como sigue:

1
I'm a class property!

2
I'm a class property!
3
I'm a new property value!
4
I belong to the second instance!

Como puedes ver, la POO mantiene los objetos como entidades separadas, lo que hace más fácil la separación de diferentes trozos de código en lotes pequeños y relacionados.

Métodos Mágicos en POO

Para hacer el uso de objetos más fácil, PHP también provee un número de métodos mágicos, o métodos especiales que son llamados cuando ciertas acciones comunes ocurren dentro de los objetos. Esto permite a los desarrolladores llevar a cabo un número de tareas útiles con relativa facilidad

Usando Constructores y Destructores

Cuando un objeto es instanciado, es a menudo deseable establecer algunas cosas de inmediato. Para manejar esto, PHP nos da el método mágico __construct(), el cual es llamado automáticamente en cuanto un nuevo objeto es
creado.

Con el propósito de ilustrar el concepto de constructores, añade un constructor a MyClass que mostrará un mensaje siempre que una nueva instancia de la clase sea creada:

1
<?php
2
3
class MyClass
4
{
5
  public $prop1 = "I'm a class property!";
6
7
  public function __construct()
8
  {
9
      echo 'The class "', __CLASS__, '" was initiated!<br />';
10
  }
11
12
  public function setProperty($newval)
13
  {
14
      $this->prop1 = $newval;
15
  }
16
17
  public function getProperty()
18
  {
19
      return $this->prop1 . "<br />";
20
  }
21
}
22
23
// Create a new object

24
$obj = new MyClass;
25
26
// Get the value of $prop1

27
echo $obj->getProperty();
28
29
// Output a message at the end of the file

30
echo "End of file.<br />";
31
32
?>

Nota — __CLASS__ devuelve el nombre de la clase desde la que es llamada; a esto es lo que se conoce como constante mágica. Hay muchas constantes mágicas disponibles, sobre la que puedes leer más en el manuel de PHP.

Recargando el archivo en tu navegador se producirá el siguiente resultado:

1
The class "MyClass" was initiated!
2
I'm a class property!
3
End of file.

Para llamar a una función cuando el objeto es destruido, el método mágico __destruct() está disponible. Esto es útil para hacer limpieza de la clase (cerrar conexiones a la base de datos, por ejemplo).

Muestra un mensaje cuando el objeto es destruido definiendo el método mágico
__destruct() en MyClass:

1
<?php
2
3
class MyClass
4
{
5
  public $prop1 = "I'm a class property!";
6
7
  public function __construct()
8
  {
9
      echo 'The class "', __CLASS__, '" was initiated!<br />';
10
  }
11
12
  public function __destruct()
13
  {
14
      echo 'The class "', __CLASS__, '" was destroyed.<br />';
15
  }
16
17
  public function setProperty($newval)
18
  {
19
      $this->prop1 = $newval;
20
  }
21
22
  public function getProperty()
23
  {
24
      return $this->prop1 . "<br />";
25
  }
26
}
27
28
// Create a new object

29
$obj = new MyClass;
30
31
// Get the value of $prop1

32
echo $obj->getProperty();
33
34
// Output a message at the end of the file

35
echo "End of file.<br />";
36
37
?>

Con un destructor definido, recargando el archivo file muestra la siguiente salida:

1
The class "MyClass" was initiated!
2
I'm a class property!
3
End of file.
4
The class "MyClass" was destroyed.

"Cuando se alcanza el final de un archivo, PHP libera automáticamente todos los recursos."

Para lanzar explícitamente el destructor, puedes destruir los objetos usando la
función unset():

1
<?php
2
3
class MyClass
4
{
5
  public $prop1 = "I'm a class property!";
6
7
  public function __construct()
8
  {
9
      echo 'The class "', __CLASS__, '" was initiated!<br />';
10
  }
11
12
  public function __destruct()
13
  {
14
      echo 'The class "', __CLASS__, '" was destroyed.<br />';
15
  }
16
17
  public function setProperty($newval)
18
  {
19
      $this->prop1 = $newval;
20
  }
21
22
  public function getProperty()
23
  {
24
      return $this->prop1 . "<br />";
25
  }
26
}
27
28
// Create a new object

29
$obj = new MyClass;
30
31
// Get the value of $prop1

32
echo $obj->getProperty();
33
34
// Destroy the object

35
unset($obj);
36
37
// Output a message at the end of the file

38
echo "End of file.<br />";
39
40
?>

Ahora los resultados cambian por lo siguiente cuando recargas tu navegador:

1
The class "MyClass" was initiated!
2
I'm a class property!
3
The class "MyClass" was destroyed.
4
End of file.

Convertir a un String

Para evitar errores si un script intenta escribir MyClass como una cadena, se usa otro método mágico llamado __toString().

Sin __troString(), intentar escribir el objeto como una cadena provoca un error fatal. Trata de usar echo para escribir el objeto sin usar un método mágico en su lugar:

1
<?php
2
3
class MyClass
4
{
5
  public $prop1 = "I'm a class property!";
6
7
  public function __construct()
8
  {
9
      echo 'The class "', __CLASS__, '" was initiated!<br />';
10
  }
11
12
  public function __destruct()
13
  {
14
      echo 'The class "', __CLASS__, '" was destroyed.<br />';
15
  }
16
17
  public function setProperty($newval)
18
  {
19
      $this->prop1 = $newval;
20
  }
21
22
  public function getProperty()
23
  {
24
      return $this->prop1 . "<br />";
25
  }
26
}
27
28
// Create a new object

29
$obj = new MyClass;
30
31
// Output the object as a string

32
echo $obj;
33
34
// Destroy the object

35
unset($obj);
36
37
// Output a message at the end of the file

38
echo "End of file.<br />";
39
40
?>

Esto produce el siguiente resultado:

1
The class "MyClass" was initiated!
2
3
Catchable fatal error: Object of class MyClass could not be converted to string in /Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 40

Para evitar este error, añade un método __toString():

1
<?php
2
3
class MyClass
4
{
5
  public $prop1 = "I'm a class property!";
6
7
  public function __construct()
8
  {
9
      echo 'The class "', __CLASS__, '" was initiated!<br />';
10
  }
11
12
  public function __destruct()
13
  {
14
      echo 'The class "', __CLASS__, '" was destroyed.<br />';
15
  }
16
17
  public function __toString()
18
  {
19
      echo "Using the toString method: ";
20
      return $this->getProperty();
21
  }
22
23
  public function setProperty($newval)
24
  {
25
      $this->prop1 = $newval;
26
  }
27
28
  public function getProperty()
29
  {
30
      return $this->prop1 . "<br />";
31
  }
32
}
33
34
// Create a new object

35
$obj = new MyClass;
36
37
// Output the object as a string

38
echo $obj;
39
40
// Destroy the object

41
unset($obj);
42
43
// Output a message at the end of the file

44
echo "End of file.<br />";
45
46
?>

En este caso, intentar convertir el objeto en una cadena acaba con una llamada al método getProperty(). Carga el script test en tu navegador para ver el resultado:

1
The class "MyClass" was initiated!
2
Using the toString method: I'm a class property!
3
The class "MyClass" was destroyed.
4
End of file.

Consejo — Además de los métodos mágicos tratados en esta sección, hay otros muchos disponibles. Para una lista completa de los métodos mágicos, mira la página del manual PHP

Usando Herencia de Clase

Las clases pueden heredar los métodos y propiedades de otra clase usando la palabra reservada extends. Por ejemplo, para crear una segunda clase que extienda MyClass y añada un método, añadirías lo siguiente en tu archivo test:

1
<?php
2
3
class MyClass
4
{
5
  public $prop1 = "I'm a class property!";
6
7
  public function __construct()
8
  {
9
      echo 'The class "', __CLASS__, '" was initiated!<br />';
10
  }
11
12
  public function __destruct()
13
  {
14
      echo 'The class "', __CLASS__, '" was destroyed.<br />';
15
  }
16
17
  public function __toString()
18
  {
19
      echo "Using the toString method: ";
20
      return $this->getProperty();
21
  }
22
23
  public function setProperty($newval)
24
  {
25
      $this->prop1 = $newval;
26
  }
27
28
  public function getProperty()
29
  {
30
      return $this->prop1 . "<br />";
31
  }
32
}
33
34
class MyOtherClass extends MyClass
35
{
36
  public function newMethod()
37
  {
38
      echo "From a new method in " . __CLASS__ . ".<br />";
39
  }
40
}
41
42
// Create a new object

43
$newobj = new MyOtherClass;
44
45
// Output the object as a string

46
echo $newobj->newMethod();
47
48
// Use a method from the parent class

49
echo $newobj->getProperty();
50
51
?>

En cuanto recargues tu archivo test en tu navegador, se mostrará lo siguiente:

1
The class "MyClass" was initiated!
2
From a new method in MyOtherClass.
3
I'm a class property!
4
The class "MyClass" was destroyed.

Sobreescribiendo Propiedades y Métodos Heredados

Para cambiar el comportamiento de una propiedad o método existente en la nueva clase, simplemente sobreescríbelo declarando de nuevo en la nueva clase:

1
<?php
2
3
class MyClass
4
{
5
  public $prop1 = "I'm a class property!";
6
7
  public function __construct()
8
  {
9
      echo 'The class "', __CLASS__, '" was initiated!<br />';
10
  }
11
12
  public function __destruct()
13
  {
14
      echo 'The class "', __CLASS__, '" was destroyed.<br />';
15
  }
16
17
  public function __toString()
18
  {
19
      echo "Using the toString method: ";
20
      return $this->getProperty();
21
  }
22
23
  public function setProperty($newval)
24
  {
25
      $this->prop1 = $newval;
26
  }
27
28
  public function getProperty()
29
  {
30
      return $this->prop1 . "<br />";
31
  }
32
}
33
34
class MyOtherClass extends MyClass
35
{
36
  public function __construct()
37
  {
38
      echo "A new constructor in " . __CLASS__ . ".<br />";
39
  }
40
41
  public function newMethod()
42
  {
43
      echo "From a new method in " . __CLASS__ . ".<br />";
44
  }
45
}
46
47
// Create a new object

48
$newobj = new MyOtherClass;
49
50
// Output the object as a string

51
echo $newobj->newMethod();
52
53
// Use a method from the parent class

54
echo $newobj->getProperty();
55
56
?>

Esto cambia la salida en el navegador a:

1
A new constructor in MyOtherClass.
2
From a new method in MyOtherClass.
3
I'm a class property!
4
The class "MyClass" was destroyed.

Preservar la Funcionalidad Original del Método Mientras se Sobreescriben Métodos

Para añadir una nueva funcionalidad a un método heredado mientras se mantiene el método original intacto, usa la palabra reservada parent con el operador de resolución de ámbito (::):

1
<?php
2
3
class MyClass
4
{
5
  public $prop1 = "I'm a class property!";
6
7
  public function __construct()
8
  {
9
      echo 'The class "', __CLASS__, '" was initiated!<br />';
10
  }
11
12
  public function __destruct()
13
  {
14
      echo 'The class "', __CLASS__, '" was destroyed.<br />';
15
  }
16
17
  public function __toString()
18
  {
19
      echo "Using the toString method: ";
20
      return $this->getProperty();
21
  }
22
23
  public function setProperty($newval)
24
  {
25
      $this->prop1 = $newval;
26
  }
27
28
  public function getProperty()
29
  {
30
      return $this->prop1 . "<br />";
31
  }
32
}
33
34
class MyOtherClass extends MyClass
35
{
36
  public function __construct()
37
  {
38
      parent::__construct(); // Call the parent class's constructor

39
      echo "A new constructor in " . __CLASS__ . ".<br />";
40
  }
41
42
  public function newMethod()
43
  {
44
      echo "From a new method in " . __CLASS__ . ".<br />";
45
  }
46
}
47
48
// Create a new object

49
$newobj = new MyOtherClass;
50
51
// Output the object as a string

52
echo $newobj->newMethod();
53
54
// Use a method from the parent class

55
echo $newobj->getProperty();
56
57
?>

Esto muestra el resultado tanto del constructor de la clase padre como el del constructor de la nueva clase:

1
The class "MyClass" was initiated!
2
A new constructor in MyOtherClass.
3
From a new method in MyOtherClass.
4
I'm a class property!
5
The class "MyClass" was destroyed.

Asignando el Ámbito de Propiedades y Métodos

Para añadir control sobre los objetos, se asigna un ámbito a los métodos y propiedades. Esto controla cómo y desde dónde se puede acceder a las propiedades y los métodos- Hay tres palabras reservadas de ámbito: public, protected, y private. Además de su ámbito, un método o propiedad puede ser declarado como static, lo que les permite ser accedidos sin una instanciación de la clase

"Para añadir control sobre objetos, a los métodos y propiedades se les asigna un ámbito."

Nota — El ámbito es una nueva característica de PHP 5. Para información sobre compatibilidad en POO con PHP 4, ver la página del manual de PHP.

Propiedades y Métodos Públicos

Todos los métodos y propiedades que has usado hasta ahora eran públicos. Esto significa que pueden ser accedidos desde cualquier parte, tanto desde el interior como el exterior de la clase.

Propiedades y Métodos Protegidos

Cuando una propiedad o método se declara protected, sólo puede ser accedido desde el interior de la propia clase o de sus hijas (clases que extiendan a la clase que contenga el método protegido)

Declara el método getProperty() como protegido en MyClass e intenta accederlo directamente desde fuera de la clase:

1
<?php
2
3
class MyClass
4
{
5
  public $prop1 = "I'm a class property!";
6
7
  public function __construct()
8
  {
9
      echo 'The class "', __CLASS__, '" was initiated!<br />';
10
  }
11
12
  public function __destruct()
13
  {
14
      echo 'The class "', __CLASS__, '" was destroyed.<br />';
15
  }
16
17
  public function __toString()
18
  {
19
      echo "Using the toString method: ";
20
      return $this->getProperty();
21
  }
22
23
  public function setProperty($newval)
24
  {
25
      $this->prop1 = $newval;
26
  }
27
28
  protected function getProperty()
29
  {
30
      return $this->prop1 . "<br />";
31
  }
32
}
33
34
class MyOtherClass extends MyClass
35
{
36
  public function __construct()
37
  {
38
      parent::__construct();
39
echo "A new constructor in " . __CLASS__ . ".<br />";
40
  }
41
42
  public function newMethod()
43
  {
44
      echo "From a new method in " . __CLASS__ . ".<br />";
45
  }
46
}
47
48
// Create a new object

49
$newobj = new MyOtherClass;
50
51
// Attempt to call a protected method

52
echo $newobj->getProperty();
53
54
?>

En cuanto intentes ejecutar este script, se mostrarán los siguientes errores:

1
The class "MyClass" was initiated!
2
A new constructor in MyOtherClass.
3
4
Fatal error: Call to protected method MyClass::getProperty() from context '' in /Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 55

Ahora, crea un nuevo método en MyOtherClass para llamar al método getProperty():

1
<?php
2
3
class MyClass
4
{
5
  public $prop1 = "I'm a class property!";
6
7
  public function __construct()
8
  {
9
      echo 'The class "', __CLASS__, '" was initiated!<br />';
10
  }
11
12
  public function __destruct()
13
  {
14
      echo 'The class "', __CLASS__, '" was destroyed.<br />';
15
  }
16
17
  public function __toString()
18
  {
19
      echo "Using the toString method: ";
20
      return $this->getProperty();
21
  }
22
23
  public function setProperty($newval)
24
  {
25
      $this->prop1 = $newval;
26
  }
27
28
  protected function getProperty()
29
  {
30
      return $this->prop1 . "<br />";
31
  }
32
}
33
34
class MyOtherClass extends MyClass
35
{
36
  public function __construct()
37
  {
38
      parent::__construct();
39
echo "A new constructor in " . __CLASS__ . ".<br />";
40
  }
41
42
  public function newMethod()
43
  {
44
      echo "From a new method in " . __CLASS__ . ".<br />";
45
  }
46
47
  public function callProtected()
48
  {
49
      return $this->getProperty();
50
  }
51
}
52
53
// Create a new object

54
$newobj = new MyOtherClass;
55
56
// Call the protected method from within a public method

57
echo $newobj->callProtected();
58
59
?>

Esto genera el resultado deseado:

1
The class "MyClass" was initiated!
2
A new constructor in MyOtherClass.
3
I'm a class property!
4
The class "MyClass" was destroyed.

Propiedades y Métodos Privados

Una propiedad o método declarado private es accesible sólo desde el interior de la clase que lo define. Esto significa que incluso aunque una nueva clase extienda la clase que define la propiedad privada, esta propiedad o método no estarán disponibles ni siquiera en el interior de la clase hija.

Para demostrar esto, declara getProperty() como privada en MyClass, e intenta llamar a callProtected() desde
MyOtherClass:

1
<?php
2
3
class MyClass
4
{
5
  public $prop1 = "I'm a class property!";
6
7
  public function __construct()
8
  {
9
      echo 'The class "', __CLASS__, '" was initiated!<br />';
10
  }
11
12
  public function __destruct()
13
  {
14
      echo 'The class "', __CLASS__, '" was destroyed.<br />';
15
  }
16
17
  public function __toString()
18
  {
19
      echo "Using the toString method: ";
20
      return $this->getProperty();
21
  }
22
23
  public function setProperty($newval)
24
  {
25
      $this->prop1 = $newval;
26
  }
27
28
  private function getProperty()
29
  {
30
      return $this->prop1 . "<br />";
31
  }
32
}
33
34
class MyOtherClass extends MyClass
35
{
36
  public function __construct()
37
  {
38
      parent::__construct();
39
      echo "A new constructor in " . __CLASS__ . ".<br />";
40
  }
41
42
  public function newMethod()
43
  {
44
      echo "From a new method in " . __CLASS__ . ".<br />";
45
  }
46
47
  public function callProtected()
48
  {
49
      return $this->getProperty();
50
  }
51
}
52
53
// Create a new object

54
$newobj = new MyOtherClass;
55
56
// Use a method from the parent class

57
echo $newobj->callProtected();
58
59
?>

Recarga tu navegador, y el siguiente error aparecerá:

1
The class "MyClass" was initiated!
2
A new constructor in MyOtherClass.
3
4
Fatal error: Call to private method MyClass::getProperty() from context 'MyOtherClass' in /Applications/XAMPP/xamppfiles/htdocs/testing/test.php on line 49

Propiedades y Métodos Estáticos

Un método o propiedad declarado static puede ser accedido sin instanciar primero la clase; simplemente provee el nombre de la clase, el operador de resolución de ámbito, y el nombre de la propiedad o método.

"Uno de los mayores beneficios de usar propiedades estáticas es que mantienen sus valores almacenados a lo largo de la ejecución del script."

Para demostrar esto, añade una propiedad estática llamada $count y un método estático llamado plusOne() en MyClass. Después inserta un bucle do...while para aumentar el valor de $count mientras el valor sea menor que 10:

1
<?php
2
3
class MyClass
4
{
5
  public $prop1 = "I'm a class property!";
6
7
  public static $count = 0;
8
9
  public function __construct()
10
  {
11
      echo 'The class "', __CLASS__, '" was initiated!<br />';
12
  }
13
14
  public function __destruct()
15
  {
16
      echo 'The class "', __CLASS__, '" was destroyed.<br />';
17
  }
18
19
  public function __toString()
20
  {
21
      echo "Using the toString method: ";
22
      return $this->getProperty();
23
  }
24
25
  public function setProperty($newval)
26
  {
27
      $this->prop1 = $newval;
28
  }
29
30
  private function getProperty()
31
  {
32
      return $this->prop1 . "<br />";
33
  }
34
35
  public static function plusOne()
36
  {
37
      return "The count is " . ++self::$count . ".<br />";
38
  }
39
}
40
41
class MyOtherClass extends MyClass
42
{
43
  public function __construct()
44
  {
45
      parent::__construct();
46
      echo "A new constructor in " . __CLASS__ . ".<br />";
47
  }
48
49
  public function newMethod()
50
  {
51
      echo "From a new method in " . __CLASS__ . ".<br />";
52
  }
53
54
  public function callProtected()
55
  {
56
      return $this->getProperty();
57
  }
58
}
59
60
do
61
{
62
  // Call plusOne without instantiating MyClass

63
  echo MyClass::plusOne();
64
} while ( MyClass::$count < 10 );
65
66
?>

Nota — Cuando se acceden a propiedades estáticas, el símbolo de dolar
($) va después del operador de resolución de ámbito.

Cuando cargas este script en tu navegador, sale lo siguiente:

1
The count is 1.
2
The count is 2.
3
The count is 3.
4
The count is 4.
5
The count is 5.
6
The count is 6.
7
The count is 7.
8
The count is 8.
9
The count is 9.
10
The count is 10.

Comentando con DocBlocks (Bloques de documentación)

"El estilo de comentarios DockBlock es un método
ampliamente aceptado de documentación de clases."

Aunque no es una parte oficial de la POO, el estilo de comentarios DockBlock es un método ampliamente aceptado de documentar clases. A parte de proveer un estándar para
los desarrolladores para escribir código, también ha sido adoptado por muchos de los kits de desarrollo de software (SDKs) más populares como Eclipse y NetBeans, y se utilizará para generar sugerencias de código.

Un DocBlock se define usando un bloque de comentario que empieza con un asterisco adicional:

1
/**

2
 * This is a very basic DocBlock

3
 */

El poder real de los DocBlocks reside en la posibilidad de usar tags(etiquetas), que empiezan con el símbolo (@) inmediatamente seguido por el nombre de la etiqueta y el valor de la etiqueta. Las etiquetas de DocBlock permiten a los desarrolladores a definir autores para el archivo, la licencia para la clase, la información de la propiedad o el método, y otra información útil.

Las etiquetas más comunes se usan como sigue:

  • @author: El autor del elemento actual (como podría ser una clase, archivo, método, o cualquier pedazo de código) se lista usando esta etiqueta Se pueden usar múltiples etiquetas de autor en el mismo DocBlock si hay más de un autor involucrado. El formato del nombre de autor es John Doe <john.doe@email.com>
  • @copyright: Esto detalla el año y nombre del copyright del propietario de los derechos del elemento actual. El formato es 2010 Propietario de los Derechos.
  • @license: Esto enlaza con la licencia del elemento actual. El formato para la información de licencia es
    http://www.example.com/path/to/license.txt Nombre de la licencia.
  • @var: Mantiene el tipo y descripción de una variable o propiedad de clase. El formato es tipo elemento descripción.
  • @param: Esta etiqueta muestra el tipo y descripción de los parámetros de una función o método. El formato es tipo $nombre_del_elemento descripción_del_elemento.
  • @return: El tipo y descripción del valor de retorno de una función o método se detallan en esta etiqueta. El formato es tipo return elemento descripción.

Un ejemplo de clase comentada con DockBlocks tendría este aspecto:

1
<?php
2
3
/**

4
 * A simple class

5
 *

6
 * This is the long description for this class,

7
 * which can span as many lines as needed. It is

8
 * not required, whereas the short description is

9
 * necessary.

10
 *

11
 * It can also span multiple paragraphs if the

12
 * description merits that much verbiage.

13
 *

14
 * @author Jason Lengstorf <jason.lengstorf@ennuidesign.com>

15
 * @copyright 2010 Ennui Design

16
 * @license http://www.php.net/license/3_01.txt PHP License 3.01

17
 */
18
class SimpleClass
19
{
20
  /**

21
   * A public variable

22
   *

23
   * @var string stores data for the class

24
   */
25
  public $foo;
26
27
  /**

28
   * Sets $foo to a new value upon class instantiation

29
   *

30
   * @param string $val a value required for the class

31
   * @return void

32
   */
33
  public function __construct($val)
34
  {
35
      $this->foo = $val;
36
  }
37
38
  /**

39
   * Multiplies two integers

40
   *

41
   * Accepts a pair of integers and returns the

42
   * product of the two.

43
   *

44
   * @param int $bat a number to be multiplied

45
   * @param int $baz a number to be multiplied

46
   * @return int the product of the two parameters

47
   */
48
  public function bar($bat, $baz)
49
  {
50
      return $bat * $baz;
51
  }
52
}
53
54
?>

Una vez analizas la clase anterior, los beneficios de los DocBlock son aparentes: todo está claramente definido de tal forma que el siguiente desarrollador que trate el código nunca tendrá que suponer qué hace un fragmento de código o qué debería contener.

Comparando Código de Orientación a Objetos y Procedural

En realidad no hay una forma correcta e incorrecta de escribir código. Como se ha dicho, esta sección resume un sólido argumento para adoptar una aproximación a la orientación a objetos en el desarrollo de software, especialmente en aplicaciones grandes.

Razón 1: Facilidad de Implementación

"Mientras que puede abrumar al principio, la POO en realidad otorga una aproximación más sencilla para tratar con datos."

Mientras que puede abrumar al principio, la POO en realidad otorga una aproximación más sencilla para tratar con datos. Dado que un objeto puede almacenar datos internamente, las variables no necesitan pasar de función en función para funcionar apropiadamente.

Además, dado que pueden existir simultáneamente múltiples instancias de la misma clase, tratar con grandes conjuntos de datos es infinitamente más fácil. Por ejemplo, imagina que tenemos información de dos personas siendo procesadas en un archivo. Sus nombres, trabajos, y edades.

La Aproximación Procedural

Aquí tenemos la aproximación procedural a nuestro ejemplo:

1
<?php
2
3
function changeJob($person, $newjob)
4
{
5
  $person['job'] = $newjob; // Change the person's job

6
  return $person;
7
}
8
9
function happyBirthday($person)
10
{
11
  ++$person['age']; // Add 1 to the person's age

12
  return $person;
13
}
14
15
$person1 = array(
16
  'name' => 'Tom',
17
  'job' => 'Button-Pusher',
18
  'age' => 34
19
);
20
21
$person2 = array(
22
  'name' => 'John',
23
  'job' => 'Lever-Puller',
24
  'age' => 41
25
);
26
27
// Output the starting values for the people

28
echo "<pre>Person 1: ", print_r($person1, TRUE), "</pre>";
29
echo "<pre>Person 2: ", print_r($person2, TRUE), "</pre>";
30
31
// Tom got a promotion and had a birthday

32
$person1 = changeJob($person1, 'Box-Mover');
33
$person1 = happyBirthday($person1);
34
35
// John just had a birthday

36
$person2 = happyBirthday($person2);
37
38
// Output the new values for the people

39
echo "<pre>Person 1: ", print_r($person1, TRUE), "</pre>";
40
echo "<pre>Person 2: ", print_r($person2, TRUE), "</pre>";
41
42
?>

Cuando lo ejecutamos, el código muestra lo siguiente:

1
Person 1: Array
2
(
3
  [name] => Tom
4
  [job] => Button-Pusher
5
  [age] => 34
6
)
7
Person 2: Array
8
(
9
  [name] => John
10
  [job] => Lever-Puller
11
  [age] => 41
12
)
13
Person 1: Array
14
(
15
  [name] => Tom
16
  [job] => Box-Mover
17
  [age] => 35
18
)
19
Person 2: Array
20
(
21
  [name] => John
22
  [job] => Lever-Puller
23
  [age] => 42
24
)

Mientras que este código no es necesariamente malo, hay un montón de cosas a tener en cuenta mientras se codifica. El array de los atributos de las personas afectadas debe ser pasado y devuelta en cada llamada a función, lo cual deja margen para el error.

Para reformar este ejemplo, sería deseable dejar el mínimo de cosas para el desarrollador como sea posible. Sólo la información absolutamente necesaria para la operación actual debería ser pasada a las funciones.

Aquí es donde la POO se impone y te ayuda a depurar las cosas.

La Aproximación con POO

Aquí está la aproximación con POO a nuestro ejemplo:

1
<?php
2
3
class Person
4
{
5
  private $_name;
6
  private $_job;
7
  private $_age;
8
9
  public function __construct($name, $job, $age)
10
  {
11
      $this->_name = $name;
12
      $this->_job = $job;
13
      $this->_age = $age;
14
  }
15
16
  public function changeJob($newjob)
17
  {
18
      $this->_job = $newjob;
19
  }
20
21
  public function happyBirthday()
22
  {
23
      ++$this->_age;
24
  }
25
}
26
27
// Create two new people

28
$person1 = new Person("Tom", "Button-Pusher", 34);
29
$person2 = new Person("John", "Lever Puller", 41);
30
31
// Output their starting point

32
echo "<pre>Person 1: ", print_r($person1, TRUE), "</pre>";
33
echo "<pre>Person 2: ", print_r($person2, TRUE), "</pre>";
34
35
// Give Tom a promotion and a birthday

36
$person1->changeJob("Box-Mover");
37
$person1->happyBirthday();
38
39
// John just gets a year older

40
$person2->happyBirthday();
41
42
// Output the ending values

43
echo "<pre>Person 1: ", print_r($person1, TRUE), "</pre>";
44
echo "<pre>Person 2: ", print_r($person2, TRUE), "</pre>";
45
46
?>

Esto muestra la siguiente salida en el navegador:

1
Person 1: Person Object
2
(
3
  [_name:private] => Tom
4
  [_job:private] => Button-Pusher
5
  [_age:private] => 34
6
)
7
8
Person 2: Person Object
9
(
10
  [_name:private] => John
11
  [_job:private] => Lever Puller
12
  [_age:private] => 41
13
)
14
15
Person 1: Person Object
16
(
17
  [_name:private] => Tom
18
  [_job:private] => Box-Mover
19
  [_age:private] => 35
20
)
21
22
Person 2: Person Object
23
(
24
  [_name:private] => John
25
  [_job:private] => Lever Puller
26
  [_age:private] => 42
27
)

Hay una poco más de organización involucrada de cara a la aproximación orientada a objetos, pero tras definir la clase, crear y modificar personas es pan comido, la información de una persona no necesita ser pasada o devuelta desde los métodos, y sólo la información absolutamente esencial se pasa a cada método.

"La POO reducirá significativamente tu carga de trabajo si se implementa apropiadamente"

A pequeña escala, esta diferencia puede no parecer gran cosa, pero al crecer tus aplicaciones en tamaño, la POO reducirá significativamente tu carga de trabajo si se implementa apropiadamente.

Consejo — No todo necesita ser orientado a objetos. Una función rápida que maneja algo pequeño en un lugar dentro de la aplicación no necesita necesariamente estar envuelto en una clase. Usa tu mejor juicio al decidir entre aproximación con orientación a objetos y procedural.

Razón 2: Mejor Organización

Otro beneficio de la POO es cómo de bien  se presta a ser fácilmente empaquetado y catalogado. Cada clase puede ser contenida generalmente dentro de su propio archivo por separado, y si se usa una nomenclatura uniforme, acceder a las clases es extremadamente simple.

Asume que tieness una apliación con 150 clases que son llamadas dinámicamente a través de un archivo controlador en la raíz del sistema de archivos de tu aplicación. Todas las 150 clases siguen la nomenclatura class.classname.inc.php y reside en la carpeta inc de tu aplicación.

El controlador puede implementar la función de PHP _autoload() para acceder dinámicamente sólo a las clases que necesita llamar, en lugar de incluir todas las 150 clases en el archivo del controlador por si acaso o dar con alguna forma inteligente de incluir los archivos en tu propio código:

1
<?php
2
  function __autoload($class_name)
3
  {
4
      include_once 'inc/class.' . $class_name . '.inc.php';
5
  }
6
?>

Teniendo cada clase en un archivo separado también hace el código más portable y más fácil de reusar en aplicaciones nuevas sin un montón de copia y pega.

Razón 3: Facilidad de Mantenimiento

Debido a la naturaleza más compacta de la POO cuando se usa correctamente, los cambios en el código son normalmente más fáciles de localizar y hacer que en un largo código espagueti de la implementación procedural.

Si un array particular de información añade un nuevo atributo, una parte de código de un software procedural podría requerir (en el peor de los escenarios) que el nuevo atributo deba ser añadido a cada función que use el array.

En una aplicación de POO podría ser potencialmente actualizada facilmente añadiendo una nueva propiedad y después añadiendo métodos que manejen dicha propiedad.

Muchos de los beneficios cubiertos en esta sección son fruto de la POO combinados con prácticas de programación NTR. Definitivamente es posible crear código procedural fácil de mantener que no cause pesadillas, y es igualmente posible crear un horrible código orientado a objetos. [Pro PHP y jQuery] intentarán demostrar una combinación de buenos hábitos de codificación junto a la POO para generar código que sea fácil de leer y mantener.

Resumen

En este punto, deberías sentirte cómodo con el estilo de programación orientado a objetos. Aprender POO es una gran manera de llevar tu programación al siguiente nivel. Cuando se implementa apropiadamente, la POO te ayudará a producir código fácil de leer, mantener y portable que te ahorrará (y a los desarrolladores con quien trabajes) horas de trabajo extra. ¿Estás atascado en algo que no se haya cubierto en este artículo? ¿Ya utilizas POO y tienes algún consejo para principiantes? ¡Compártelos en los comentarios!

Nota del Autor — Este tutorial es un fragmento de Pro PHP y jQuery (Apress, 2010).