You are on page 1of 14

La programación orientada a objetos (Object Oriented Programming

OOP) es un modelo de lenguaje de programación organizado


por objetos constituidos por datos y funciones, entre los cuales se
pueden crear relaciones como herencia, cohesión, abstracción,
polimorfismo o encapsulamiento. Esto permite que haya una gran
flexibilidad y se puedan crear objetos que pueden heredarse y
transmitirse sin necesidad de ser modificados continuamente.

Indice de contenido

1. Clases y Objetos 6. Propiedades y métod

2. Interacciones entre objetos 7. Traits

3. Public, protected y private 8. Type hinting

4. Paamayim Nekudotayim 9. Métodos mágicos

5. Constantes

1. Clases y objetos

Una clase define los datos y la lógica de un objeto. La lógica se divide


en funciones (métodos) y variables (propiedades).

Para definir una propiedad:

class Coche {
public $color;
}
Para definir un método:

class Coche {
public function getColor()
{
// Contenido de la función
}
}
Para crear un objeto hay que instanciar una clase:

class Coche {
// Contenido de la clase
}

$miCoche = new Coche(); // Objeto


La clase es como una plantilla que define características y funciones.
El objeto agrupa los datos de la clase y permite utilizarlos desde una
unidad.

Podemos definir las características de un coche de la siguiente forma:

class Coche {
public $color;
public $potencia;
public $marca;
}

$miCoche = new Coche();


$miCoche->color = 'rojo';
$miCoche->potencia = 120;
$miCoche->marca = 'audi';
De momento sólo hemos definido propiedades del objeto. Si queremos
mostrar alguna característica ahora:

//...
echo 'Color del coche: ' . $miCoche->color; // Muestra Color del
coche: rojo
Ahora vamos a definir un método que devuelve una propiedad:

class Coche {
//...

public function getColor()


{
return $this->color;
}
}
//...
El método getColor() nos permite devolver el color del objeto
instanciado. La variable $this se puede utilizar en cualquier método, y
hace referencia al objeto que hemos instanciado, en este caso
$miCoche. Podemos obtener el mismo resultado que antes para mostrar
el color del coche pero ahora utilizando un método para mostrar
la propiedad color:

//...
echo 'Color del coche: ' . $miCoche->getColor();
Las propiedades pueden tener valores por defecto:

class Coche {
public $color = 'rojo';
//...
}
De esta forma siempre que se instancie un objeto de la clase Coche,
éste será de color rojo a no ser que se modifique después. Ahora
creamos también el objeto $otroCoche y le ponemos otras
características:

class Coche {

public $color = 'rojo';


public $potencia;
public $marca;

public function getColor()


{
return $this->color;
}
}

$miCoche = new Coche();


$miCoche->color = 'verde';
$miCoche->potencia = 120;
$miCoche->marca = 'audi';

$otroCoche = new Coche();


$otroCoche->color = 'azul';
$otroCoche->potencia = 100;
$otroCoche->marca = 'bmw';
Creamos ahora dos "getters" para la potencia y la marca:

class Coche {

public $color = 'rojo';


public $potencia;
public $marca;

public function getColor()


{
return $this->color;
}
public function getPotencia()
{
return $this->potencia;
}
public function getMarca()
{
return $this->marca;
}
}
Y creamos una función (fuera de la clase) que devuelve las
caracteristicas totales de un objeto coche:

function printCaracteristicas($cocheConcreto)
{
echo 'Color: '. $cocheConcreto->getColor();
echo "\n";
echo 'Potencia: '. $cocheConcreto->getPotencia();
echo "\n";
echo 'Marca: '. $cocheConcreto->getMarca();
}

$miCoche = new Coche();


$miCoche->color = 'verde';
$miCoche->potencia = 120;
$miCoche->marca = 'audi';

$otroCoche = new Coche();


$otroCoche->color = 'azul';
$otroCoche->potencia = 100;
$otroCoche->marca = 'bmw';

printCaracteristicas($miCoche);
echo "\n";
printCaracteristicas($otroCoche);
La función printCaracteristicas() requiere un
argumento, $cocheConcreto, que es una instancia de la clase Coche que
mostrará las características del propio objeto.

2. Interacciones entre objetos

Supongamos ahora que queremos comparar y mostrar qué coche es


más rápido dependiendo de su potencia. Añadimos un nuevo método a
la clase Coche:

