Academia.eduAcademia.edu

POO y las clases en PHP (segunda parte

En la sesión anterior trabajamos con la clase Database.php que gestiona la conexión a la base de datos y los diversos formularios de nuestra aplicación WEB.

POO y las clases en PHP (segunda parte) Prof. Dr. Jorge Domínguez Chávez En la sesión anterior trabajamos con la clase Database.php que gestiona la conexión a la base de datos y los diversos formularios de nuestra aplicación WEB. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <? php class Database { public $db ; // variable p ú blica que gestiona la conexion a la db private static $dns = " mysql : host = localhost ; dbname = tucoplast " ; private static $user = " root " ; private static $pass = " pumas " ; private static $instance ; public function __construct () { $this - > db = new PDO ( self :: $dns , self :: $user , self :: $pass ) ; } /* Evita el copiado del objeto . Patr ó n Singleton */ private function __clone () { } /* Funci ó n encargada de crear , si es necesario , el objeto . /* Funci ó n a llamar desde fuera de la clase para instanciar el objeto y utilizar sus m é todos */ public static function getInstance () { if (! isset ( self :: $instance ) ) { $object = __CLASS__ ; self :: $instance = new $object ; } return self :: $instance ; } } ?> La variable public $db; es pública y gestiona la conexion a la db, mientras que las siguientescuatro variables son privadas estáticas, sólo son reconocidas por la clase y NO fuera de ella. La function __construct () es llamada automáticamente al ser ejecutada la clase. La private function __clone() evita que la clase Database sea clonada o copiada; esto es hecho por seguridad. La public static function getInstance() es llamada fuera de la clase para instanciar el objeto y utilizar sus métodos, sin abrir un nuevo canal para ello. 1 1. 1 2 3 4 5 6 7 Formulario Clientes <? php include_once ( ' conexion . php ' ) ; $pdo = Database :: getInstance () ; $sql = " SELECT id , nombre , direccion , telefono FROM clientes order by id " ; $registro = $pdo - > db - > prepare ( $sql ) -> execute ( $sql ) ; ?> ¿Ahora, cómo trabaja realmente la clase, sus variables y funciones cada vez que invoquemos la clase conexion.php? A continuación le presentamos la teoría, no toda, de la programación orientada a objeto en PHP. 2. Introducción A partir de PHP 5 se incluye un modelo de objetos completo. Algunas de sus características son: visibilidad, clases y métodos abstractos y finales, métodos mágicos adicionales, interfaces, clonación y determinación de tipos. PHP trata los objetos igual que las referencias o manejadores, lo tanto cada variable contiene una referencia a un objeto en lugar copiarlo. Véanse los Objetos y referencias. Sugerencia Vea también Guía de entorno de usuario para nombres. 3. Lo básico 3.1. class Una clase se define por la palabra reservada class, seguida de un nombre, y enmarcados par de llaves las propiedades y métodos que le pertenecen. El nombre de clase es cualquier etiqueta válida, siempre y cuando no sea una palabra reservada de PHP. Un nombre válido de clase comienza con una letra o un guión bajo, seguido de una cantidad arbitraria de letras, números o guiones bajos. Una expresión regular tiene la siguiente forma: ^[azA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$. Una clase contiene sus propias constantes, variables (”propiedades”), y funciones (”métodos”). Ejemplo 1 Definición de una clase sencilla 1 2 3 4 5 6 7 8 9 10 11 <? php class ClaseSencilla { // Declaraci ó n de una propiedad public $var = ' un valor predeterminado ' ; // Declaraci ó n de un m é todo public function mostrarVar () { echo $this - > var ; } } ?> 2 La pseudovariable $this está disponible cuando un método es invocado dentro del contexto de un objeto. $this es una referencia al objeto invocador (usualmente el objeto al cual el método pertenece, aunque puede ser cualquier otro objeto si el método es llamado estáticamente desde un objeto secundario). A partir de PHP 7.0.0, la llamada estática a un método no estático desde un contexto incompatible resulta en que $this no esté definido dentro del método. Una llamada estática a un método no estático desde un contexto no compatible está obsoleta desde PHP 5.6.0. A partir de PHP 7.0.0, una llamada estática a un método no estático está obsoleta en general (incluso si se llama desde un contexto compatible). Antes de PHP 5.6.0, tales llamadas ocasionaban un aviso de estrictez. Ejemplo 2 Algunos ejemplos de la pseudovariable $this Se asume que para este ejemplo error_reporting está inhabilitado; de lo contrario, el código emite avisos de estrictez y obsolescencia, respectivamente, dependiendo de la versión de PHP. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <? 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 () { A :: foo () ; } } $a = new A () ; $a - > foo () ; A :: foo () ; $b = new B () ; $b - > bar () ; B :: bar () ; ?> Salida del ejemplo anterior en PHP 5: 1 2 3 4 $this $this $this $this est á definida ( A ) no est á definida . est á definida ( B ) no est á definida . Salida del ejemplo anterior en PHP 7: 1 2 $this est á definida ( A ) $this no est á definida . 3 $this no est á definida . $this no est á definida . 3 4 3.2. new Para crear una instancia1 de una clase debe emplear la palabra reservada new. Un objeto se crea siempre a menos que el objeto tenga un constructor que arroje una excepción en caso de error. Las clases deben estar definidas antes de la instanciación. Si se emplea un string que contenga el nombre de una clase con new, se crea una nueva instancia de esa clase. Si la clase estuviera en un espacio de nombres, debe utilizar su nombre completo al realizar esto. Ejemplo 3 Creación de una instancia <? php $instancia = new ClaseSencilla () ; // ver ejemplo 1 1 2 3 4 5 6 7 // Esto tambi é n se puede hacer con una variable : $nombreClase = ' ClaseSencilla ' ; $instancia = new $nombreClase () ; // new ClaseSencilla () ?> En el contexto de una clase, es posible crear un nuevo objeto con new self y new parent. Cuando se asigna una instancia ya creada de una clase a una nueva variable, ésta última accederá a la misma instancia que el objeto que le fue asignado. Esta conducta es la misma que cuando se pasan instancias a una función. Se puede realizar una copia de un objeto ya creado a través de la clonación del mismo. Ejemplo 4 Asignación de objetos <? php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 $instancia = new ClaseSencilla () ; $asignada = $instancia ; $referencia =& $instancia ; $instancia - > var = ' $asignada tendr á este valor ' ; $instancia = null ; // $instancia y $referencia son null var_dump ( $instancia ) ; var_dump ( $referencia ) ; var_dump ( $asignada ) ; ?> El resultado del ejemplo es: NULL NULL object ( ClaseSencilla ) #1 (1) { [ " var " ]= > string (27) " $asignada tendr á este valor " 1 2 3 4 1 Podemos pensar en instancia como una copia independiente de la clase. 4 5 } PHP 5.3.0 introdujo un par de formas nuevas para crear instancias de un objeto. Ejemplo 5 Creación de nuevos objetos 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <? php class Prueba { static public function getNew () { return new static ; } } class Hija extends Prueba {} $obj1 = new Prueba () ; $obj2 = new $obj1 ; var_dump ( $obj1 !== $obj2 ) ; $obj3 = Prueba :: getNew () ; var_dump ( $obj3 instanceof Prueba ) ; $obj4 = Hija :: getNew () ; var_dump ( $obj4 instanceof Hija ) ; ?> El resultado del ejemplo es: 1 2 3 bool ( true ) bool ( true ) bool ( true ) PHP 5.4.0 introdujo la posibilidad de acceder a un miembro de un objeto recién crecado en una única expresión. Ejemplo 6 Acceder a un mimebro de un objeto recién creado 1 2 3 <? php echo ( new DateTime () ) -> format ( ' Y ' ) ; ?> El resultado del ejemplo es similar a: 1 4. 2016 Propiedades y métodos Las propiedades y métodos de una clase viven en «espacios de nombres» diferentes, por tanto, es posible tener una propiedad y un método con el mismo nombre. Al hacer referencia tanto a una propiedad como a un método se utiliza la misma notación, y si se accederá a la propiedad o se llamará al método, solamente depende del contexto, es decir, si el empleo es el acceso a una variable o la llamada a una función. Ejemplo 7 Acceso a propiedad contra llamada a método 5 1 2 3 4 5 6 7 8 9 10 class Foo { public $bar = ' propiedad ' ; public function bar () { return ' m é todo ' ; } } $obj = new Foo () ; echo $obj - > bar , PHP_EOL , $obj - > bar () , PHP_EOL ; El resultado del ejemplo es: propiedad método Esto significa que llamar a una función anónima que ha sido asignada a una propiedad no es posible directamte. En su lugar, la propiedad ha de ser asignada primero a una variable, por ejemplo. A partir de PHP 7.0.0, es posible llamar a dicha propiedad directamente encerrándola entre paréntesis. Ejemplo 8 Llamar a una función anónima almacenada en una propiedad 1 2 3 4 5 6 7 8 9 class Foo { public $bar ; public function $ __construct () $ { $this - > bar = function () { return 42; }; } } // A partir de PHP 5.3.0: 1 2 3 $obj = new Foo () ; $func = $obj - > bar ; echo $func () , PHP_EOL ; // Alternativamente, a partir de PHP 7.0.0: 1 echo ( $obj - > bar ) () , PHP_EOL ; El resultado del ejemplo es: 42 5. extends Una clase hereda los métodos y propiedades de otra clase empleando la palabra reservada extends en la declaración de la clase. No es posible la extensión de múltiples clases; una clase sólo hereda 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 madre. Sin embargo, si la clase madre definió un método como final, éste no será sobrescrito. Es posible acceder a los métodos sobrescritos o a las propiedades estáticas 6 haciendo referencia a ellos con parent::. Cuando se sobrescriben métodos, la firma de los parámetros sería la misma o PHP generará un error de nivel E_STRICT. Esto no se aplica a los constructores, los cuales permiten la sobrescritura con diferentes parámetros. Ejemplo 9 Herencia de clases sencilla 1 2 3 4 5 6 7 8 9 10 11 12 <? php class ClaseExtendida extends ClaseSencilla { // Redefinici ó n del m é todo padre function mostrarVar () { echo ' Clase extendida \ n ' ; parent :: mostrarVar () ; } } $extendida = new ClaseExtendida () ; $extendida - > mostrarVar () ; ?> El resultado del ejemplo es: 1 2 3 Clase extendida un valor predeterminado :: class Desde PHP 5.5, también se emplea la palabra reservada class para la resolución de nombres de clases. Se puede obtener un string con el nombre completamente cualificado de la clase NombreClase utilizando NombreClase::class. Esto es particularmete útil con clases en espacios de nombres. Ejemplo 10 Resolución de nombres de clases 1 2 3 4 5 6 7 8 <? php namespace NS { class NombreClase { } echo NombreClase :: class ; } ?> El resultado del ejemplo es: NS\NombreClase Nota: La resolución de nombres de clases con ::class es una transformación durante la compilación. Esto significa que, en el instante de crear el string del nombre de la clase, aún no se ha realizado ninguna autocarga. Como consecuencia, los nombres de clases se expanden incluso si la clase no existe. No se emite ningún error en tal caso. 6. Propiedades Las variables pertenecientes a una clase 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 7 ”propiedades”. Éstas se definen usando una de las palabras reservadas 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 durante la compilación y no depender de información generada en la ejecución. Véase la 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 reservada 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 se emite 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 como public. Dentro de los métodos de una clase, se puede acceder a las propiedades no estáticas utilizando >(el operador de objeto): $this->propiedad (donde propiedad es el nombre de la propiedad). A las propiedades estáticas se puede acceder utilizando :: (doble dos puntos): self::$propiedad. Véase la palabra reservada ’static’para más información sobre la diferencia entre propiedades estáticas y no estáticas. La pseudovariable $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 invocador (usualmente el objeto al cual pertenece el método, aunque puede que sea otro objeto si el método es llamado estáticamente desde el contexto de un objeto secundario). Ejemplo 11 Declaración de propiedades 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <? php class ClaseSencilla { // V á lido a partir de PHP 5.6.0: public $var1 = ' hola ' . ' mundo ' ; // V á lido a partir de PHP 5.3.0: public $var2 = <<< EOD hola mundo EOD ; // V á lido a partir de PHP 5.6.0: public $var3 = 1+2; // Declaraciones de propiedades inv á lidas : public $var4 = self :: miM é todoEst á tico () ; public $var5 = $myVar ; // Declaraciones de propiedades v á lidas : public $var6 = miConstante ; public $var7 = array ( true , false ) ; // V á lido a partir de PHP 5.3.0: public $var8 = <<<' EOD ' hola mundo EOD ; } ?> 8 Nota: Existen varias funciones interesantes para manipular clases y objetos. Puede ser interesante echarle un vistazo a las Funciones de clases/objetos. A partir de PHP 5.3.0, se puede utilizar heredocs y nowdocs en cualquier contexto de datos estáticos, incluyendo la declaración de propiedades. Ejemplo 12 Uso de nowdoc para inicializar una propiedad 1 2 3 4 5 6 7 8 9 10 11 <? php class foo { // A paritr de PHP 5.3.0 public $bar = <<<' EOT ' bar EOT ; public $baz = <<< EOT baz EOT ; } ?> Nota: Se añadio soporte para Nowdoc y Heredoc en PHP 5.3.0. 7. Constantes de clases Es posible definir valores constantes en función de cada clase manteniéndola invariable. Las constantes se diferencian de las variables comunes en que no utilizan el símbolo $ al declararlas o emplearlas. La visibilidad predeterminada de las constantes de clase es public. El valor debe ser una expresión constante, no (por ejemplo) una variable, una propiedad o una llamada a una función. También es posible que las interfaces tengan constantes. Consulte los ejemplos de la documentación de interfaces. A partir de PHP 5.3.0, es posible referirse a una clase utilizando una variable. El valor de la variable no puede ser una palabra reservada (p.ej., self, parent o static). Observe que las constantes de clase están asignadas una vez por clase, y no por cada instancia de la clase. Ejemplo 13 Definición y uso de una constante 1 2 3 4 5 6 7 8 9 10 11 12 13 <? php class MiClase { const CONSTANTE = ' valor constante ' ; function mostrarConstante () { echo self :: CONSTANTE . ' ' \ n ' ' ; } } echo MiClase :: CONSTANTE . ' ' \ n ' ' ; $nombreclase = ' ' MiClase ' ' ; echo $nombreclase :: CONSTANTE . ' ' \ n ' ' ; // A partir de PHP 5.3.0 9 14 15 16 17 18 19 $clase = new MiClase () ; $clase - > mostrarConstante () ; echo $clase :: CONSTANTE . ' ' \ n ' ' ; // A partir de PHP 5.3.0 ?> Ejemplo 14 Datos estáticos 1 2 3 4 5 6 7 8 9 10 11 12 <? php class foo { // A partir const BAR = bar EOT ; // A partir const BAZ = baz EOT ; } ?> de PHP 5.3.0 <<<' EOT ' de PHP 5.3.0 <<< EOT Nota: El soporte para la inicialización de constantes con la sintaxis de Heredoc y Nowdoc fue agregado en PHP 5.3.0. La constante especial ::class está disponible a partir de PHP 5.5.0, y permite la resolución de nombres de clase completamente cualificados en la compilación. Esto es útil para clases en espacios de nombres: Ejemplo 15 Ejemplo de ::class en espacio de nombres 1 2 3 4 5 6 7 8 <? php namespace foo { class bar { } echo bar :: class ; // foo \ bar } ?> Ejemplo 16 Expresión constante 1 2 3 4 5 6 7 8 9 10 <? php const UNO = 1; class foo { // A partir de PHP 5.6.0 const DOS = UNO * 2; const TRES = UNO + self :: DOS ; const SENTENCIA = ' El valor de TRES es ' . self :: TRES ; } ?> Es posible proporcionar una expresión escalar que implique literales numéricos y de string y/o constantes en el contexto de una constante de clase. 10 Nota: El soporte para expresiones constantes se añadió en PHP 5.6.0. Ejemplo 17 Modificadores de visibilidad de constantes de clase 1 2 3 4 5 6 7 8 9 <? php class Foo { // A partir de PHP 7.1.0 public const BAR = ' bar ' ; private const BAZ = ' baz ' ; } echo Foo :: BAR , PHP_EOL ; echo Foo :: BAZ , PHP_EOL ; ?> Salida del ejemplo anterior en PHP 7.1: 1 2 bar Fatal error : Uncaught Error : Cannot access private const Foo :: BAZ in \ dot Nota: A partir de PHP 7.1.0, están permitidos los modificadores de visibilidad para constantes de clase. Es posible declarar una constante en una clase base, y sobreescribirla un hijo, y acceder al valor correcto de la constante (const) desde el método static a través de get_called_class: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <? php abstract class dbObject { const TABLE_NAME = ' undefined ' ; public static function GetAll () { $c = get_called_class () ; return ' ' SELECT * FROM `' ' . $c :: TABLE_NAME . ' ' `' ' ; } } class dbPerson extends dbObject { const TABLE_NAME = ' persons ' ; } class dbAdmin extends dbPerson { const TABLE_NAME = ' admins ' ; } echo dbPerson :: GetAll () . ' ' <br > ' ' ;// output : ' ' SELECT * FROM ` persons ` ' ' echo dbAdmin :: GetAll () . ' ' <br > ' ' ;// output : ' ' SELECT * FROM ` admins ` ' ' ?> 11 8. Autocarga de clases Muchos desarrolladores que escriben aplicaciones orientadas a objetos crean un archivo fuente de PHP para cada definición de clase. Una de las mayores molestias es tener que hacer una larga lista de inclusiones al comienzo de cada script (uno por cada clase). En PHP 5 esto ya no es necesario. La función spl_autoload_register() registra cualquier número de autocargadores, posibilitando que las clases e interfaces sean cargadas automáticamente si no están definidas actualmente. Al registrar autocargadores, a PHP se le da una última oportunidad de cargar las clases o interfaces antes de que falle por un error. Sugerencia Aunque la función __autoload() también puede ser empleada para autocargar clases e interfaces, es preferible utilizar la función spl_autoload_register(). Esto es debido a que es una alternativa más flexible (posibilitando que se pueda especificar cualquier número de autocargadores en la aplicación, tales como los de las bibliotecas de terceros). Por esta razón, se desaconseja el uso de __autoload(), ya que podría estar obsoleta 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, resultando en un error fatal. Desde 5.3 en adelante, esto es posible simpre que, si se lanza una excepción personalizada, esté disponible la clase de la excepción personalizada. La función __autoload() podría utilizarse recursivamente para cargar la clase de 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(), este 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 18 Autocarga Este ejemplo intenta cargar las clases MiClase1 y MiClase2 desde los archivos MiClase1.php y MiClase2.php, respectivamente. 1 2 3 4 5 6 7 8 <? php s p l _ a u t o l o a d _ r e g i s t e r ( function ( $nombre_clase ) { include $nombre_clase . ' . php ' ; }) ; $obj = new MiClase1 () ; $obj2 = new MiClase2 () ; ?> Ejemplo 19 Otro ejemplo de autocarga Este ejemplo intenta cargar la interfaz IPrueba. 1 2 3 4 5 6 <? php s p l _ a u t o l o a d _ r e g i s t e r ( function ( $nombre ) { var_dump ( $nombre ) ; }) ; 12 7 8 9 10 11 12 13 14 15 class Foo implements IPrueba { } /* string (7) ' ' IPrueba ' ' Fatal error : Interface ' IPrueba ' not found in ... */ ?> Ejemplo 20 Autocarga con manejo de excepciones para 5.3.0+ Este ejemplo lanza una excepción y demuestra los bloques try/catch. 1 2 3 4 5 6 7 8 9 10 11 12 <? php s p l _ a u t o l o a d _ r e g i s t e r ( function ( $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 es: 1 2 Intentando cargar ClaseNoCargable . Imposible cargar ClaseNoCargable . Ejemplo 21 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. 1 2 3 4 5 6 7 8 9 10 11 12 <? php s p l _ a u t o l o a d _ r e g i s t e r ( function ( $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 es: 1 2 3 4 Intentando cargar ClaseNoCargable . Intentando cargar Excepci ó nAusente . Fatal error : Class ' Excepci ó nAusente ' not found in t e s t E x c e p c i o n A u s e n t e . php on line 4 Ver también 13 unserialize() unserializec allbackf unc spla utoloadr egister() spla utoload() __autoload() 9. 9.1. Constructores y destructores Constructor __construct([mixedargs = ” ” [, ...]]) : void 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: Los constructores padres no son llamados implícitamente si la clase hija define un constructor. Para ejecutar un constructor padre, se requiere invocar a parent:: __construct() desde el constructor hijo. Si el hijo no define un constructor, entonces se puede heredar de la clase madre como un método de clase normal (si no fue declarada como privada). Ejemplo 22 Utilización de nuevos constructores unificados 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <? php class BaseClass { function $ __construct () $ { print ' ' En el constructor BaseClass \ n ' ' ; } } class SubClass extends BaseClass { function $ __construct () $ { parent :: $ __construct () $ ; print ' ' En el constructor SubClass \ n ' ' ; } } class OtherSubClass extends BaseClass { // heredando el constructor BaseClass } // En el constructor BaseClass $obj = new BaseClass () ; // En el constructor BaseClass // En el constructor SubClass $obj = new SubClass () ; 14 26 27 28 // En el constructor BaseClass $obj = new OtherSubClass () ; ?> Por motivos de retrocompatibilidad con PHP 3 y PHP 4, si PHP no puede encontrar una función __construct() de una clase dada, se buscará la función constructora del estilo antiguo, por 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 semáticas. Advertencia Los constructores del estilo antiguo están OBSOLETOS en PHP 7.0, por lo que serán eliminados en una futura versión. Se debería utilizar siempre __construct() en código nuevo. 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 23 Constructores en clases pertenecientes a un nombre de espacios 1 2 3 4 5 6 7 8 9 <? 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 } } ?> 9.2. Destructor __destruct(void) : 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 24 Destructor 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <? php class M yD e st r uc t a bl e Cl a s s { function $ __construct () $ { print ' ' En el constructor \ n ' ' ; $this - > name = ' ' M yD e s tr u ct a b le C la s s ' ' ; } function __destruct () { print ' ' Destruyendo ' ' . $this - > name . ' ' \ n ' ' ; } } $obj = new M yD e st r u ct a bl e C la s s () ; ?> 15 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. También como los constructores, una clase child puede heredar el destructor de los padres si no implementa uno propio. 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. 10. Visibilidad La visibilidad de una propiedad, un método o (a partir de PHP 7.1.0) una constante se puede definir anteponiendo a su declaración una de las palabras reservadas public, protected o private. A los miembros de clase declarados como ’public’se puede acceder desde donde sea; a los miembros declarados como ’protected’, solo desde la misma clase o mediante clases heredadas. A los miembros declarados como ’private’únicamente se puede acceder desde la clase que los definió. 10.1. Visibilidad de propiedades Las propiedades de clases deben ser definidas como ’public’, ’privateó ’protected’. Si se declaran usando var, serán definidas como ’public’. Ejemplo 25 Declaración de propiedades 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 <? php /* * * Definici ó n de MyClass */ class MyClass { public $public = ' Public ' ; protected $protected = ' Protected ' ; private $private = ' Private ' ; function printHello () { echo $this - > public ; echo $this - > protected ; echo $this - > private ; } } $obj = new MyClass () ; echo $obj - > public ; echo $obj - > protected ; echo $obj - > private ; $obj - > printHello () ; // // // // Funciona bien Error Fatal Error Fatal Muestra Public , Protected y Private 16 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 /* * * Definici ó n de MyClass2 */ class MyClass2 extends MyClass { // Se pueden redeclarar las propiedades p ú blica y protegida , pero no la privada public $public = ' Public2 ' ; protected $protected = ' Protected2 ' ; function printHello () { echo $this - > public ; echo $this - > protected ; echo $this - > private ; } } $obj2 = new MyClass2 () ; echo $obj2 - > public ; // echo $obj2 - > protected ; // echo $obj2 - > private ; // $obj2 - > printHello () ; // Funciona bien Error Fatal Undefined Muestra Public2 , 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. 10.2. 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 26 Declaración de métodos 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <? 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 17 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 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 ' ' ; } 18 68 69 70 71 72 73 74 75 76 77 private function testPrivate () { echo ' ' Foo :: testPrivate \ n ' ' ; } } $myFoo = new Foo () ; $myFoo - > test () ; // Bar :: testPrivate // Foo :: testPublic ?> 10.3. Visibilidad de las constantes A partir de PHP 7.1.0, las constantes de clase se pueden definir como públicas, privadas o protegidas. Las constantes declaradas sin una visibilidad explítica serán definidas como públicas. Ejemplo 27 Declaración de constantes a partir de PHP 7.1.0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <? php /* * * Definir MiClase */ class MiClase { // Declarar una constante p ú blica public const MY_PUBLIC = ' public ' ; // Declarar una constante protegida protected const MY_PROTECTED = ' protected ' ; // Declarar una constante privada private const MY_PRIVATE = ' private ' ; public echo echo echo } function foo () { self :: MY_PUBLIC ; self :: MY_PROTECTED ; self :: MY_PRIVATE ; } $myclass = new MiClase () ; MiClase :: MY_PUBLIC ; // Funciona MiClase :: MY_PROTECTED ; // Error fatal MiClase :: MY_PRIVATE ; // Error fatal $myclass - > foo () ; // Funcionan Public , Protected y Private /* * * Definir MiClase2 */ class MiClase2 extends MiClase { // Esta es p ú blica function foo2 () { echo self :: MY_PUBLIC ; 19 36 37 38 39 40 41 42 43 44 echo self :: MY_PROTECTED ; echo self :: MY_PRIVATE ; // Error fatal } } $myclass2 = new MiClase2 ; echo MiClase2 :: MY_PUBLIC ; // Funciona $myclass2 - > foo2 () ; // Funcionan Public y Protected , pero no Private ?> 10.4. 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 28 Accediendo a miembros private del mismo tipo de objeto 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <? 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 es: 1 string (5) ' ' hola ' ' Método private accedido. 20 11. 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 29 Ejemplo de herencia 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <? 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 : ?> Ejemplo : <? php class A { // more code here 21 ' Foo : baz ' ' PHP is great ' ' Bar : baz ' ' PHP is great ' 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 } class B extends A { // more code here } class C extends B { // more code here } $someObj = new A () ; // no problems $someOtherObj = new B () ; // no problems $lastObj = new C () ; // still no problems ?> Ejemplo <? php class Person { public $name ; protected $age ; private $phone ; public function talk () { // Do stuff here } protected function walk () { // Do stuff here } private function swim () { // Do stuff here } } class Tom extends Person { /* Since Tom class extends Person class this means that class Tom is a child class and class person is the parent class and child class will inherit all public and protected members ( properties and methods ) from the parent class */ /* So class Tom will have these properties and methods */ // public $name ; // protected $age ; // public function talk () {} // protected function walk () {} 22 85 86 87 88 // but it will not inherit the private members // this is all what Object inheritance means } 12. 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 y static). 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 30 :: desde el exterior de la definición de la clase 1 2 3 4 5 6 7 8 9 10 <? 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 31 :: desde el interior de la definición de la clase 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <? 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 ' ; $classname :: doubleColon () ; // A partir de PHP 5.3.0 OtherClass :: doubleColon () ; ?> 23 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 32 Invocando a un método parent 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <? 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 . 12.1. La palabra reservada static Sugerencia Esta página describe el uso de la palabra reservada static para definir métodos y propiedades estáticos. static también se puede usar para definir 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 significados 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. 13. Métodos estáticos Debido a que los métodos estáticos se pueden invocar sin tener creada una instancia del objeto, la seudovariable $this no está disponible dentro de los métodos declarados como estáticos. Precaución En PHP 5, llamar a métodos no estáticos de forma estática genera una advertencia de nivel E_STRICT. Advertencia En PHP 7, llamar a métodos no estáticos de forma estática está obsoleto y generará una advertencia E_DEPRECATED. El soporte para las llamadas a métodos no estáticos de forma estática podría ser eliminado en el futuro. 24 Ejemplo 33 Método estático 1 2 3 4 5 6 7 8 9 10 11 <? php class Foo { public static function unMetodoEstatico () { // ... } } Foo :: unMetodoEstatico () ; $nombre_clase = ' Foo ' ; $nombre_clase :: unMetodoEstatico () ; // A partir de PHP 5.3.0 ?> 13.1. Propiedades estáticas No se puede acceder a las propiedades estáticas a través del objeto utilizando el operador flecha (->). 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 reservada (p.ej., self, parent y static). Ejemplo 34 Propiedad estática 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <? 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 ' ' ; definida print $foo :: $mi_static . ' ' \ n ' ' ; $nombreClase = ' Foo ' ; 25 // ' ' Propiedad ' ' mi_static no 25 26 27 28 29 30 print $nombreClase :: $mi_static . ' ' \ n ' ' ; // A partir de PHP 5.3.0 print Bar :: $mi_static . ' ' \ n ' ' ; $bar = new Bar () ; print $bar - > fooStatic () . ' ' \ n ' ' ; ?> 14. 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 final. Si la propia clase se define como final, entonces no se podrá heredar de ella. Ejemplo 35 Métodos Final 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <? 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 36 Clase Final 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <? 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 ) 26 16 ?> Nota: Las propiedades no pueden declararse como final. Sólo pueden las clases y los métodos. 15. 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. 1 $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. __clone ( void ): 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 37 Clonación de un objeto 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <? 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 . 27 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 $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 es: Objeto Original: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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 ) ) PHP 7.0.0 introdujo la posibilidad de acceder a un miembro del objeto recién clonado en una única expresión: Ejemplo 38 Acceder a un miembre del objeto recién clonado 1 2 3 4 <? php $dateTime = new DateTime () ; echo ( clone $dateTime ) -> format ( ' Y ' ) ; ?> 28 El resultado del ejemplo sería algo similar a: 1 2016 29