Clases y Objetos

Anuncio
Clases y Objetos
Introducción
A partir de PHP 5, el modelo de objetos ha sido reescrito para permitir un mejor rendimiento y con
más características. Este fue un cambio importante a partir de PHP 4. PHP 5 tiene un modelo de
objetos completo.
Entre las características de PHP 5 están la inclusión de la visibilidad, las clases abstractas y clases y
métodos finales, métodos mágicos adicionales, interfaces,clonación y tipos sugeridos.
PHP trata los objetos de la misma manera como referencias o manejadores, lo que significa que cada
variable contiene una referencia de objeto en lugar de una copia de todo el objeto. Ver objetos y
referencias
Sugerencia
Vea también Guia de Entorno de Usuario para Nombres.
Lo básico
class
La definición básica de clases comienza con la palabra clave class, seguido por un nombre de clase,
continuado por un par de llaves que encierran las definiciones de las propiedades y métodos
pertenecientes a la clase.
El nombre de clase puede ser cualquier etiqueta válida que no sea una palabra reservada de PHP. Un
nombre válido de clase comienza con una letra o un guión bajo, seguido de la cantidad de letras,
números o guiones bajos que sea. Como una expresión regular, se expresaría de la siguiente
forma: [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*.
Una clase puede tener sus propias constantes, variables (llamadas "propiedades"), y funciones
(llamadas "métodos").
Ejemplo #1 Definición simple de una clase
<?php
class SimpleClass
{
// Declaración de la propiedad
public $var = 'a default value';
// Declaración del método
public function displayVar() {
echo $this->var;
}
}
?>
La pseudo-variable $this está disponible cuando un método es invocado dentro del contexto de un
objeto. $this es una referencia del objeto que invoca (usualmente el objeto al que el método
pertenece, pero posiblemente sea otro objeto, si el método es llamado estáticamente desde el
contexto de un objeto secundario).
Ejemplo #2 Algunos ejemplo de la pseudo-variable $this
<?php
class A
{
function foo()
{
if (isset($this)) {
echo '$this está definida (';
echo get_class($this);
echo ")\n";
} else {
echo "\$this no está definida.\n";
}
}
}
class B
{
function bar()
{
// Nota: la siguiente línea arrojará un Warning si E_STRICT está habilitada.
A::foo();
}
}
$a = new A();
$a->foo();
// Nota: la siguiente línea arrojará un Warning si E_STRICT está habilitada.
A::foo();
$b = new B();
$b->bar();
// Nota: la siguiente línea arrojará un Warning si E_STRICT está habilitada.
B::bar();
?>
El resultado del ejemplo sería:
$this
$this
$this
$this
está definida (A)
no está definida.
está definida (B)
no está definida.
new
Para crear una instancia de una clase, la palabra clave new debe ser usada. Un objeto siempre se
creará a menos que el objeto tenga un constructor que arroje una excepción en caso de error. Las
clases deberían ser definidas antes de la instanciación (y en algunos casos esto es un requerimiento).
Si un string que contiene el nombre de una clase se usa con new, una nueva instancia de esa clase
será creada. Si la clase está en un espacio de nombres, su nombre completo debe ser usado cuando
se hace esto.
Ejemplo #3 Creación de una instancia
<?php
$instance = new SimpleClass();
// Esto también se puede hacer con variables:
$className = 'Foo';
$instance = new $className(); // Foo()
?>
En el contexto de una clase, es posible crear un nuevo objeto con new self y new parent.
Cuando se asigna una instancia de una clase ya creada a una nueva variable, ésta última accederá a
la misma instancia como al objeto que le fue asignado. Esta conducta es la misma cuando se pasan
instancias a una función. Una copia de un objeto ya creado se puede lograr a través de
la clonación de la misma.
Ejemplo #4 Asignación de objetos
<?php
$instance = new SimpleClass();
$assigned
$reference
= $instance;
=& $instance;
$instance->var = '$assigned tendrá este valor';
$instance = null; // $instance y $reference se transforman en null
var_dump($instance);
var_dump($reference);
var_dump($assigned);
?>
El resultado del ejemplo sería:
NULL
NULL
object(SimpleClass)#1 (1) {
["var"]=>
string(30) "$assigned tendrá este valor"
}
PHP 5.3.0 introdujo un par de nuevas maneras para crear instancias de un objeto:
Ejemplo #5 Creando nuevos objetos
<?php
class Test
{
static public function getNew()
{
return new static;
}
}
class Child extends Test
{}
$obj1 = new Test();
$obj2 = new $obj1;
var_dump($obj1 !== $obj2);
$obj3 = Test::getNew();
var_dump($obj3 instanceof Test);
$obj4 = Child::getNew();
var_dump($obj4 instanceof Child);
?>
El resultado del ejemplo sería:
bool(true)
bool(true)
bool(true)
extends
Una clase puede heredar los métodos y propiedades de otra clase al utilizar la palabra
clave extends en la declaración de la clase. No es posible extender múltiples clases; una clase sólo
puede heredar de una clase base.
Los métodos y propiedades heredados pueden ser sobrescritos con la redeclaración de éstos
utilizando el mismo nombre que en la clase parent. Sin embargo, si la clase parent definió un método
como final, éste no podrá ser sobrescrito. Es posible acceder a los métodos sobrescritos o
propiedades estáticas referenciándolos con parent::.
Cuando se sobrescriben métodos, la cantidad y disposición de los parámetros debería ser la misma o
PHP generará un error a nivel de E_STRICT. Esto no se aplica a los constructores, que permiten la
sobrescritura con diferentes parámetros.
Ejemplo #6 Herencia simple de clases
<?php
class ExtendClass extends SimpleClass
{
// Redefinición del método parent
function displayVar()
{
echo "Clase extendida\n";
parent::displayVar();
}
}
$extended = new ExtendClass();
$extended->displayVar();
?>
El resultado del ejemplo sería:
Clase extendida
un valor por defecto
Propiedades
Las variables pertenecientes a clases se llaman "propiedades". También se les puede llamar usando
otros términos como "atributos" o "campos", pero para los propósitos de esta referencia se va a
utilizar "propiedades". Éstas se definen usando una de las palabras clave public, protected,
o private, seguido de una declaración normal de variable. Esta declaración puede incluir una
inicialización, pero esta inicialización debe ser un valor constante, es decir, debe poder ser evaluada
en tiempo de compilación y no debe depender de información en tiempo de ejecución para ser
evaluada.
Véase Visibilidad para más información sobre el significado de public, protected, y private.
Nota:
Con el fin de mantener la compatibilidad con PHP 4, PHP 5 continuará aceptando el uso de la palabra
clave var en la declaración de propiedades en lugar de (o además de) public, protected, o private.
Sin embargo, var ya no es necesaria. Entre las versiones 5.0 y 5.1.3 de PHP, el uso de var fue
considerado obsoleto y emitía una advertencia de nivel E_STRICT, pero a partir de PHP 5.1.3 ya no
está obsoleta y no emitirá la advertencia.
Si se declara una propiedad utilizando var en lugar de public, protected, o private, PHP tratará
dicha propiedad como si hubiera sido definida comopublic.
Dentro de los métodos de clase, las propiedades, constantes y métodos pueden ser accedidos a
través de $this->propiedad (donde propiedad es el nombre de la propiedad; véanse también
los nombres de propiedades variables) a menos que el acceso sea a una propiedad estática dentro
del contexto de un método de clase estático, en cuyo caso sería accedida usando self::$propiedad.
Véase la palabra clave 'static' para más información.
La pseudo-variable $this está disponible dentro de cualquier método de clase cuando éste es
invocado dentro del contexto de un objeto. $this es una referencia al objeto que se invoca
(usualmente el objeto al que pertenece el método, pero posiblemente sea otro objeto, si el método
es llamado estáticamentedesde el contexto de un objeto secundario).
Ejemplo #1 Declaración de propiedades
<?php
class ClaseSencilla
{
// Declaraciones de propiedades inválidas:
public $var1 = 'hola ' . 'mundo';
public $var2 = <<<EOD
hola mundo
EOD;
public $var3 = 1+2;
public $var4 = self::myStaticMethod();
public $var5 = $myVar;
// Declaraciones de propiedades válidas:
public $var6 = myConstant;
public $var7 = array(true, false);
// Esto se permite sólo en PHP 5.3.0 y posteriores.
public $var8 = <<<'EOD'
hola mundo
EOD;
}
?>
Nota:
Existen varias funciones interesantes para manipular clases y objetos. Quizá pueda ser interesante
echar un vistazo a las Funciones de clases/objetos.
A diferencia de heredocs, nowdocs puede ser utilizado en cualquier contexto de datos estáticos,
incluyendo la declaración de propiedades.
Ejemplo #2 Ejemplo del uso de nowdoc para inicializar una propiedad
<?php
class foo {
// A partir de PHP 5.3.0
public $bar = <<<'EOT'
bar
EOT;
}
?>
Nota:
El soporte para nowdoc fue agregado en PHP 5.3.0.
Constantes de Clases
Es posible definir valores constantes en función de cada clase manteniéndola invariable. Las
constantes se diferencian de variables comunes en que no utilizan el símbolo $ al declararlas o
usarlas.
El valor debe ser una expresión constante, no (por ejemplo) una variable, una propiedad, un
resultado de una operación matemática, o una llamada a una función.
También es posible para las interfaces tener constantes. Ver la documentación de interfaces para
ejemplos.
A partir de PHP 5.3.0, es posible hacer referencia a una clase utilizando una variable. El valor de la
variable no puede ser una palabra clave (por ej., self, parenty static).
Ejemplo #1 Definición y uso de una constante
<?php
class MyClass
{
const constant = 'valor constante';
function showConstant() {
echo self::constant . "\n";
}
}
echo MyClass::constant . "\n";
$classname = "MyClass";
echo $classname::constant . "\n"; // A partir de PHP 5.3.0
$class = new MyClass();
$class->showConstant();
echo $class::constant."\n"; // A partir de PHP 5.3.0
?>
Ejemplo #2 Ejemplo de datos estáticos
<?php
class foo {
// A partir de PHP 5.3.0
const bar = <<<'EOT'
bar
EOT;
}
?>
A diferencia de heredocs, nowdocs puede ser utilizado en cualquier contexto de datos estáticos.
Nota:
El soporte nowdoc fue agregado en PHP 5.3.0.
Autocarga de clases
Muchos desarrolladores que escriben aplicaciones orientadas a objetos crean un fichero fuente PHP
para cada definición de clase. Una de las mayores molestias es tener que hacer una larga lista de
includes al comienzo de cada script (uno por cada clase).
En PHP 5 esto ya no es necesario. Se puede definir una función __autoload() que es
automáticamente invocada en caso de que se esté intentando utilizar una clase/interfaz que todavía
no haya sido definida. Al invocar a esta función el motor de scripting da una última oportunidad para
cargar la clase antes que PHP falle con un error.
Sugerencia
spl_autoload_register() proporciona una alternativa más flexible para la carga automática de clases.
Por esta razón, el uso de__autoload() no se recomienda y puede quedar obsoleta o ser eliminada en
el futuro.
Nota:
Antes de 5.3.0, las excepciones lanzadas en la función __autoload no podían ser capturadas en el
bloque catch y resultaba en un error fatal. Desde 5.3.0+ las excepciones lanzadas en la función
__autoload pueden ser capturadas en el bloque catch, con una consideración. Si se lanza una
excepción personalizada, la clase de dicha excepción debe estar disponible. La función __autoload
puede usarse recursivamente para autocargar la clase de la excepción personalizada.
Nota:
La autocarga no está disponible si se utiliza PHP en el modo interactivo CLI.
Nota:
Si el nombre de la clase se utiliza, por ejemplo, en call_user_func(), puede contener algunos
caracteres peligrosos tales como ../. Se recomienda no utilizar la entrada del usuario en tales
funciones, o al menos verificar dicha entrada en __autoload().
Ejemplo #1 Ejemplo de autocarga
Este ejemplo intenta cargar las clases MiClase1 y MiClase2 desde los
ficheros MiClase1.php y MiClase2.php respectivamente.
<?php
function __autoload($nombre_clase) {
include $nombre_clase . '.php';
}
$obj = new MiClase1();
$obj2 = new MiClase2();
?>
Ejemplo #2 Otro ejemplo de autocarga
Este ejemplo intenta cargar la interfaz ITest.
<?php
function __autoload($nombre) {
var_dump($nombre);
}
class Foo implements ITest {
}
/*
string(5) "ITest"
Fatal error: Interface 'ITest' not found in ...
*/
?>
Ejemplo #3 Autocarga con manejo de excepciones para 5.3.0+
Este ejemplo lanza una excepción y demuestra los bloques try/catch.
<?php
function __autoload($nombre) {
echo "Intentando cargar $nombre.\n";
throw new Exception("Imposible cargar $nombre.");
}
try {
$obj = new ClaseNoCargable();
} catch (Exception $e) {
echo $e->getMessage(), "\n";
}
?>
El resultado del ejemplo sería:
Intentando cargar ClaseNoCargable.
Imposible cargar ClaseNoCargable.
Ejemplo #4 Autocarga con manejo de excepciones para 5.3.0+ - Excepción personalizada
ausente
Este ejemplo lanza una excepción para una excepción personalizada no cargable.
<?php
function __autoload($nombre) {
echo "Intentando cargar $nombre.\n";
throw new ExcepciónAusente("Imposible cargar $nombre.");
}
try {
$obj = new ClaseNoCargable();
} catch (Exception $e) {
echo $e->getMessage(), "\n";
}
?>
El resultado del ejemplo sería:
Intentando cargar ClaseNoCargable.
Intentando cargar ExcepciónAusente.
Fatal error: Class 'ExcepciónAusente' not found in testExcepcionAusente.php on line 4
Ver también