class Coche {
//...

public function elCocheElegidoEsMasRapido($cocheElegido)


{
return $cocheElegido->potencia > $this->potencia;
}
}
//...
Tenemos dos objetos $miCoche y $otroCoche. La condición que
mostrará que coche es más rápido:

//...
if ($miCoche->elCocheElegidoEsMasRapido($otroCoche)) {
echo 'El ' . $otroCoche->marca . ' es más rápido';
} else {
echo 'El ' . $miCoche->marca . ' es más rápido';
}

$miCoche->elCocheElegidoEsMasRapido($otroCoche);
// En este caso el Audi ($miCoche) es más rápido que el BMW
($otroCoche)
Podemos comparar la igualdad entre dos objetos, con los operadores
de comparación (==) y de identidad (===):
 Dos objetos serán iguales si tienen los mismos atributos y
valores, siendo instancias de la misma clase. En ejemplo anterior,
los atributos de los dos objetos deberían tener los mismos
valores, por ejemplo: verde, 100, audi.

 Dos objetos serán idénticos si además hacen referencia a


la misma instancia de la misma clase.

3. Public, protected y private

Anteriormente hemos definido todas las propiedades y métodos


como public . Esto significa que pueden ser accedidos y alterados desde
cualquier parte fuera de la clase. En el ejemplo anterior hemos podido
definir $miCoche->potencia sin ningún problema, y podríamos aplicarle
cualquier valor (un número, un string...).

Cuando se define una propiedad como private , se indica que ésta no


puede verse o modificarse a no ser que sea desde la propia clase. Si
utilizamos $miCoche->potencia para verla o definirla, nos dará error. Si
queremos definirla, se utiliza un setter , un método publicpara definir
una propiedad private:

class Coche {

//...

public function setPotencia($potencia)


{
$this->potencia = $potencia;
}
//...
}
Así podemos definir desde fuera de la clase el valor de la propiedad
potencia:

//...
$miCoche->setPotencia(120);
También deberemos de tener un getter para poder acceder al valor que
tiene establecido la propiedad:

//...
public function getPotencia()
{
return $this->potencia;
}
//...
Con esto conseguimos, entre otras cosas, que puedan definirse valores
limitados. En este caso, la propiedad $potencia queremos que pueda
ser sólo un número. Para ello, modificamos el setter anterior:

//...
public function setPotencia($potencia)
{
if(!is_numeric($potencia)){
throw new \Exception('Potencia no válida: '.
$potencia);
}
// Si $potencia no es un número, devolverá un error
$this->potencia = $potencia;
}
//...
Para entender las propiedades y métodos bajo la palabra reservada
protected, vamos a explicar primero las relaciones entre clases
mediante la herencia.

Una clase puede heredar métodos y propiedades de otra clase, y éstos


se pueden sobreescribir empleando el mismo nombre que en la clase
madre. Las clases sólo pueden heredar de una única clase (no es
posible herencia múltiple), pero sí que pueden heredarse unas a otras
(sí es posible herencia multinivel). La herencia se realiza mediante la
palabra extends .

Supongamos ahora la clase Coche con 3 tipos de


propiedades y CocheDeLujo como heredera:

class Coche {
private $color = 'red';
protected $potencia = 120;
public $marca = 'audi';
}
class CocheDeLujo extends Coche {

// La función displayColor devolverá un error porque es private


public function displayColor()
{
return $this->color;
}
// La función displayPotencia devolverá 120, ya que hereda el
valor
public function displayPotencia()
{
return $this->potencia;
}
// La función displayMarca devolverá audi, ya que también
hereda el valor
public function displayMarca()
{
return $this->marca;
}
}
La clase CocheDeLujo podrá emplear y modificar las propiedades y
métodos protected y public de la madre, pero no las private. Además,
podrá añadir cualquier propiedad o métodos complementarios.
Creamos varios métodos en la clase Coche,
incluído printCaracteristicas():

class Coche {
protected $color;
public function setColor($color)
{
$this->color = $color;
}
public function getColor()
{
return $this->color;
}
public function printCaracteristicas()
{
echo 'Color: '. $this->getColor;
}
}
Añadimos otros métodos en CocheDeLujo, y modificamos la herencia
de printCaracteristicas():

class CocheDeLujo extends Coche {


protected $extras;
public function setExtras($extras)
{
$this->extras = $extras;
}
public function getExtras()
{
return $this->extras;
}
public function printCaracteristicas()
{
echo 'Color: '. $this->color;
echo '<hr/>';
echo 'Extras: ' . $this->extras;
}
}

