Programación Orientada a Objetos en
PHP
Clase constructor
Los
constructores son funciones, o métodos, que se encargan de realizar las tareas
de inicialización de los objetos al ser instanciados. Es decir, cuando se crean
los objetos a partir de las clases, se llama a un constructor que se encarga de
inicializar los atributos del objeto y realizar cualquier otra tarea de
inicialización que sea necesaria.
No es obligatorio disponer de un constructor, pero
resultan muy útiles y su uso es muy habitual. En el ejemplo de la caja, que
comentábamos en el anterior artículo de programación orientada a objetos en PHP,
lo normal sería inicializar las variables como color o las relacionadas con las
dimensiones y, además, indicar que el contenido de la caja está vacío. Si no
hay un constructor no se inicializan ninguno de los atributos de los objetos.
El constructor se define dentro de la propia clase,
como si fuera otro método. El único detalle es que el constructor debe tener el
mismo nombre que la clase. Atentos a PHP, que diferencia entre mayúsculas y
minúsculas.
Para la clase Caja definida anteriormente, se
podría declarar este constructor:
function
Caja($alto=1,$ancho=1,$largo=1,$color="negro"){
$this->alto=$alto;
$this->ancho=$ancho;
$this->largo=$largo;
$this->color=$color;
$this->contenido="";
}
En este constructor recibimos por parámetro todos
los atributos que hay que definir en una caja.
Es muy útil definir unos valores por defecto en los
parámetros que recibe el constructor, igualando el parámetro a un valor dentro
de la declaración de parámetros de la función constructora, pues así, aunque se
llame al constructor sin proporcionar parámetros, se inicializará con los
valores por defecto que se hayan definido.
Es importante señalar que en los constructores no
se tienen por qué recibir todos los valores para inicializar el objeto. Hay
algunos valores que pueden inicializarse a vacío o a cualquier otro valor fijo,
como en este caso el contenido de la caja, que inicialmente hemos supuesto que
estará vacía.
void __construct ([ mixed $args [, $... ]] )
Por motivos de
compatibilidad, si PHP 5 no puede encontrar una función __construct() para una
determinada clase y la clase no heredó uno de una clase padre, buscará el viejo
estilo de la función constructora, mediante el nombre de la clase.
Efectivamente, esto significa que en el único caso en el que se tendría
compatibilidad es si la clase tiene un método llamado __construct() que fuese
utilizado para diferentes propósitos.
A diferencia con
otros métodos, PHP no generará un mensaje de error a nivel de E_STRICT cuando
__construct() es sobrescrito con diferentes parámetros que los métodos padre
__construct() tienen.
A partir de PHP
5.3.3, los métodos con el mismo nombre que el último elemento de una clase en
un nombre de espacios no serán más tratados como un constructor. Este cambio no
afecta a clases sin espacio de nombres.
PHP 5 permite a los
desarrolladores declarar métodos constructores para las clases. Aquellas que
tengan un método constructor lo invocarán en cada nuevo objeto creado, lo que
lo hace idóneo para cualquier inicialización que el objeto pueda necesitar
antes de ser usado.
Nota: Constructores parent no son llamados
implícitamente si la clase child define un constructor. Para ejecutar un
constructor parent, se requiere invocar a parent::__construct() desde el
constructor child. Si el child no define un constructor, entonces se puede
heredar de la clase padre como un método de clase normal (si no fue declarada
como privada).
Herencia
Qué
es la Herencia en PHP y como implementarla
Como su nombre indica el concepto de herencia se aplica
cuando creamos una clase, que va a heredar los métodos y atributos de una ya
definida, entonces la clase que hemos creado es una subclase.
Para que una clase sea subclase de otra ya creada
deberemos usar la palabra reservada extendí en el siguiente código podremos ver
como creamos una clase llamada SubClaseA que heredará los métodos y atributos
de una clase definida con anterioridad llamada ClaseA.
Subclase
de la clase A
class SubClaseA extendí ClaseA {
var $atributo2;
function operacion2()
{
}
}
Tenemos la clase ClaseA que es definida de la
siguiente forma:
Class
ClaseA {
var
$atributo1;
function
operacion1()
{
}
}
Si creamos un objeto de la clase SubClaseA
este heredará todos los métodos de la clase ClaseA, por lo tanto el siguiente
código es válido:
$x = new SubClaseA();
$x->operacion1();
$x->atributo1
= 100;
$x->operacion2();
$x->atributo2
= 200;
Como podemos observar aunque declaremos un
objeto de la clase SubClaseA, al ser una clase extendida de ClaseA podemos
hacer uso de todos los métodos y atributos definidos en ClaseA como si
estuvieran contenidos en SubClaseA.
Debemos tener en cuenta que la herencia solo
trabaja en una dirección, la subclase o clase hija hereda las características
de su clase padre o superclase, pero la clase padre no posee las
características de la hija. Para el caso anterior ClaseA no tendría atributo2
ni metodo2();
Encapsulamiento
Este lenguaje de programación no es muy estricto, en POO
es muy bueno tener en cuenta la ocultación de información (encapsulamiento).
Muchos dicen que PHP rompe el encapsulamiento debido a que nos permite acceder
a cualquier atributo de una clase directamente, pero en si hay una forma de
hacer que no se pueda, para generar el encapsulamiento. Para ello tenemos el
concepto de visibilidad en pH.
El concepto de visibilidad nos dice que hay tres palabras
claves/reservadas: public, protected y private que anteponiéndolas a cualquier
método o atributo/propiedad se podrán modificar o implementar su visibilidad,
haciendo posible el encapsulamiento.
Public: Se podrá acceder a ella de cualquier forma,
directamente o por métodos. Ejemplo:
class Persona{
public $nombre;
public
$apellido;
public $edad;
// Es public por lo que se accede desde cualquier parte
public function
__construct($nom, $ape, $e){
$this->nombre = $nom;
$this->apellido= $ape;
$this->edad = $e;
}
public function imprimir(){
return $this->edad;
}
}
$persona = new Persona('Pepito','Perez',24);
echo
$persona->edad;
echo
$persona->imprimir();
Como vemos es la misma clase persona, creamos el objeto y
hacemos hecho a la edad directamente, lo que nos imprimirá un 24, después por
medio del método imprimir() también nos pondrá en pantalla el mismo dato, la
edad.
Protected: Si cambiamos el public por el protected, y
dejamos lo mismo nos saldrá un fatal error, ya que con protected no nos dejara
acceder a la propiedad a menos que sea por métodos de la misma clase, herencia
o con el parent.
class Persona{
public $nombre;
public
$apellido;
protected
$edad;
public function
__construct($nom, $ape, $e){
$this->nombre = $nom;
$this->apellido= $ape;
$this->edad = $e;
}
public function imprimir(){
return $this->edad;
}
}
$persona = new
Persona('Pepito','Perez',24);
echo $persona->edad;
echo $persona->imprimir();
Si comentamos la línea donde imprimimos directamente la
propiedad, nos imprimirá el resultado del método imprimir().
//echo $persona->edad;
echo $persona->imprimir();
Private: Al poner la propiedad edad en private solo nos
dejara acceder desde la misma clase, entonces si hacemos el ejercicio anterior
class Persona{
public $nombre;
public
$apellido;
private $edad;
public function
__construct($nom, $ape, $e){
$this->nombre = $nom;
$this->apellido= $ape;
$this->edad = $e;
}
public function imprimir(){
return $this->edad;
}
}
class trabajo extendí Persona{
public
$trabajos;
public
$pruebas;
public function
trabajar($Job){
$this->taboos =
$job;
}
public function imprimir(){
retorno 'Mi nombre es '.$this->nombre.'
'.$this->apellido.' y tengo '.
$this->edad.'
Años y trabajo en '.$this->trabajos;
}
}
$persona = new Persona('Pepito','Perez',24);
echo $persona->imprimir();
Si corremos pH con el siguiente código, no nos dejara
acceder a la propiedad edad de la clase Persona desde trabajo porque es
privada, si fuera protected si nos dejaría pero solo por métodos o parent.
Polimorfismo
Qué es el polimorfismo y
como implementarlo
Cualquier lenguaje de programación orientado a objetos
debe soportar el polimorfismo, esto significa que clases diferentes tendrán un
comportamiento distinto para la misma operación. Esto lo veremos más claro con
el siguiente ejemplo.
Supongamos que tenemos dos clases distintas coche y
ciclomotor. Ambas tienen sus propios métodos de movimiento, éstos tienen
diferentes comportamientos, pero su nombre es el mismo.
class coche {
function
avanza() {
}
function
para() {
}
function
girar derecha() {
}
}
Clases ciclomotor {
función avanza() {
}
function para() {
}
function girar_derecha() {
}
}
Como podemos observar,
ambas clases tienen los mismos métodos, supongamos ahora que tenemos otra clase
que controla el movimiento de todos los vehículos, es aquí donde entra en juego
el polimorfismo, que dependiendo del objeto que tratemos actuará de una forma u
otra el método al que llamamos.
clases movimiento {
function mover_adelante($obj) {
$obj->avanza();
}
}
Supongamos que queremos
mover cualquier vehículo hacia adelante entonces haríamos:
$obj_coche = new
coche();
$obj_ciclomotor = new ciclomotor(); $obj_movimiento = new
movimiento();
//con esta sentencia el coche avanzaría hacia adelante.
$obj_movimiento-> mover_adelante($obj_coche);
//con esta sentencia el ciclomotor avanzaría hacia
adelante.
$obj_movimiento-> mover_adelante($obj_ciclomotor);
Como podemos ver el mismo método del objeto movimiento
actúa de dos formas diferentes dependiendo del objeto que le pasamos como
parámetro.