unserialize()
unserialize_callback_func
spl_autoload()
spl_autoload_register()
Constructores y destructores
Constructor
void __construct ([ mixed $args [, $... ]] )
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.
Ejemplo #1 Utilización de nuevos constructores unificados
<?php
class BaseClass {
function __construct() {
print "En el constructor de BaseClass\n";
}
}
class SubClass extends BaseClass {
function __construct() {
parent::__construct();
print "En el constructor de SubClass\n";
}
}
$obj = new BaseClass();
$obj = new SubClass();
?>
Por motivos de compatibilidad, si PHP 5 no puede encontrar una función __construct() para una
determinada clase, 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.
Ejemplo #2 Constructores en clases pertenecientes a un nombre de espacios
<?php
namespace Foo;
class Bar {
public function Bar() {
// Tratado como constructor en PHP 5.3.0 - 5.3.2
// Tratado como método regular a partir de PHP 5.3.3
}
}
?>
Destructor
void __destruct ( void )
PHP 5 introduce un concepto de destructor similar al de otros lenguajes orientados a objetos, tal
como C++. El método destructor será llamado tan pronto como no hayan otras referencias a un
objeto determinado, o en cualquier otra circunstancia de finalización.
Ejemplo #3 Ejemplo de Destructor
<?php
class MyDestructableClass {
function __construct() {
print "En el constructor\n";
$this->name = "MyDestructableClass";
}
function __destruct() {
print "Destruyendo " . $this->name . "\n";
}
}
$obj = new MyDestructableClass();
?>
Como los constructores, los destructores padre no serán llamados implícitamente por el motor. Para
ejecutar un destructor padre, se deberá llamar explícitamente a parent::__destruct() en el interior
del destructor.
El destructor será invocado aún si la ejecución del script es detenida usando exit(). Llamar a exit() en
un destructor evitará que se ejecuten las rutinas restantes de finalización.
Nota:
Los destructores invocados durante la finalización del script tienen los headers HTTP ya enviados. El
directorio de trabajo en la fase de finalización del script puede ser diferente con algunos SAPIs (por
ej., Apache).
Nota:
Intentar lanzar una excepción desde un destructor (invocado en la finalización del script) causa un
error fatal.
Visibilidad
La visibilidad de una propiedad o método se puede definir anteponiendo una de las palabras
claves public, protected o private en la declaración. Miembros de clases declarados como public
pueden ser accedidos de cualquier lado. Miembros declarados como protected, sólo de la clase
misma, por herencia y clases parent. Aquellos definidos como private, únicamentede la clase que los
definió.
Visibilidad de Propiedades
Las propiedades de clases deben ser definidas como public, private, o protected. Si se declaran
usando var, serán definidas como public.
Ejemplo #1 Declaración de propiedades
<?php
/**
* Definición de MyClass
*/
class MyClass
{
public $public = 'Public';
protected $protected = 'Protected';
private $private = 'Private';
function
{
echo
echo
echo
}
printHello()
$this->public;
$this->protected;
$this->private;
}
$obj = new MyClass();
echo $obj->public; // Funciona
echo $obj->protected; // Error Fatal
echo $obj->private; // Error Fatal
$obj->printHello(); // Muestra Public, Protected y Private
/**
* Definición de MyClass2
*/
class MyClass2 extends MyClass
{
// Se puede redeclarar los métodos public y protected, pero no el private
protected $protected = 'Protected2';
function
{
echo
echo
echo
}
printHello()
$this->public;
$this->protected;
$this->private;
}
$obj2 = new MyClass2();
echo $obj2->public; // Funciona
echo $obj2->private; // Undefined
echo $obj2->protected; // Error Fatal
$obj2->printHello(); // Muestra Public, Protected2, Undefined
?>
Nota: La forma de declaración de una variable de PHP 4 con la palabra clave var todavía es
soportado (como un sinónimo de public) por razones de compatibilidad. En PHP 5 antes de 5.1.3, su
uso genera un Warning E_STRICT.
Visibilidad de Métodos
Los métodos de clases pueden ser definidos como public, private, o protected. Aquellos declarados
sin ninguna palabra clave de visibilidad explícita serán definidos como public.
Ejemplo #2 Declaración de métodos
<?php
/**
* Definición de MyClass
*/
class MyClass
{
// Declaración de un constructor public
public function __construct() { }
// Declaración de un método public
public function MyPublic() { }
// Declaración de un método protected
protected function MyProtected() { }
// Declaración de un método private
private function MyPrivate() { }
// Esto es public
function Foo()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate();
}
}
$myclass = new MyClass;
$myclass->MyPublic(); // Funciona
$myclass->MyProtected(); // Error Fatal
$myclass->MyPrivate(); // Error Fatal
$myclass->Foo(); // Public, Protected y Private funcionan
/**
* Definición de MyClass2
*/
class MyClass2 extends MyClass
{
// Esto es public
function Foo2()
{
$this->MyPublic();
$this->MyProtected();
$this->MyPrivate(); // Error Fatal
}
}
$myclass2 = new MyClass2;
$myclass2->MyPublic(); // Funciona
$myclass2->Foo2(); // Public y Protected funcionan, pero Private no
class Bar
{
public function test() {
$this->testPrivate();
$this->testPublic();
}
public function testPublic() {
echo "Bar::testPublic\n";
}
private function testPrivate() {
echo "Bar::testPrivate\n";
}
}
class Foo extends Bar
{
public function testPublic() {
echo "Foo::testPublic\n";
}
private function testPrivate() {
echo "Foo::testPrivate\n";
}
}
$myFoo = new foo();
$myFoo->test(); // Bar::testPrivate
// Foo::testPublic
?>
Visibilidad desde otros objetos
Los objetos del mismo tipo tendrán acceso a los miembros private y protected entre ellos aunque no
sean de la misma instancia. Esto es porque los detalles específicos de implementación ya se conocen
cuando se encuentra dentro de estos objetos.
Ejemplo #3 Accediendo a miembros private del mismo tipo de objeto
<?php
class Test
{
private $foo;
public function __construct($foo)
{
$this->foo = $foo;
}
private function bar()
{
echo 'Método private accedido.';
}
public function baz(Test $other)
{
// Se puede cambiar la propiedad private:
$other->foo = 'hola';
var_dump($other->foo);
// También se puede invocar al método private:
$other->bar();
}
}
$test = new Test('test');
$test->baz(new Test('other'));
?>
El resultado del ejemplo sería:
string(5) "hola"
Método private accedido.
Herencia de Objetos
La herencia es un principio de programación bien establecido y PHP hace uso de él en su modelado
de objetos. Este principio afectará la manera en que muchas clases y objetos se relacionan unas con
otras.
Por ejemplo, cuando se extiende una clase, la subclase hereda todos los métodos públicos y
protegidos de la clase padre. A menos que una clase sobrescriba esos métodos, mantendrán su
funcionalidad original.
Esto es útil para la definición y abstracción de la funcionalidad y permite la implementación de
funcionalidad adicional en objetos similares sin la necesidad de reimplementar toda la funcionalidad
compartida.
Nota:
A menos que la carga automática sea utilizada, entonces las clases deben ser definidas antes de ser
usadas. Si una clase se extiende a otra, entonces la clase padre debe ser declarada antes de la
estructura de clase hija. Esta regla se aplica a las clases que heredan de otras clases e interfaces.
Ejemplo #1 Ejemplo de herencia
<?php
class foo
{
public function printItem($string)
{
echo 'Foo: ' . $string . PHP_EOL;
}
public function printPHP()
{
echo 'PHP is great.' . PHP_EOL;
}
}
class bar extends foo
{
public function printItem($string)
{
echo 'Bar: ' . $string . PHP_EOL;
}
}
$foo = new foo();
$bar = new bar();
$foo->printItem('baz');
$foo->printPHP();
$bar->printItem('baz');
$bar->printPHP();
//
//
//
//
Salida:
Salida:
Salida:
Salida:
'Foo: baz'
'PHP is great'
'Bar: baz'
'PHP is great'
?>
Operador de Resolución de Ámbito (::)
El Operador de Resolución de Ámbito (también denominado Paamayim Nekudotayim) o en términos
simples, el doble dos-puntos, es un token que permite acceder a elementos estáticos, constantes, y
sobrescribir propiedades o métodos de una clase.
Cuando se hace referencia a estos items desde el exterior de la definición de la clase, se utiliza el
nombre de la clase.
A partir de PHP 5.3.0, es posible hacer referencia a una clase usando una variable. El valor de la
variable no puede ser una palabra clave (por ej., self, parent ystatic).
Paamayim Nekudotayim podría, en un principio, parecer una extraña elección para bautizar a un
doble dos-puntos. Sin embargo, mientras se escribía el Zend Engine 0.5 (que utilizó PHP 3), asi es
como el equipo Zend decidió bautizarlo. En realidad, significa doble dos-puntos - en Hebreo!
Ejemplo #1 :: desde el exterior de la definición de la clase
<?php
class MyClass {
const CONST_VALUE = 'Un valor constante';
}
$classname = 'MyClass';
echo $classname::CONST_VALUE; // A partir de PHP 5.3.0
echo MyClass::CONST_VALUE;
?>
Las tres palabras claves especiales self, parent y static son utilizadas para acceder a propiedades y
métodos desde el interior de la definición de la clase.
Ejemplo #2 :: desde el interior de la definición de la clase
<?php
class OtherClass extends MyClass
{
public static $my_static = 'variable estática';
public static function doubleColon() {
echo parent::CONST_VALUE . "\n";
echo self::$my_static . "\n";
}
}
$classname = 'OtherClass';
echo $classname::doubleColon(); // A partir de PHP 5.3.0
OtherClass::doubleColon();
?>
Cuando una clase extendida sobrescribe la definición parent de un método, PHP no invocará al
método parent. Depende de la clase extendida el hecho de llamar o no al método parent. Esto
también se aplica a definiciones de métodos Constructores y Destructores, Sobrecarga, y Mágicos.
Ejemplo #3 Invocando a un método parent
<?php
class MyClass
{
protected function myFunc() {
echo "MyClass::myFunc()\n";
}
}
class OtherClass extends MyClass
{
// Sobrescritura de definición parent
public function myFunc()
{
// Pero todavía se puede llamar a la función parent
parent::myFunc();
echo "OtherClass::myFunc()\n";
}
}
$class = new OtherClass();
$class->myFunc();
?>
Véase también algunos ejemplos de trucos de llamadas estáticas .
La palabra clave 'static'
Sugerencia
Esta página describe el uso de la palabra clave static para definir métodos y propiedades
estáticos. static también se puede usar paradefinir variables estáticas y para enlaces estáticos en
tiempo de ejecución. Por favor, consulte estas páginas para más información sobre estos sifnificados
de static.
Declarar propiedades o métodos de clases como estáticos los hacen accesibles sin la necesidad de
instanciar la clase. Una propiedad declarada como static no puede ser accedida con un objeto de
clase instanciado (aunque un método estático sí lo puede hacer).
Por motivos de compatibilidad con PHP 4, si no se utiliza ninguna declaración de visibilidad, se tratará
a las propiedades o métodos como si hubiesen sido definidos como public.
Debido a que los métodos estáticos se pueden invocar sin tener creada una instancia del objeto, la
pseudo-variable $this no está disponible dentro de los métodos declarados como estáticos.
Las propiedades estáticas no pueden ser accedidas a través del objeto utilizando el operador flecha (>).
Invocar métodos no estáticos estáticamente genera una advertencia de nivel E_STRICT.
Como cualquier otra variable estática de PHP, las propiedades estáticas sólo pueden ser inicializadas
utilizando un string literal o una constante; las expresiones no están permitidas. Por tanto, se puede
inicializar una propiedad estática con enteros o arrays (por ejemplo), pero no se puede hacer con
otra variable, con el valor de devolución de una función, o con un objeto.
A partir de PHP 5.3.0, es posible hacer referencia a una clase usando una variable. El valor de la
variable no puede ser una palabra clave (p.ej., self, parent ystatic).
Ejemplo #1 Ejemplo de propiedad estática
<?php
class Foo
{
public static $mi_static = 'foo';
public function valorStatic() {
return self::$mi_static;
}
}
class Bar extends Foo
{
public function fooStatic() {
return parent::$mi_static;
}
}
print Foo::$mi_static . "\n";
$foo = new Foo();
print $foo->valorStatic() . "\n";
print $foo->mi_static . "\n";
// "Propiedad" mi_static no definida
print $foo::$mi_static . "\n";
$nombreClase = 'Foo';
print $nombreClase::$mi_static . "\n"; // A partir de PHP 5.3.0
print Bar::$mi_static . "\n";
$bar = new Bar();
print $bar->fooStatic() . "\n";
?>
Ejemplo #2 Ejemplo de método estático
<?php
class Foo {
public static function unMétodoEstático() {
// ...
}
}
Foo::unMétodoEstático();
$nombreClase = 'Foo';
$nombreClase::unMétodoEstático(); // A partir de PHP 5.3.0
?>
Abstracción de clases
PHP 5 introduce clases y métodos abstractos. Las clases definidas como abstract seguramente no son
instanciadas y cualquier clase que contiene almenos un método abstracto debe ser definida como
abstract. Los métodos definidos como abstractos simplemente declaran la estructura del método,
pero no pueden definir la implementación.
Cuando se hereda de una clase abstracta, todos los métodos definidos como abstract en la definición
de la clase parent deben ser redefinidos en la clase child; adicionalmente, estos métodos deben ser
definidos con la misma visibilidad (o con una menos restrictiva). Por ejemplo, si el método abstracto
está definido como protected, la implementación de la función puede ser redefinida como protected o
public, pero nunca como private. Por otra parte, las estructuras de los métodos tienen que coincidir,
es decir, los (type hinting) tipos sugeridos y el número de argumentos requeridos deben ser los
mismos. Esto también aplica a los constructores de PHP 5.4. Antes de PHP 5.4 las estructuras del
constructor podían ser diferentes.
Ejemplo #1 Ejemplo de clase abstracta
<?php
abstract class AbstractClass
{
// Forzando la extensión de clase para definir este método
abstract protected function getValue();
abstract protected function prefixValue($prefix);
// Método común
public function printOut() {
print $this->getValue() . "\n";
}
}
class ConcreteClass1 extends AbstractClass
{
protected function getValue() {
return "ConcreteClass1";
}
public function prefixValue($prefix) {
return "{$prefix}ConcreteClass1";
}
}
class ConcreteClass2 extends AbstractClass
{
public function getValue() {
return "ConcreteClass2";
}
public function prefixValue($prefix) {
return "{$prefix}ConcreteClass2";
}
}
$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue('FOO_') ."\n";
$class2 = new ConcreteClass2;
$class2->printOut();
echo $class2->prefixValue('FOO_') ."\n";
?>
El resultado del ejemplo sería:
ConcreteClass1
FOO_ConcreteClass1
ConcreteClass2
FOO_ConcreteClass2
Códigos antiguos que no tengan clases o funciones definidas por el usuario llamadas 'abstract'
deberían ejecutarse sin modificaciones.
Interfaces de objetos
Las interfaces de objetos permiten crear código con el cual especificamos qué métodos deben ser
implementados por una clase, sin tener que definir cómo estos métodos son manipulados.
Las interfaces son definidas utilizando la palabra clave interface, de la misma forma que con clases
estándar, pero sin métodos que tengan su contenido definido.
Todos los métodos declarados en una interfaz deben ser public, ya que ésta es la naturaleza de una
interfaz.
implements
Para implementar una interfaz, se utiliza el operador implements. Todos los métodos en una
interfaz deben ser implementados dentro de la clase; el no cumplir con esta regla resultará en un
error fatal. Las clases pueden implementar más de una interfaz si se deseara, separándolas cada una
por una coma.
Nota:
Una clase no puede implementar dos interfaces que compartan nombres de funciones, puesto que
esto causaría ambigüedad.
Nota:
Las interfaces se pueden extender al igual que las clases utilizando el operador extends.
Nota:
La clase que implemente una interfaz debe utilizar exactamente las mismas estructuras de métodos
que fueron definidos en la interfaz. De no cumplir con esta regla, se generará un error fatal.
Constantes
Es posible tener constantes dentro de las interfaces. Las constantes de interfaces funcionan como
las constantes de clases excepto porque no pueden ser sobrescritas por una clase/interfaz que las
herede.
Ejemplos
Ejemplo #1 Ejemplo de interfaz
<?php
// Declarar la interfaz 'iTemplate'
interface iTemplate
{
public function setVariable($name, $var);
public function getHtml($template);
}
// Implementar la interfaz
// Ésto funcionará
class Template implements iTemplate
{
private $vars = array();
public function setVariable($name, $var)
{
$this->vars[$name] = $var;
}
public function getHtml($template)
{
foreach($this->vars as $name => $value) {
$template = str_replace('{' . $name . '}', $value, $template);
}
return $template;
}
}
// Ésto no funcionará
// Error fatal: La Clase BadTemplate contiene un método abstracto
// y por lo tanto debe declararse como abstracta (iTemplate::getHtml)
class BadTemplate implements iTemplate
{
private $vars = array();
public function setVariable($name, $var)
{
$this->vars[$name] = $var;
}
}
?>
Ejemplo #2 Interfaces extensibles
<?php
interface a
{
public function foo();
}
interface b extends a
{
public function baz(Baz $baz);
}
// Ésto sí funcionará
class c implements b
{
public function foo()
{
}
public function baz(Baz $baz)
{
}
}
// Ésto no funcionará y resultará en un error fatal
class d implements b
{
public function foo()
{
}
public function baz(Foo $foo)
{
}
}
?>
Ejemplo #3 Herencia múltiple de interfaces
<?php
interface a
{
public function foo();
}
interface b
{
public function bar();
}
interface c extends a, b
{
public function baz();
}
class d implements c
{
public function foo()
{
}
public function bar()
{
}
public function baz()
{
}
}
?>
Ejemplo #4 Interfaces con constantes
<?php
interface a
{
const b = 'Interface constant';
}
// Imprime: Interface constant
echo a::b;
// Sin embargo ésto no funcionará ya que no está permitido
// sobrescribir constantes
class b implements a
{
const b = 'Class constant';
}
?>
Una interfaz, junto con type-hinting, proveen una buena forma de asegurarse que determinado
objeto contiene métodos particulares. Vea el operadorinstanceof y type hinting.
Traits
Desde PHP 5.4.0, PHP implementa una metodología de reutilización de código llamada Traits.
Los traits (rasgos) son un mecanismo de reutilización de código en lenguajes de herencia simple,
como PHP. El objetivo de un trait es el de reducir las limitaciones propias de la herencia simple
permitiendo que los desarrolladores reutilicen a voluntad conjuntos de métodos sobre varias clases
independientes y pertenecientes a clases jerárquicas distintas. La semántica a la hora combinar Traits
y clases se define de tal manera que reduzca su complejidad y se eviten los problemas típicos
asociados a la herencia múltiple y a los Mixins.
Un Trait es similar a una clase, pero con el único objetivo de agrupar funcionalidades muy específicas
y de una manera coherente. No se puede instanciar directamente un Trait. Es por tanto un añadido a
la herencia tradicional, y habilita la composición horizontal de comportamientos; es decir, permite
combinar miembros de clases sin tener que usar herencia.
Ejemplo #1 Ejemplo de Trait
<?php
trait ezcReflectionReturnInfo {
function getReturnType() { /*1*/ }
function getReturnDescription() { /*2*/ }
}
class ezcReflectionMethod extends ReflectionMethod {
use ezcReflectionReturnInfo;
/* ... */
}
class ezcReflectionFunction extends ReflectionFunction {
use ezcReflectionReturnInfo;
/* ... */
}
?>
Precedencia
Los miembros heredados de una clase base se sobrescriben cuando se inserta otro miembro
homónimo desde un Trait. De acuerdo con el orden de precedencia, los miembros de la clase actual
sobrescriben los métodos del Trait, que a su vez sobrescribe los métodos heredados.
Ejemplo #2 Ejemplo de Orden de Precedencia
Se sobrescribe un miembro de la clase base con el método insertado en MiHolaMundo a partir del
Trait DecirMundo. El comportamiento es el mismo para los métodos definidos en la clase
MiHolaMundo. Según el orden de precedencia los métodos de la clase actual sobrescriben los
métodos del Trait, a la vez que el Trait sobrescribe los métodos de la clase base.
<?php
class Base {
public function decirHola() {
echo '¡Hola ';
}
}
trait DecirMundo {
public function decirHola() {
parent::decirHola();
echo 'Mundo!';
}
}
class MiHolaMundo extends Base {
use DecirMundo;
}
$o = new MiHolaMundo();
$o->decirHola();
?>
El resultado del ejemplo sería:
¡Hola Mundo!
Ejemplo #3 Ejemplo de Orden de Precedencia #2
<?php
trait HolaMundo {
public function decirHola() {
echo '¡Hola Mundo!';
}
}
class ElMundoNoEsSuficiente {
use HolaMundo;
public function decirHola() {
echo '¡Hola Universo!';
}
}
$o = new ElMundoNoEsSuficiente();
$o->decirHola();
?>
El resultado del ejemplo sería:
¡Hola Universo!
Multiples Traits
Se pueden insertar múltiples Traits en una clase, mediante una lista separada por comas en la
sentencia use.
Ejemplo #4 Uso de Múltiples Traits
<?php
trait Hola {
public function decirHola() {
echo 'Hola ';
}
}
trait Mundo {
public function decirMundo() {
echo 'Mundo';
}
}
class MiHolaMundo {
use Hola, Mundo;
public function decirAdmiración() {
echo '!';
}
}
$o = new MiHolaMundo();
$o->decirHola();
$o->decirMundo();
$o->decirAdmiración();
?>
El resultado del ejemplo sería:
Hola Mundo!
Resolución de Conflictos
Si dos Traits insertan un método con el mismo nombre, se produce un error fatal, siempre y cuando
no se haya resuelto explicitamente el conflicto.
Para resolver los conflictos de nombres entre Traits en una misma clase, se debe usar el
operador insteadof para elejir unívocamente uno de los métodos conflictivos.
Como esto sólo permite excluir métodos, se puede usar el operador as para permitir incluir uno de
los métodos conflictivos bajo otro nombre.
Ejemplo #5 Resolución de Conflictos
En este ejemplo, Talker utiliza los traits A y B. Como A y B tienen métodos conflictos, se define el uso
de la variante de smallTalk del trait B, y la variante de bigTalk del traita A.
Aliased_Talker hace uso del operador as para poder usar la implementación de bigTalk de B, bajo el
alias adicional talk.
<?php
trait A {
public function smallTalk() {
echo 'a';
}
public function bigTalk() {
echo 'A';
}
}
trait B {
public function smallTalk() {
echo 'b';
}
public function bigTalk() {
echo 'B';
}
}
class Talker {
use A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
}
}
class Aliased_Talker {
use A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
B::bigTalk as talk;
}
}
?>
Modificando la Visibilidad de los Métodos
Al usar el operador as, se puede también ajustar la visibilidad del método en la clase exhibida.
Ejemplo #6 Modificar la Visibilidad de un Método
<?php
trait HolaMundo {
public function decirHola() {
echo 'Hola Mundo!';
}
}
// Cambiamos visibilidad de decirHola
class MiClase1 {
use HolaMundo { decirHola as protected }
}
// Método alias con visibilidad cambiada
// La visibilidad de decirHola no cambia
class MiClase2 {
use HolaMundo { hacerHolaMundo as private decirHola }
}
?>
Traits Compuestos de Traits
Al igual que las clases, los Traits también pueden hacer uso de otros Traits. Al usar uno o más traits
en la definición de un trait, éste puede componerse parcial o completamente de miembros de finidos
en esos otros traits.
Ejemplo #7 Traits Compuestos de Traits
<?php
trait Hola {
public function decirHola() {
echo 'Hola ';
}
}
trait Mundo {
public function decirMundo() {
echo 'Mundo!';
}
}
trait HolaMundo {
use Hola, Mundo;
}
class MiHolaMundo {
use HolaMundo;
}
$o = new MiHolaMundo();
$o->decirHola();
$o->decirMundo();
?>
El resultado del ejemplo sería:
Hola Mundo!
Miembros Abstractos de Traits
Los traits soportan el uso de métodos abstractos para imponer requisitos a la clase a la que se
exhiban.
Ejemplo #8 Expresar Resquisitos con Métodos Abstractos
<?php
trait Hola {
public function decirHolaMundo() {
echo 'Hola'.$this->obtenerMundo();
}
abstract public function obtenerMundo();
}
class MiHolaMundo {
private $mundo;
use Hola;
public function obtenerMundo() {
return $this->mundo;
}
public function asignarMundo($val) {
$this->mundo = $val;
}
}
?>
Miembros Estáticos en Traits
Los métodos de un trait pueden referenciar a variables estáticas, pero no puede ser definido en el
trait. Los traits, sin embargo, pueden definir método estáticos a la clase a la que se exhiben.
Ejemplo #9 Variables estáticas
<?php
trait Contador {
public function inc() {
static $c = 0;
$c = $c + 1;
echo "$c\n";
}
}
class C1 {
use Contador;
}
class C2 {
use Contador;
}
$o = new C1(); $o->inc(); // echo 1
$p = new C2(); $p->inc(); // echo 1
?>
Ejemplo #10 Métodos Estáticos
<?php
trait EjemploEstatico {
public static function hacerAlgo() {
return 'Hacer algo';
}
}
class Ejemplo {
use EjemploEstatico;
}
Ejemplo::hacerAlgo();
?>
Propiedades
Los traits también pueden definir propiedades.
Ejemplo #11 Definir Propiedades
<?php
trait PropiedadesTrait {
public $x = 1;
}
class EjemploPropiedades {
use PropiedadesTrait;
}
$ejemplo = new EjemploPropiedades;
$ejemplo->x;
?>
Si un trait define una propiedad una clase no puede definir una propiedad con el mismo nombre, si
no se emitirá un error.Éste de tipo E_STRICT si la definición de la clase es compatible (misma
visibilidad y valor inicial) o de otro modo un error fatal.
Ejemplo #12 Resolución de Conflictos
<?php
trait PropiedadesTrait {
public $misma = true;
public $diferente = false;
}
class EjemploPropiedades {
use PropiedadesTrait;
public $misma = true; // Estándares estrictos
public $diferente = true; // Error fatal
}
?>
Sobrecarga
La sobrecarga en PHP ofrece los medios para "crear" dinámicamente propiedades y métodos. Estas
entidades dinámicas se procesan por los métodos mágicos que se pueden establecer en una clase
para diversas acciones.
Se invoca a los métodos de sobrecarga cuando se interactúa con propiedades o métodos que no se
han declarado o que no son visibles en el ámbito activo. A lo largo de esta sección usaremos los
términos "propiedades inaccesibles" y "métodos inaccesibles" para referirnos a esta combinación de
declaración y visibilidad.
Todos los métodos sobrecargados deben definirse como public.
Nota:
No se puede pasar ninguno de los parámetros de estos métodos mágicos por referencia.
Nota:
La interpretación de PHP de "overloading" es distinta de la mayoría de los lenguajes orientados a
objetos. La sobrecarga tradicionalmente ofrece la capacidad de tener múltiples métodos con el mismo
nombre, pero con un tipo o un número distinto de parámetros.
Historial de cambios
Versión
Descripción
5.3.0
Se añade __callStatic. Se añadieron advertencias para hacer cumplir la visibilidad public e impedir la
declaración static.
5.1.0
Añadidos los métodos __isset y __unset.
Sobrecarga de propiedades
public void __set ( string $name , mixed $value )
public mixed __get ( string $name )
public bool __isset ( string $name )
public void __unset ( string $name )
__set() se ejecuta al escribir datos sobre propiedades inaccesibles.
__get() se utiliza para consultar datos a partir de propiedades inaccesibles.
__isset() se lanza al llamar a isset() o a empty() sobre propiedades inaccesibles.
__unset() se invoca cuando se usa unset() sobre propiedades inaccesibles.
El parámetro $name es el nombre de la propiedad con la que se está interactuando. En el
método __set() el parámetro $value especifica el valor que se debe asignar a la propiedad $name.
La sobrecarga de propiedades sólo funciona en contextos de objetos. Estos métodos mágicos no se
lanzarán en contextos estáticos. Por esa razón, no se deben declarar como estáticos. Desde PHP
5.3.0, se emite un aviso si alguno de los métodos de sobrecarga es declarado como static.
Nota:
Debido a la forma en que PHP procesa el operador de asignación, el valor que devuelve __set() se
ignora. Del mismo modo, nunca se llama a __get() al encadenar asignaciones como ésta:
$a = $obj->b = 8;
Nota:
No se puede utilizar una propiedad sobrecargada en ninguna construcción del lenguaje que no
sea isset(). Esto significa que si se invoca a empty() en una propiedad sobrecargada, no se llamará al
método de sobrecarga.
Para solventar esta limitación, se debe copiar la propiedad sobrecargada en una variable de ámbito
local que empty() pueda manejar.
Ejemplo #1 Sobrecarga de propiedades mediante los
métodos __get(), __set(), __isset() y __unset()
<?php
class PropertyTest
{
/** Localización de los datos sobrecargados.
private $data = array();
*/
/** La sobrecarga no se usa en propiedades declaradas.
public $declared = 1;
*/
/** La sobre carga sólo funciona aquí al acceder desde fuera de la clase.
private $hidden = 2;
public function __set($name, $value)
{
echo "Estableciendo '$name' a '$value'\n";
$this->data[$name] = $value;
}
public function __get($name)
{
echo "Consultando '$name'\n";
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
$trace = debug_backtrace();
*/
trigger_error(
'Propiedad indefinida mediante __get(): ' . $name .
' en ' . $trace[0]['file'] .
' en la línea ' . $trace[0]['line'],
E_USER_NOTICE);
return null;
}
/** Desde PHP 5.1.0 */
public function __isset($name)
{
echo "¿Está definido '$name'?\n";
return isset($this->data[$name]);
}
/** Desde PHP 5.1.0 */
public function __unset($name)
{
echo "Eliminando '$name'\n";
unset($this->data[$name]);
}
/** No es un método mágico, esta aquí para completar el ejemplo.
public function getHidden()
{
return $this->hidden;
}
*/
}
echo "<pre>\n";
$obj = new PropertyTest;
$obj->a = 1;
echo $obj->a . "\n\n";
var_dump(isset($obj->a));
unset($obj->a);
var_dump(isset($obj->a));
echo "\n";
echo $obj->declared . "\n\n";
echo
echo
echo
echo
echo
?>
"Vamos a probar con la propiedad privada que se llama 'hidden':\n";
"Las propiedades privadas pueden consultarse en la clase, por lo que no se usa __get()...\n";
$obj->getHidden() . "\n";
"Las propiedades privadas no son visibles fuera de la clase, por lo que se usa __get()...\n";
$obj->hidden . "\n";
El resultado del ejemplo sería:
Estableciendo 'a' a '1'
Consultando 'a'
1
¿Está definido 'a'?
bool(true)
Eliminando 'a'
¿Está definido 'a'?
bool(false)
1
Vamos a probar con la propiedad privada que se llama 'hidden':
Las propiedades privadas pueden consultarse en la clase, por lo que no se usa __get()...
2
Las propiedades privadas no son visibles fuera de la clase, por lo que se usa __get()...
Consultando 'hidden'
Notice: Propiedad indefinida mediante __get(): hidden en <file> en la línea 69 in <file>en la
línea 28
Sobrecarga de métodos
public mixed __call ( string $name , array $arguments )
public static mixed __callStatic ( string $name , array $arguments )
__call() es lanzado al invocar un método inaccesible en un contexto de objeto.
__callStatic() es lanzado al invocar un método inaccesible en un contexto estático.
El parámetro $name corresponde al nombre del método al que se está llamando. El
parámetro $arguments es un array enumerado que contiene los parámetros que se han pasado al
método $name.
Ejemplo #2 Sobrecarga de métodos mediante los métodos __call() and __callStatic()
<?php
class MethodTest
{
public function __call($name, $arguments)
{
// Nota: el valor $name es sensible a mayúsculas.
echo "Llamando al método de objeto '$name' "
. implode(', ', $arguments). "\n";
}
/** Desde PHP 5.3.0 */
public static function __callStatic($name, $arguments)
{
// Nota: el valor $name es sensible a mayúsculas.
echo "Llamando al método estático '$name' "
. implode(', ', $arguments). "\n";
}
}
$obj = new MethodTest;
$obj->runTest('en contexto de objeto');
MethodTest::runTest('en contexto estático');
?>
// Desde PHP 5.3.0
El resultado del ejemplo sería:
Llamando al método de objeto 'runTest' en contexto de objeto
Llamando al método estático 'runTest' en contexto estático
Iteración de objetos
PHP 5 ofrece una manera para que los objetos sean definidos por lo que es posible iterar a través de
una lista de elementos, con, por ejemplo, una sentenciaforeach. Por defecto, todas las
propiedades visibles serán utilizados para la iteración.
Ejemplo #1 Iteración simple de objeto
<?php
class MyClass
{
public $var1 = 'value 1';
public $var2 = 'value 2';
public $var3 = 'value 3';
protected $protected = 'protected var';
private
$private
= 'private var';
function iterateVisible() {
echo "MyClass::iterateVisible:\n";
foreach($this as $key => $value) {
print "$key => $value\n";
}
}
}
$class = new MyClass();
foreach($class as $key => $value) {
print "$key => $value\n";
}
echo "\n";
$class->iterateVisible();
?>
El resultado del ejemplo sería:
var1 => value 1
var2 => value 2
var3 => value 3
MyClass::iterateVisible:
var1 => value 1
var2 => value 2
var3 => value 3
protected => protected var
private => private var
Como se muestra en la salida, el foreach itera a través de todas las propiedades visibles que se
puedan acceder.
Para dar un paso más, se puede implementar la interfaz Iterator. Esto permite al objeto decidir cómo
será iterado y qué valores estarán disponibles en cada iteración.
Ejemplo #2 Iteración de objeto implementando Iterator
<?php
class MyIterator implements Iterator
{
private $var = array();
public function __construct($array)
{
if (is_array($array)) {
$this->var = $array;
}
}
public function rewind()
{
echo "rewinding\n";
reset($this->var);
}
public function current()
{
$var = current($this->var);
echo "current: $var\n";
return $var;
}
public function key()
{
$var = key($this->var);
echo "key: $var\n";
return $var;
}
public function next()
{
$var = next($this->var);
echo "next: $var\n";
return $var;
}
public function valid()
{
$key = key($this->var);
$var = ($key !== NULL && $key !== FALSE);
echo "valid: $var\n";
return $var;
}
}
$values = array(1,2,3);
$it = new MyIterator($values);
foreach ($it as $a => $b) {
print "$a: $b\n";
}
?>
El resultado del ejemplo sería:
rewinding
valid: 1
current: 1
key: 0
0: 1
next: 2
valid: 1
current: 2
key: 1
1: 2
next: 3
valid: 1
current: 3
key: 2
2: 3
next:
valid:
La interface IteratorAggregate se puede usar como alternativa para implementar todos los métodos
de Iterator. IteratorAggregate solamente requiere la implementación de un único
método, IteratorAggregate::getIterator(), el cual debería devolver una instancia de una clase que
implemente Iterator.
Ejemplo #3 Iteración de objeto implementando IteratorAggregate
<?php
class MyCollection implements IteratorAggregate
{
private $items = array();
private $count = 0;
// Se requiere la definición de la interfaz IteratorAggregate
public function getIterator() {
return new MyIterator($this->items);
}
public function add($value) {
$this->items[$this->count++] = $value;
}
}
$coll = new MyCollection();
$coll->add('value 1');
$coll->add('value 2');
$coll->add('value 3');
foreach ($coll as $key => $val) {
echo "key/value: [$key -> $val]\n\n";
}
?>
El resultado del ejemplo sería:
rewinding
current: value 1
valid: 1
current: value 1
key: 0
key/value: [0 -> value 1]
next: value 2
current: value 2
valid: 1
current: value 2
key: 1
key/value: [1 -> value 2]
next: value 3
current: value 3
valid: 1
current: value 3
key: 2
key/value: [2 -> value 3]
next:
current:
valid:
Nota:
Para más ejemplos de iteradores, vea la extensión SPL.
Métodos mágicos
Los nombres de
método __construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), _
_sleep(), __wakeup(), __toString(),__invoke(), __set_state() y __clone() son mágicos en las clases
PHP. No se puede tener métodos con estos nombres en cualquiera de las clases a menos que desee
la funcionalidad mágica asociada a estos.
Precaución
PHP se reserva todos los nombres de los métodos que comienzan con __ como mágicos. Se
recomienda que no utilice los nombres de métodos con __ en PHP a menos que desee alguna
funcionalidad mágica documentada.
__sleep() y __wakeup()
public array __sleep ( void )
void __wakeup ( void )
serialize() comprueba si la clase tiene un método con el nombre mágico __sleep(). Si es así, el
método se ejecuta antes de cualquier serialización. Se puede limpiar el objeto y se supone que
devuelve un array con los nombres de todas las variables de el objeto que se va a serializar. Si el
método no devuelve nada, entonces NULL es serializado y un error E_NOTICE es emitido.
Nota:
No es posible para __sleep() devolver nombres de propiedades privadas en las clases padres. Hacer
esto resultaría un nivel de error E_NOTICE. En su lugar, puede utilizar la interfaz Serializable.
El uso para el que está destinado __sleep() consiste en confirmar datos pendientes o realizar tareas
similares de limpieza. Además, el método es útil si tiene objetos muy grandes que no necesitan
guardarse por completo.
Por el contrario, unserialize() comprueba la presencia de un método con el nombre
mágico __wakeup(). Si está presente, este método puede reconstruir cualquier recurso que el objeto
pueda tener.
El uso para el que está destinado __wakeup() es restablecer las conexiones de base de datos que se
puedan haber perdido durante la serialización y realizar otras tareas de reinicialización.
Ejemplo #1 Sleep y wakeup
<?php
class Connection
{
protected $link;
private $server, $username, $password, $db;
public function __construct($server, $username, $password, $db)
{
$this->server = $server;
$this->username = $username;
$this->password = $password;
$this->db = $db;
$this->connect();
}
private function connect()
{
$this->link = mysql_connect($this->server, $this->username, $this->password);
mysql_select_db($this->db, $this->link);
}
public function __sleep()
{
return array('server', 'username', 'password', 'db');
}
public function __wakeup()
{
$this->connect();
}
}
?>
__toString()
public string __toString ( void )
El método __toString() permite a una clase decidir cómo comportarse cuando se le trata como un
string. Por ejemplo, lo que echo $obj; mostraría. Este método debe devolver un string, si no se
emitirá un nivel de error fatal E_RECOVERABLE_ERROR.
Ejemplo #2 Ejemplo simple
<?php
// Declarar una clase simple
class TestClass
{
public $foo;
public function __construct($foo)
{
$this->foo = $foo;
}
public function __toString()
{
return $this->foo;
}
}
$class = new TestClass('Hola Mundo');
echo $class;
?>
El resultado del ejemplo sería:
Hola Mundo
Antes de PHP 5.2.0 el método __toString() se llama sólo cuando se combina directamente
con echo o print. Desde PHP 5.2.0, se le llama en cualquier contexto de string (e.j. en printf() con el
modificador %s) pero no en el contexto de otros tipos (e.j. con el modificador %d). Desde PHP
5.2.0, la conversión de los objetos sin el método __toString() a string podría
causar E_RECOVERABLE_ERROR.
__invoke()
mixed __invoke ([ $... ] )
El método __invoke() es llamado cuando un script intenta llamar a un objeto como si fuera una
función.
Nota:
Esta característica está disponible desde PHP 5.3.0.
Ejemplo #3 Uso de __invoke()
<?php
class CallableClass
{
public function __invoke($x)
{
var_dump($x);
}
}
$obj = new CallableClass;
$obj(5);
var_dump(is_callable($obj));
?>
El resultado del ejemplo sería:
int(5)
bool(true)
__set_state()
static object __set_state ( array $properties )
Este método static es llamado para las clases exportadas por var_export(), desde PHP 5.1.0.
El único parámetro de este método es un array que contiene las propiedades exportadas en la
forma array('property' => value, ...).
Ejemplo #4 Uso de __set_state() (desde PHP 5.1.0)
<?php
class A
{
public $var1;
public $var2;
public static function __set_state($an_array) // A partir de PHP 5.1.0
{
$obj = new A;
$obj->var1 = $an_array['var1'];
$obj->var2 = $an_array['var2'];
return $obj;
}
}
$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';
eval('$b = ' . var_export($a, true) . ';'); // $b = A::__set_state(array(
//
'var1' => 5,
//
'var2' => 'foo',
// ));
var_dump($b);
?>
El resultado del ejemplo sería:
object(A)#2 (2) {
["var1"]=>
int(5)
["var2"]=>
string(3) "foo"
}
Palabra clave Final
PHP 5 introduce la nueva palabra clave final, que impide que las clases hijas sobrescriban un método,
antecediendo su definición con la palabra final. Si la propia clase se define como final, entonces no se
podrá heredar de ella.
Ejemplo #1 Ejemplo de métodos Final
<?php
class BaseClass {
public function test() {
echo "llamada a BaseClass::test()\n";
}
final public function moreTesting() {
echo "llamada a BaseClass::moreTesting()\n";
}
}
class ChildClass extends BaseClass {
public function moreTesting() {
echo "llamada a ChildClass::moreTesting()\n";
}
}
// Devuelve un error Fatal: Cannot override final method BaseClass::moreTesting()
?>
Ejemplo #2 Ejemplo de clase Final
<?php
final class BaseClass {
public function test() {
echo "llamada a BaseClass::test()\n";
}
// Aquí no importa si definimos una función como final o no
final public function moreTesting() {
echo "llamada a BaseClass::moreTesting()\n";
}
}
class ChildClass extends BaseClass {
}
// Devuelve un error Fatal: Class ChildClass may not inherit from final class (BaseClass)
?>
Nota: Las propiedades no pueden declararse como final. Sólo pueden las clases y los métodos.
Clonación de Objetos
No siempre se desea crear una copia de un objeto replicando todas sus propiedades completamente.
Un buen ejemplo que ilustra la necesidad de contar con un constructor de copias, sería si tuviéramos
un objeto que represente una ventana en GTK y el objeto almacene los recursos de esta ventana
GTK, de forma que cuando creas un duplicado el comportamiento esperado sería una nueva ventana
con las mismas propiedades, y que el nuevo objeto referencie a los recursos de la nueva ventana.
Otro ejemplo es si un objeto hace referencia a otro objeto necesario, de forma que cuando se realiza
una réplica del objeto principal, se espera que se cree una nueva instancia de este otro objeto, de
forma que la réplica tenga su propia copia
Para crear una copia de un objeto se utiliza la palabra clave clone (que invoca, si fuera posible, al
método __clone() del objeto). No se puede llamar al método__clone() de un objeto directamente.
$copia_de_objeto = clone $objeto;
Cuando se clona un objeto, PHP5 llevará a cabo una copia superficial de las propiedades del objeto.
Las propiedades que sean referencias a otras variables, mantendrán las referencias.
void __clone ( void )
Una vez que la clonación ha finalizado, se llamará al método __clone() del nuevo objeto (si el
método __clone() estuviera definido), para permitirle realizar los cambios necesarios sobre sus
propiedades.
Ejemplo #1 Clonación de un objeto
<?php
class SubObject
{
static $instances = 0;
public $instance;
public function __construct() {
$this->instance = ++self::$instances;
}
public function __clone() {
$this->instance = ++self::$instances;
}
}
class MyCloneable
{
public $object1;
public $object2;
function __clone()
{
// Forzamos la copia de this->object, si no
// hará referencia al mismo objeto.
$this->object1 = clone $this->object1;
}
}
$obj = new MyCloneable();
$obj->object1 = new SubObject();
$obj->object2 = new SubObject();
$obj2 = clone $obj;
print("Objeto Original:\n");
print_r($obj);
print("Objeto Clonado:\n");
print_r($obj2);
?>
El resultado del ejemplo sería:
Objeto Original:
MyCloneable Object
(
[object1] => SubObject Object
(
[instance] => 1
)
[object2] => SubObject Object
(
[instance] => 2
)
)
Objeto Clonado:
MyCloneable Object
(
[object1] => SubObject Object
(
[instance] => 3
)
[object2] => SubObject Object
(
[instance] => 2
)
)
Comparación de Objetos
En PHP 5, la comparación de objetos es más complicada que en PHP 4, y en mayor concordancia con
lo que cabe esperar de un Lenguaje Orientado a Objetos (tenga en cuenta que PHP lo es).
Al utilizar el operador de comparación (==), se comparan de una forma sencilla las variables de cada
objeto, es decir: Dos instancias de un objeto son iguales si tienen los mismos atributos y valores, y
son instancias de la misma clase.
Por otra parte, cuando se utiliza el operador identidad (===), las variables de un objeto son
idénticas sí y sólo sí hacen referencia a la misma instancia de la misma clase.
Un ejemplo aclarará estas reglas.
Ejemplo #1 Ejemplo de comparación de objetos en PHP 5
<?php
function bool2str($bool)
{
if ($bool === false) {
return 'FALSO';
} else {
return 'VERDADERO';
}
}
function
{
echo
echo
echo
echo
}
compararObjetos(&$o1, &$o2)
'o1
'o1
'o1
'o1
== o2 : ' . bool2str($o1 == $o2) .
!= o2 : ' . bool2str($o1 != $o2) .
=== o2 : ' . bool2str($o1 === $o2)
!== o2 : ' . bool2str($o1 !== $o2)
class Bandera
{
public $bandera;
function Bandera($bandera = true) {
$this->bandera = $bandera;
}
}
class OtraBandera
{
public $bandera;
function OtraBandera($bandera = true) {
$this->bandera = $bandera;
}
}
$o
$p
$q
$r
=
=
=
=
new Bandera();
new Bandera();
$o;
new OtraBandera();
echo "Dos instancias de la misma clase\n";
compararObjetos($o, $p);
echo "\nDos referencias a la misma instancia\n";
compararObjetos($o, $q);
echo "\nInstancias de dos clases diferentes\n";
"\n";
"\n";
. "\n";
. "\n";
compararObjetos($o, $r);
?>
El resultado del ejemplo sería:
Dos instancias de la misma clase
o1 == o2 : VERDADERO
o1 != o2 : FALSO
o1 === o2 : FALSO
o1 !== o2 : VERDADERO
Dos referencias a la misma instancia
o1 == o2 : VERDADERO
o1 != o2 : FALSO
o1 === o2 : VERDADERO
o1 !== o2 : FALSO
Instancias de dos clases diferentes
o1 == o2 : FALSO
o1 != o2 : VERDADERO
o1 === o2 : FALSO
o1 !== o2 : VERDADERO
Nota:
Las extensiones pueden definir sus propias reglas para la comparación de sus objetos.
Implicación de Tipos
Desde PHP 5 se incorpora la implicación de tipos. Ahora, las funciones pueden obligar a que sus
parámetros sean objetos (especificando el nombre de la clase en el prototipo de la función),
interfaces, arrays (desde PHP 5.1) o tipos callable (despe PHP 5.4). Sin embargo, si se
usa NULL como el valor predeterminado del parámetro, será permitido como un argumento para
llamada posterior.
Si se especifica una clase o una interfaz como tipo implicado también se permitirán todos sus hijos o
implementaciones too.
La implicación de tipos no puede usarse con tipos escalares como int o string. Tampoco están
permitidos los Traits.
Ejemplo #1 Ejemplos de Implicación de Tipos
<?php
// Una clase de ejemplo
class MiClase
{
/**
* Una función de prueba
*
* El primer parámetro debe ser un objeto del tipo OtraClase
*/
public function prueba(OtraClase $otraclase) {
echo $otraclase->var;
}
/**
* Otra función de prueba
*
* El primer parámetro debe ser un array
*/
public function prueba_array(array $array_entrada) {
print_r($array_entrada);
}
/**
* El primer parámetro debe ser un iterador
*/
public function prueba_interface(Traversable $iterador) {
echo get_class($iterador);
}
/**
* El primer parámetro debe ser de tipo callable
*/
public function prueba_callable(callable $callback, $data) {
call_user_func($callback, $data);
}
}
// Otra clase de ejemplo
class OtraClase {
public $var = 'Hola Mundo';
}
?>
Si no se satisface el type hint, se produce un error fatal capturable
<?php
// Una instancia de cada clase
$miclase = new MiClase;
$otraclase = new OtraClase;
// Error Fatal: El argumento 1 debe ser un objeto de la clase OtraClase
$miclase->prueba('hola');
// Error Fatal: El argumento 1 debe ser una instancia de OtraClase
$foo = new stdClass;
$miclase->prueba($foo);
// Error fatal: El argumento 1 no puede ser null
$miclase->prueba(null);
// Funciona: Imprime en pantalla Hola Mundo
$miclase->prueba($otraclase);
// Error Fatal: El argumento 1 debe ser un array
$miclase->prueba('una cadena');
// Funciona: Imprime en pantalla el array
$miclase->prueba(array('a', 'b', 'c'));
// Funciona: Imprime en pantalla ArrayObject
$miclase->prueba_interface(new ArrayObject(array()));
// Funciona: Imprime en pantalla int(1)
$miclase->prueba_callable('var_dump', 1);
?>
Los tipos sugeridos tambíen se pueden usar con funciones:
<?php
// Una clase de ejemplo
class MiClase {
public $var = 'Hola Mundo';
}
/**
* Una función de prueba
*
* El primer parámetro debe ser un objeto del tipo MiClase
*/
function miFunción (MiClase $foo) {
echo $foo->var;
}
// Funciona
$miclase = new MiClase;
miFunción($miclase);
?>
Tipo implicado que acepta valores de tipo NULL:
<?php
/* Se acepta el valor NULL */
function prueba(stdClass $obj = NULL) {
}
prueba(NULL);
prueba(new stdClass);
?>
Enlace estático en tiempo de ejecución
Desde PHP 5.3.0, PHP incorpora una nueva funcionalidad llamada enlace estático en tiempo de
ejecución que permite hacer referencias a la clase en uso dentro de un contexto de herencia estática.
De forma más precisa, un enlace estático en tiempo de ejecución para funcionar almacena el nombre
de clase de la última llamada que no tenga "propagación". En el caso de las llamadas a métodos
estáticos, se trata de la clase a la que se llamó explícitamente (normalmente, la que precede al
operador ::); en los casos de llamadas a métodos que no son estáticos, se resolvería a la clase del
objeto. Una "llamada con propagación" es una llamada estática que está precedida
porself::, parent::, static::, o, si seguimos la jerarquía de clases, forward_static_call(). La
función get_called_class() puede utilizarse para obtener un string con el nombre de la clase que
realiza la llamada, y static:: revela cuál es su alcance.
Se le ha llamado "enlace estático en tiempo de ejecución" teniendo en cuenta un punto de vista
interno. "Enlace en tiempo de ejecución" viene del hecho de questatic:: ya resuelve a la clase en la
que se definió el método, sino que en su lugar se resolverá utilizando información en tiempo de
ejecución debido a que se puede utilizar (entre otras cosas) para las llamadas de métodos estáticos,
se le llamó también "enlace estático".
Limitaciones de self::
Las referencias estáticas que hay dentro de la clase en uso, como self:: o __CLASS__, se resuelven
empleando el nombre de la clase a la que pertenece la función:
Ejemplo #1 Uso de self::
<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
self::who();
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
?>
El resultado del ejemplo sería:
A
Uso de Enlace Estático en Tiempo de ejecución
Los enlaces estáticos en tiempo de ejecución tratan de resolver estas limitaciones empleando una
palabra clave que haga referencia a la clase que realizó la llamada en tiempo de ejecución. Es decir,
una palabra clave que en el ejemplo anterior permita hacer referencia desde test() a B. Se decidió
no crear una nueva palabra clave, por lo que en su lugar se ha utilizado la palabra reservada static.
Ejemplo #2 Uso básico de static::
<?php
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
static::who(); // He aquí el enlace estático en tiempo de ejecución
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
?>
El resultado del ejemplo sería:
B
Nota:
En contextos no estáticos, la clase que realiza la llamada será la clase del objeto instanciado. Dado
que $this-> tratará de invocar métodos privados en su mismo ámbito, el uso de static:: puede
provocar diferents resultados. Otra diferencia es que static:: sólo puede hacer referencia a
propiedades estáticas.
Ejemplo #3 Uso de static:: en un contexto no estático
<?php
class A {
private function foo() {
echo "exito!\n";
}
public function test() {
$this->foo();
static::foo();
}
}
class B extends A {
/* foo() se copiará en B, por lo tanto su ámbito seguirá siendo A
* y la llamada tendrá éxito */
}
class C extends A {
private function foo() {
/* se reemplaza el método original; el ámbito del nuevo es ahora C */
}
}
$b = new B();
$b->test();
$c = new C();
$c->test();
//falla
?>
El resultado del ejemplo sería:
exito!
exito!
exito!
Fatal error:
Call to private method C::foo() from context 'A' in /tmp/test.php on line 9
Nota:
En una llamada que se resuelva como estática, la resolución de enlaces estáticos en tiempo de
ejecución se dentendrá sin propagarse. Por otra parte, las llamadas estáticas que utilicen palabras
clave como parent:: o self:: sí propagarán la información.
Ejemplo #4 Llamadas que propagan y que no propagan
<?php
class A {
public static function foo() {
static::who();
}
public static function who() {
echo __CLASS__."\n";
}
}
class B extends A {
public static function test() {
A::foo();
parent::foo();
self::foo();
}
public static function who() {
echo __CLASS__."\n";
}
}
class C extends B {
public static function who() {
echo __CLASS__."\n";
}
}
C::test();
?>
El resultado del ejemplo sería:
A
C
C
Objetos y referencias
Uno de los puntos clave de la POO de PHP 5 que a menudo se menciona es que "por omisión los
objetos se pasan por referencia". Esto no es completamente cierto. Esta sección rectifica esa creencia
general, usando algunos ejemplos.
Una referencia en PHP es un alias, que permite a dos variables diferentes escribir sobre un mismo
valor. Desde PHP 5, una variable de tipo objeto ya no contiene el objeto en sí como valor.
Únicamente contiene un identificador del objeto que le permite localizar al objeto real. Cuando se
pasa un objeto como parámetro, o se devuelve como retorno, o se asigna a otra variable, las
distintas variables no son alias: guardan una copia del identificador, que apunta al mismo objeto.
Ejemplo #1 Referencias y Objetos
<?php
class A {
public $foo = 1;
}
$a = new A;
$b = $a;
// $a y $b son copias del mismo identificador
// ($a) = ($b) = <id>
$b->foo = 2;
echo $a->foo."\n";
$c = new A;
$d = &$c;
// $c y $d son referencias
// ($c,$d) = <id>
$d->foo = 2;
echo $c->foo."\n";
$e = new A;
function foo($obj) {
// ($obj) = ($e) = <id>
$obj->foo = 2;
}
foo($e);
echo $e->foo."\n";
?>
El resultado del ejemplo sería:
2
2
2
Serialización de objetos
serialización de objetos - objetos en sesiones
La función serialize() devuelve un string que contiene un flujo de bytes que representa cualquier
valor que se pueda almacenar en PHP. Por otra parte,unserialize() puede restaurar los valores
originales a partir de dicho string. Al utilizar serialize para guardar un objeto, almacenará todas las
variables de dicho objeto. En cambio los métodos no se guardarán, sólo el nombre de la clase.
Para poder deserializar ( unserialize()) un objeto, debe estar definida la clase de ese objeto. Es decir,
si se tiene un objeto de la clase A, y lo serializamos, se obtendrá un string que haga referencia a la
clase A y contenga todas las variables que haya en esta clase. Si se desea deseralizar en otro fichero,
antes debe estar presente la definición de la clase A. Esto se puede hacer, por ejemplo, escribiendo la
definición de la clase A en un fichero, para después o bien incluirlo, o bien hacer uso de la
función spl_autoload_register().
<?php
// classa.inc:
class A {
public $one = 1;
public function show_one() {
echo $this->one;
}
}
// page1.php:
include("classa.inc");
$a = new A;
$s = serialize($a);
// almacenamos $s en algún lugar en el que page2.php puede encontrarlo.
file_put_contents('store', $s);
// page2.php:
// se necesita para que unserialize funcione correctamente.
include("classa.inc");
$s = file_get_contents('store');
$a = unserialize($s);
// now use the function show_one() of the $a object.
$a->show_one();
?>
Si una aplicación está usando sesiones, y utiliza session_register() para registrar objetos, estos
objetos se serializarán automáticamente al final de cada página PHP, y se deserializan también
automáticamente en cada una de las siguientes peticiones. Esto significa que, una vez que formen
parte de la sesión, estos objetos se podrán utilizar en cualquier página de la aplicación. Sin embargo,
la función session_register(): ha sido borrada a partir de PHP 5.4.0
Si una aplicación serializa objetos para su uso posterior, se recomienda encarecidamente que se
incluya la definición de la clase en toda la aplicación. Si no se hiciera, se deserializaría el objeto sin
una definición de clase, lo cual daría como resultado que PHP definiera al objeto con la
clase__PHP_Incomplete_Class_Name, que no tiene métodos, haciendo que el objeto no fuera
útil.
Por tanto, si en el ejemplo anterior $a se guardara en una sesión mediante session_register("a"),
sería necesario incluir el fichero classa.inc en todas las páginas, no sólo en page1.php y page2.php.
Registro de cambios de POO
Aquí se registran los cambios del modelo de POO de PHP 5. Las descripciones y otras notas respecto
a estas nuevas funcionalidades están documentadas dentro de la documentación de POO 5.
Versión
Descripción
5.4.0
Cambiado: Si una clase abstracta define una firma para el constructor ahora se hará
cumplir.
5.3.3
Cambiado: Los métodos con el mismo nombre que el último elemento de un nombre de
clase perteneciente a un espacio de nombres ya no serán tratado como un constructor.
Este cambio no afecta a las clases que no pertenecen a un espacio de nombres.
5.3.0
Cambiado: Ya no es necesario que los valores por omisión de los métodos de una clase que
implemente un interfaz coincidan con los valores por omisión de los prototipos de la
interfaz.
5.3.0
Cambiado: Ahora es posible hacer referencia a la clase utilizando una variable (p.ej., echo
$nombreclase::constante;). La variable no puede contener como valor una palabra clave
(p.ej., self, parent o static).
5.3.0
Cambiado: Se emite un error de nivel E_WARNING si al sobrecargar un método mágico se le
declara como estático. Además, hace necesario que tengan visibilidad pública.
5.3.0
Cambiado: Antes de 5.3.0, las excepciones lanzadas en la función __autoload() no podían
capturarse en el bloque catch, y provocaban un error fatal. Ahora, las excepciones lanzadas
dentro de la función __autoload pueden capturarse en el bloque catch, con una única
salvedad. Si se lanza una excepción definida por el usuario, entonces esta excepción
debería estar disponible. Se puede utilizar recursivamente la función __autoload para
cargar automáticamente la clase de la excepción definida por el usuario.
5.3.0
Añadido: El método __callStatic.
5.3.0
Añadido: Soporte heredoc y nowdoc para constantes de clase y definición de propiedades.
Nota: los valores heredoc deben seguir las mismas reglas que las cadenas de dobles
comillas (p.ej., no contener variables).
5.3.0
Añadido: Enlaces estáticos en tiempo de ejecución.
5.3.0
Añadido: El método __invoke().
5.2.0
Cambiado: Al método __toString() sólo se le invocaba cuando se le combinaba con echo o
con print. Pero ahora, se le invoca en cualquier contexto de strings (p.ej, en printf() con el
modificador %s) pero no en contextos de otro tipo (p.ej. con el modificador %d). Desde
PHP 5.2.0, convertir objetos a string sin el método __toString emitirá un error de
Versión
Descripción
nivel E_RECOVERABLE_ERROR.
5.1.3
Cambiado: En versiones anteriores de PHP 5, se consideraba obsoleto el uso de var y
emitía un error de nivel E_STRICT. Ya no está obsoleto, y por tanto no emite el error.
5.1.0
Cambiado: Ahora se invoca al método estático __set_state() en las clases exportadas
por var_export().
5.1.0
Añadido: Los métodos __isset() y __unset().
Descargar