$miCoche = new CocheDeLujo();


$miCoche->setColor('negro');
$miCoche->setExtras('TV');

$miCoche->printCaracteristicas(); // Devuelve Color : negro Extras:


TV
El objeto $miCoche, que es una instancia de la clase CocheDeLujo,
puede determinar la nueva propiedad $extras además de las anteriores.
El método que se ha heredado se ha modificado para añadir la nueva
característica.

Accesos que permiten las palabras reservadas public, protected y


private en métodos y propiedades:

Private:

 Desde la misma clase que declara

Protected:

 Desde la misma clase que declara

 Desde las clases que heredan esta clase

Public:

 Desde la misma clase que declara

 Desde las clases que heredan esta clase

 Desde cualquier elemento fuera de la clase

Es posible impedir que un método pueda sobreescribirse mediante


la palabra final:

class Coche {
final public function getColor()
{
echo "Rojo";
}
}
class CocheDeLujo extends Coche {
public function getColor()
{
echo "Azul";
}
} // Dará un error fatal, getColor() no puede sobreescribirse
También se puede impedir que la clase pueda heredarse mediante la
misma palabra:

final class Coche {


public function getColor()
{
echo "Rojo";
}
}
class CocheDeLujo extends Coche {
// Error fatal, clase no heredable
}

4. Paamayim Nekudotayim

Se le llama Paamayim Nekudotayim, operador de resolución de ámbito


o doble dos puntos "::" (double colon ) al operador que permite acceder
a constantes y a métodos estáticos además de poder sobreescribir
propiedades o métodos de una clase. En los dos siguientes apartados
se explican las constantes y los métodos estáticos.

5. Constantes

Las constantes son valores invariables. Se definen mediante la


palabra const y se obtienen utilizando el operador double colon:
_$objeto::CONSTANTE _o NombreClase::CONSTANTE. No van precedidas
del símbolo $ y se escriben en mayúscula:

class Coche {
const RUEDAS = 4;
}
// Obtener el valor mediante el nombre de la clase:
echo Coche::RUEDAS . "\n";
// Obtener el valor mediante el objeto:
$miCoche = new Coche();
echo $miCoche::RUEDAS . "\n";

6. Propiedades y métodos estáticos

Las propiedades y métodos estáticos permiten que sean accesibles


sin la necesidad de instanciar la clase. Es importante saber que no se
puede acceder a una propiedad static con un objeto instanciado,
aunque sí a un método static.

No es posible usar la pseudo-variable $this, ya que los métodos


estáticos pueden ejecutarse sin tener una instancia del objeto,
y $thishace referencia al objeto creado.

class Coche {
public static $color = 'rojo';

public function mostrarColor()


{
return self::$color;
}
}
print Coche::$color . "\n"; // Muestra "rojo"

// Creando el objeto miCoche:


$miCoche = new Coche();
print $miCoche->mostrarColor() . "\n"; // Muestra "rojo"
print $miCoche->color . "\n"; // Error, propiedad color no definida
print $miCoche::$color . "\n"; // Muestra "rojo"
En este ejemplo hemos visto que no se puede obtener
la propiedad _$color _desde la instancia del objeto. En el siguiente
ejemplo se puede obtener un método instanciando la clase o no:

class Coche {
public static function mostrarColor()
{
echo 'Rojo';
}
}
Coche::mostrarColor(); // Muestra Rojo
$miCoche = new Coche;
$miCoche->mostrarColor(); // Muestra Rojo

7. Traits

Los traits son como clases que agrupan funcionalidades diseñadas para
ser reutilizadas en otras clases y así evitar las limitaciones de
la herencia simple. A diferencia de las clases, no se pueden
instanciar, tan sólo permiten utilizar sus funciones específicas en otras
clases. Los traits permiten relaciones horizontales entre clases evitando
así la verticalidad.

En el siguiente ejemplo se utiliza un trait para mostrar el modelo de


coche. En la clase Ventas se incluye use Modelo, este trait tiene una
función getModelo() que presupone que en la clase donde se vaya a
utilizar existe un método getMarca() de la clase Coche. Los métodos de
la clase Ventas sobreescriben los métodos del trait, y éstos a su vez
sobreescriben la clase Coche:

class Coche {
public function getMarca() {
echo 'Renault ';
}
}
trait Modelo {
public function getModelo() {
parent::getMarca();
echo 'Clio';
}
}
class Ventas extends Coche {
use Modelo;
}

$o = new Ventas();
$o->getMarca(); // Podemos obtener este método de la clase Coche
$o->getModelo(); // Podemos obtener este método del trait Modelo
Se pueden emplear múltiples traits añadiéndolos a la clase:

class Ventas extends Coche {


use Model, Serie, Versión;
//...
}
O incluso emplear múltiples traits en otro trait para luego usarlo en
la clase:

trait Coche {
public function getMarca() {
echo 'Renault ';
}
}
trait Modelo {
public function getModelo() {
echo 'Clio';
}
}
trait CocheModelo {
use Coche, Modelo;
}

class Venta {
use CocheModelo;
}

$o = new Venta();
$o->getMarca();
$o->getModelo();
Los traits también pueden incluir propiedades y métodos estáticos.

8. Type hinting

El Type hinting, o la implicación de tipos, permite determinar el tipo


de parámetro que un método va a
devolver: objeto, array, interfaz o callable. No añade ningún tipo de
funcionalidad, pero es muy útil por ejemplo para saber si cometes algún
error al añadir argumentos con valores incorrectos.

En el siguiente ejemplo al argumento de la


función listadoCochesEnVenta(Venta $venta) se le exige que sea una
instancia de la clase Venta. Si se pasara cualquier otro argumento, daría
error:
class Venta {
public $coche = 'Audi';
}

class Coche {
public function listadoCochesEnVenta(Venta $venta)
{
echo $venta->coche;
}
}
$venta = new Venta;
$coche = new Coche;
$coche->listadoCochesEnVenta($venta); // Devuelve Audi
Si se pusiera, por ejemplo $coche->listadoCochesEnVenta('Audi') daría
error, ya que no es una clase instanciada.

En el siguiente ejemplo, vamos a exigir un array:

class Coche {
public function listadoCochesEnVenta(Array $listado)
{
foreach ($listado as $coche){
echo $coche . "\n";
}
}
}
$listaCoches = ['Audi', 'BMW'];

$coche = new Coche;


$coche->listadoCochesEnVenta($listaCoches); // Devuelve el listado
Audi BMW
Si el argumento de listadoCochesEnVenta() no fuera un array, también
daría error

9. Métodos mágicos

Los métodos mágicos permiten reaccionar a eventos que le puedan


ocurrir a un objeto instanciado. Se inician con una doble barra baja, y
son: __construct(), __destruct(), call(), callStatic(), __get(), __set(), __i
sset(), __unset(), sleep(), wakeup(), __toString(), invoke(), set_state(),
clone() y debugInfo(). Tan se introducen algunos de ellos:

El más utilizado es el constructor __construct(), que se ejecuta cuando


el objeto se crea, pudiendo
inyectar parámetros y dependeciasrequeridos para crear el objeto.

class Coche {
public $color;

public function __construct($color)


{
$this->color = $color;
}
}

$miCoche = new Coche('Rojo');


echo $miCoche->color; // Devuelve Rojo
Los constructores también se heredan. Si una clase hija define un
constructor propio, para heredar el de la madre es necesario indicarlo
con _parent::__construct()_:

class Coche {
public $color;

public function __construct($color)


{
$this->color = $color;
}
}
class CocheDeLujo extends Coche {
public $extras;

public function __construct($color, $extras)


{
parent::__construct($color);
$this->extras = $extras;
}
}

$miCoche = new CocheDeLujo('Rojo', 'TV');


echo $miCoche->color; // Devuelve Rojo
echo $miCoche->extras; // Devuelve TV
El método __destruct() hace lo contrario, se ejecuta cuando un objeto
se destruye, aunque apenas se utiliza.

Los métodos mágicos __get() y __set() actúan


como getters y setters para propiedades que no tienen visibilidad
public.

El método __isset() actúa como la función isset() normal, como


cuando se trabaja con arrays o variables. Este método mágico
permite comprobar la existencia de una propiedad no pública. El
método __unset() también actúa como la función unset()** normal
pero para propiedades no públicas.

El método mágico __toString() permite devolver el objeto en forma


de string:

class Post {
public $title;
public function setTitle($title)
{
$this->title = $title;
}
public function __toString()
{
return $this->title;
}
}

$post = new Post;


$post->setTitle('Este es mi primer artículo');
echo $post; // Devuelve Este es mi primer artículo

You might also like