domingo, 16 de noviembre de 2014

[PHP]Control de salida

Por defecto, todo lo que se imprime en un script en PHP o cualquier HTML fuera de las etiquetas PHP (incluso al incluir archivos) se envia inmediatamente al navegador. 

El almacenamiento en buffer de salida (o control de salida, como el manual de PHP lo llama) es una caracteristica de PHP que anula este comportamiento. En lugar de enviar inmediatamente HTML al navegador web, la salida se colocara en el buffer - memoria temporal. Entonces, cuando el buffer se vacia, se envia al navegador web. Alli puede ser una mejora de rendimiento con el almacenamiento de buffer de salida, pero el principal beneficio es que se erradica esas molestas cabeceras "headers already sent". Algunas funciones header(), setcookie(), y session_start() - solo se pueden llamar si nada ha sido enviado al navegador. 

Con el almacenamiento en buffer de salida nada se enviara al navegador web hasta el final de la pagina, por lo que es libre de llamar a estas funciones en cualquier punto del script.

Para comenzar el almacenamiento de buffer de salida, invocamos la funcion ob_start(), una vez que usted lo llama, la salida de cada echo, print, y funciones similares llamadas seran enviadas al buffer de memoria en lugar del navegador web. Por el contrario, las cabeceras HTTP (como header() y setcookie()) no se almacenaran y funcionaran como de costumbre. Como conclusion del script, llamar a la funcion ob_end_flush() para enviar el buffer acumulado al navegador web. O bien, utilice la funcion ob_end_clean() para eliminar los datos almacenados sin enviarlos. Ambas funciones tienen efectos secundarios de desactivar el almacenamiento de buffer de salida. 

Un ejemplo de todo esto podria ser el siguiente:

 <?php
 ob_start();
 echo "Hola Mundo\n";
 setcookie("MiCookie","ASDF");
 ob_end_flush();
?>



En las versiones mas recientes de PHP, el almacenamiento en buffer de salida esta activado por defecto, el tamaño del buffer - el maximo numero de bytes almacenados en memoria - es 4,096, pero esto se puede cambiar en el archivo de configuracion en PHP. 

La funcion ob_get_contents() devolvera el buffer de modo que se puede asignar a una variable, en caso de necesidad.

La funcion ob_flush() enviara el contenido actual de la memoria al navegador web y luego lo desechara, lo que permite iniciarse un nuevo buffer. Esta funcion permite que los scripts mantengan tamaño de buffer mas moderados. Por el contrario ob_end_flush() apaga el almacenamiento del buffer de salida despues de enviar el buffer al navegador web. 

La funcion ob_clean() borra el contenido actual de la memoria sin detener el proceso de buffer.

PHP ejecutara automaticamente al final de la secuencia ob_end_flush() al final del script si no se hace lo contrario.

viernes, 14 de noviembre de 2014

[Parte 2] Programacion orientada a objetos con PHP

Teorías avanzadas

La herencia de objetos es cuando una clase se deriva de otra, al igual que los seres humanos heredan cualidades de sus padres. Por supuesto las "cualidades" en el mundo orientado a objetos son los atributos (variables) y métodos (funciones). A traves de la herencia, se puede definir una clase que se "nace" de los mismos atributos y metodos como la otra. La clase hija heredada puede incluso tener sus propias "cualidades" unicas que el padre no tiene.


La clase hijo hereda (es decir, tiene) todos los atributos y metodos de su clase padre.


Las clases hijo pueden tener sus propios miembros además de los que heredaron. De esta manera un hijo puede separarse (funcionalmente hablando) de su padre.

Indicando herencia en UML

En un diagrama de clases UML, la herencia es representada mediante una flecha entre las dos clases, como en las figuras anteriores. La flecha debe de ir de la subclase a la clase base (es decir, los puntos de flecha a los padres). 
Convencionalmente, la clase padre se coloca por encima de las clases hijas.

Terminologia de herencia

Con las definiciones de clase, los terminos principales son atributos y metodos, variables y funciones, respectivamente. La combinacion de atributos y metodos componen los miembros de una clase. Con la herencia tiene una clase padre y una clase hijo: esta ultima se hereda de la antigua. Tambien vera que estos son descritos como clase base o superclase y su clase derivada o subclase.

Pero la herencia no es necesariamente una relacion uno-a-uno. No hay limite para el numero de veces que la herencia puede ocurrir: multiples clases pueden ser heredades de la clase padre. O una clase puede ser hija de una clase hija. Esto hablando de la poderosa reutilizacion de codigo de la clase.



Una sola clase padre puede tener descendencia sin limite, cada una personalizada en su camino.


La herencia puede teoricamente tener profundidad ilimitada.

Una vez que se haya definido una clase que se hereda de otra, no se necesita mucho tiempo para comenzar pensando en lo agradable que seria si se comporta un poco de manera diferente. Puede añadir nuevos atributos y metodos, ¿Que pasa si usted quiere cambiar el comportamiento de los metodos de la clase padre? Seria un error al cambiar la definicion de la clase padre (presumiblemente funciona como deberia, y ademas otras clases se podrian heredar de la misma). En su lugar puede sobreescribir un metodo de la clase padre para personalizarlo para una nueva clase. Este es el polimorfismo, donde al llamar al mismo metodo puede tener resultados diferentes, dependiendo del tipo de objeto. 

La herencia de las clases

Una manera en que los objetos hacen una programacion mas rapida es la capacidad de utilizar una definicion de clase como base para otra. Este proceso se conoce como herencia.

Siguiendo con el ejemplo de la parte anterior donde teniamos una clase usuario que tenia de atributos id de usuario, correo electronico, contraseña y tiene los metodos de inicio de sesion y cierre de sesion, se podria crear otra clase llamada Administrador que es una extension de usuario. Junto con las variables y funciones mencionadas, un objeto Administrador podria tener tambien un atributo NiveldeAcceso y el metodo editarUsuario.

Este tipo de clases significa que las dos tienen una relacion, en la que Administrador es un tipo de usuario. Cuando estas en estas situaciones de diseño donde una cosa es simplemente un tipo mas especifico de otra cosa, usted probablemente querra usar herencia. 

Para crear una clase hija desde uno de los padres, hacemos uso de la palabra clave extends. Asumiendo que ya tiene definido el NombredeLaClase, usted puede crear una clase hija de este modo:

class ClaseHijo extends NombredeLaClase{}
Como esta escrito, la clase sera ClaseHijo y contendra todos los miembros de su padre, NombredeLaCLase. Ahora se puede modificar esta clase para adaptarla a sus necesidades especificas sin la alteracion de la clase original. Idealmente, una vez que ha creado una clase padre solida, que nunca tendra que modificar de nuevo, puede usar las clases hijos para adaptar el codigo a sus requisitos individuales.

La clase Administrador puede tener todos los mismos miembros que Usuario, al mismo tiempo que añade las suyas propias.

La palabra clave instanceof

La palabra clave instanceof puede ser usada para ver si es un objeto en particular de un cierto tipo de clase:

if($obj instanceof AlgunaClase){ ... 

El script de PHP debe tener acceso a la definicion AlgunaClase 

Para una implementacion de este ejemplo, vamos a comenzar con un ejemplo de mascotas (comprensible) algo tonto. Digamos que usted tiene 2 mascotas: un gato y un perro. Ambos animales tienen un nombre, y ambos comen y duermen. Los gatos difieren de los perros, ya que pueden trepar a los arboles y los perros difieren de los gatos en que pueden recuperar bolas. Ser capaz de describir estas cualidades y relaciones en un lenguaje sencillo conduce a la estructura de la herencia que debe crear:  




Un ejemplo de codigo seria el siguiente:


 <!DOCTYPE html>
<html lang="es">
<head>
 <meta charset="utf-8">
 <title>Mascotas</title>
</head>
<body>
<?php
 # Mascotas
 // Esta pagina define y usa clas clases mascota, gato y perro.

 # *** Clases *** #
 /*
 * Clase Mascota
 * Esta clase contiene un atributo:
 * nombre
 * Esta clase contiene tres metodos:
 * __construct()
 * comer()
 * dormir()
 */
 class Mascota{
  // Declaramos los atributos:
  public $nombre;

  // Constructor que asigna nombre a la mascota:
  function __construct($nombre_mascota){
   $this->nombre = $nombre_mascota;
  }

  // La mascota come:
  function comer(){
   echo "<p>$this->nombre esta comiendo.</p>";
  }

  // La mascota puede domir:
  function dormir(){
   echo "<p>$this->nombre esta durmiendo</p>";
  }
 } // Fin de la clase mascota

 /* La clase Perro extiende la clase Mascota
 * Perro tiene un metodo adicional: recuperar()
 */
 class Perro extends Mascota{
  function recuperar(){
   echo "<p>$this->nombre recupera la bola.</p>";
  }
 } // Fin de la clase Perro

 /* La clase Gato extiende la clase Mascota
 * Gato agrega un metodo adicional: subir()
 */
 class Gato extends Mascota{
  function subir(){
   echo "<p>$this->nombre esta subiendo</p>";
  }
 } // Fin de la clase Gato

 # *** Fin de las clases *** #


 // Creamos un Perro:
 $Perro = new Perro('Satchel');
 // Creamos un Gato:
 $Gato = new Gato('Bucky');

 // Darles de comer:
 $Perro->comer();
 $Gato->comer();

 // Hora de la siesta:
 $Perro->dormir();
 $Gato->dormir();

 // Hacer cosa especifica de los animales:
 $Perro->recuperar();
 $Gato->subir();

 // Eliminamos los objetos:
 unset($Perro,$Gato);

?>
</body>
</html>


El codigo es muy basico y se entiende perfectamente ya que todo lo hemos visto anteriormente, lo unico que hay que explicar aqui es que extendemos la clase Mascota para tener dos clases personalizadas Perro y Gato las cuales tienen unos metodos diferentes ya que un Gato y un Perro realizan diferentes acciones.





Heredando Constructores y Destructores

El ejemplo Mascota muestra como podemos crear una clase (Mascota) y que de la misma se deriven otras clases (Perro, Gato). Estas clases pueden tener sus propios metodos, unicos a ellos mismos, tal como subir() y recuperar().


Hay dos metodos que son muy comunes en muchas clases: Los constructores y los destructores (los hemos visto anteriormente). La clase Mascota tiene un constructor, pero no hay necesidad de un destructor. ¿Que pasaria si el Gato o el Perro tuvieran un constructor? Por definicion este metodo se llama siempre __construct(). ¿Como determinamos que version del constructor de PHP ejecutamos?




Cuando se crea un objeto, PHP siempre llamara al constructor de ese objeto.

Como regla general, PHP siempre llamara al constructor para la clase. La misma regla se aplica para los destructores. Ademas, a diferencia de otros lenguajes de POO, en PHP, cuando se crea un objeto de una clase hijo, el constructor de la clase padre no se llamara automaticamente. 

Vamos a extender la clase Rectangulo que hicimos anteriormente, para crear una clase Cuadrado.




 <!DOCTYPE html>
<html lang="es">
<head>
 <meta charset="utf-8">
 <title>Cuadrado</title>
</head>
<body>
<?php
 // Esta pagina declara y usa la clase Cuadrado que es derivada de la clase Rectangulo
 
 // incluimos la primera definicion de la clase:
 require('Rectangulo.php');
 class Cuadrado extends Rectangulo{
  // Creamos la clase Cuadrado
  // Este valor es asignado para el rectangulo con los atributos ancho y alto
  function __construct($lado = 0){
   $this->ancho = $lado;
   $this->alto = $lado;
  } 

 }// Fin de la clase Cuadrado.

 // Dimensiones del Rectangulo:
 $ancho = 21;
 $alto = 98;

 // Imprimimos una pequeña introduccion:
 echo "<h2>Con un ancho de $ancho y un alto de $alto ...</h2>";

 // Creamos un nuevo Rectangulo:
 $r = new Rectangulo($ancho,$alto);

 // Imprimimos el area:
 echo '<p>El area del rectangulo es:'.$r->obtenerArea().'</p>';

 // Imprimimos el perimetro
 echo '<p>El perimetro del rectangulo es:'.$r->obtenerPerimetro().'</p>';

 // Dimensiones del cuadrado:
 $lado = 60;

 // Imprimimos una pequeña introduccion:
 echo "<h2>Con cada lado $lado ...</h2>";

 // Creamos un nuevo objeto:
 $c = new Cuadrado($lado);

 // Imprimimos el area:
 echo '<p>El area del cuadrado es:'.$c->obtenerArea().'</p>';

 // Imprimimos el perimetro
 echo '<p>El perimetro del cuadrado es:'.$c->obtenerPerimetro().'</p>';

 // Eliminamos los objetos:
 unset($r,$c); 
?>
</body>
</html>







Incluso si el constructor de la clase Cuadrado toma un solo argumento, el uso de los metodos del Rectangulo, y el resultado final, funcionan de la misma manera. 

Diseño de herencia simple

Cada vez que una clase hereda otra, el resultado debe ser una descripcion mas especifica de una cosa. Por lo tanto, si nos vamos a Mascota para Perro o Gato y del Rectangulo para Cuadrado. Al decidir donde colocar los metodos, incluyendo constructores y destructores, usted tiene que pensar si esa funcionalidad es universal o mas especifico.

En el ejemplo Mascota, el constructor establece el nombre de la mascota, que es universal para todas las mascotas. Asi que Perro y Gato no necesitan sus propios constructores. En el ejemplo Rectangulo, su constructor establece el alto y el ancho. Pero un cuadrado no tiene dos dimensiones distintas, por ello debemos tener un nuevo constructor para que sea valido.

Notas:

Los constructores nunca devuelven nada.

Una recomendacion de POO es que todas las clases tengan un constructor heredado o de otra manera.

Usted puede llamar al constructor de la clase padre, si es necesario.

Sobreescritura de metodos

Para sobreescribir un metodo en PHP, la subclase debe definir un metodo con el mismo nombre exacto y el numero de argumentos que la clase padre.

 <?php
 class AlgunaClase{
  function gritar($count = 1){
   for($i = 0;$i < $count;$i++){
    echo 'Eek!<br />';
   }
  }
 }

 class AlgunaOtraClase extends AlgunaClase{
  function gritar($count = 1){
   for($i=0;$i<$count;$i++){
    echo 'Whoohoo!<br />';
   }
  }
 }

 $obj1 = new AlgunaClase();
 $obj1->gritar();
 $obj1->gritar(2);
 $obj2 = new AlgunaOtraClase();
 $obj2->gritar();
 $obj2->gritar(2);
?>


La sobreescritura de metodos es una caracteristica comun y util de la programacion orientada a objetos. Como se menciono anteriormente, los metodos sobreescritos crean polimorfismo, donde al llamar al mismo metodo puede obtener resultados diferentes, dependiendo del tipo de objeto. 

Como un simple ejemplo de esto, vamos a volver a las clases Mascota, Perro y Gato, en lugar de tener los metodos subir() y recuperar(), implementaremos una sobreescritura de metodo llamada jugar().



 <!DOCTYPE html>
<html lang="es">
<head>
 <meta charset="utf-8">
 <title>Mascotas</title>
</head>
<body>
<?php
 // Esta pagina define el uso de la clase Mascota, Perro y Gato.

 # *** CLASES *** #
 
 /* Clase Mascota
 * La clase contiene un atributo
 * La clase contiene 4 metodos:
 * - __construct()
 * - comer()
 * - dormir()
 * - jugar()
 */
 class Mascota{
  public $nombre;

  function __construct($nombre){
   $this->nombre = $nombre;
  }

  function comer(){
   echo "<p>$this->nombre esta comiendo.</p>";
  }

  function dormir(){
   echo "<p>$this->nombre esta durmiendo.</p>";
  }

  // Mascota puede jugar:
  function jugar(){
   echo "<p>$this->nombre esta jugando.</p>";
  }
 } // Fin de la clase Mascota

 /* La clase Gato se extiende desde la clase Mascota
 * Gato sobreescribe jugar()
 */

 class Gato extends Mascota{
  function jugar(){
   echo "<p>$this->nombre esta subiendo.</p>";
  }
 } // Fin de la clase Gato.

 /* Perro extiende la clase Mascota 
 * Perro sobreescribe jugar()
 */

 class Perro extends Mascota{
  function jugar(){
   echo "<p>$this->nombre esta recuperando.</p>";
  }
 } // Fin de la clase Perro

 # *** Fin de las CLASES *** #

 // Creamos un nuevo Perro
 $Perro = new Perro('Satchel');

 // Creamos un nuevo Gato
 $Gato = new Gato('Bucky');

 // Creamos un tipo desconocido de Mascota
 $Mascota = new Mascota('Rob');

 // Les damos de comer
 $Perro->comer();
 $Gato->comer();
 $Mascota->comer();

 // Hora de la siesta:
 $Perro->dormir();
 $Gato->dormir();
 $Mascota->dormir();

 // Pedirles que jueguen
 $Perro->jugar();
 $Gato->jugar();
 $Mascota->jugar();

 // Eliminamos los objetos:
 unset($Perro, $Gato, $Mascota);
?>
</body>
</html>



Metodos finales

La mayoria de los metodos de las clases se pueden sobrescribir. La excepcion es que si una funcion es definida como definitiva:

final function mifuncion(){...}

La definicion de un metodo final no puede ser alterado por cualquier subclase. Una clase tambien puede ser declarada como definitiva lo que significa que no puede ser extendida.

La clase Cuadrado puede ser logicamente sobreescribir el metodo de esCuadrado() de la clase Rectangulo. Simplemente se define:

function esCuadrado(){ return true; }

Control de Acceso

El control de Acceso, tambien se llama la visibilidad, dicta como son accesibles los atributos y metodos... en otras palabras: donde pueden ser referenciados los miembros de la clase y en el que son inaccesibles.

Hay tres niveles de visibilidad: public, protected y private. Para establecer la visibilidad de un atributo, la declaracion de la variable lleva como prefijo una de estas palabras clave:

class NombreClase{
        public $var1 = 'Hola';
        private $var2 = 'Mundo';
        protected $var3 = 34;
    }
Ya has estado haciendo esto, por lo que indica la visibilidad de un atributo que se requiere en PHP. Hasta el momento todos los atributos han sido declarados como publicos (public).

Para establecer la visibilidad de un metodo, el prefijo de la declaracion de la funcion debe estar con una de las palabras claves:

class NombreClase{
        public function miFuncion(){
            // codigo
        }
    }
Los metodos que carecen de la declaracion de accesibilidad son considerados como publicos. Y debido a que la mayoria de los metodos son publicos, la visibilidad para ellos se omite con frecuencia.

Piense en cada termino como la prescripcion de un circulo mas limitado en el cada miembro se puede acceder.


Cuanto mas restringida la visibilidad, es mas pequeño el reino donde el atributo y metodo son accesibles.

Un miembro publico es el mas accesible: esta disponible para metodos dentro de la propia clase, en clases heredadas, y fuera de la clase. Por ejemplo, debido a que el atributo $nombre en Mascota es publico, usted puede hacer esto:

$Mascota = new Mascota('Charlie');
 $Mascota->nombre = 'Fungo';
Una vez mas,$nombre es publico por lo cual tambien esta disponible en las clases Perro y Gato, como hemos visto.

Los miembros protegidos solo se pueden acceder dentro de la clase y subclases derivadas. Esto significa que si el atributo $nombre en Mascota se hace protected, usted todavia podria utilizarlo dentro de los metodos que se encuentran en las clases de Perro o Gato, pero no directamente a traves de una instancia de objeto de cualquiera de esas clases.

Privado es mas restrictivo: aquellos miembros solo son accesibles dentro de la clase que los define. Miebros de la clase privada no se pueden acceder por la subclase o por medio de una instancia de objeto de esa clase. Si el atributo $nombre en Mascota fue hecho privado, solo se podria hacer referencia a el dentro de la definicion de la clase de Mascota (es decir, dentro de uno de sus metodos).

Puede parecer extraño para una clase que tiene atributos, o los miembros que son inaccesibles, pero este es un valioso importante concepto de POO, llamado encapsulacion. En pocas palabras la encapsulacion, es la ocultacion de informacion (datos o procesos reales) que no necesita estar disponible fuera de la clase. Desde una perspectiva de diseño, una buena clase es una entidad utilizable sin saber necesariamente como funciona internamente. Por ejemplo, una base de datos necesita una conexion a la base de datos interna, pero no hay razon para que la conexion pueda ser accesible fuera de la clase (de hecho, no deberia).

En cuanto a la clase de Mascota, su atributo $nombre debe hacerse de modo protegido. Tiene sentido que la clase y sus subclases para acceder al nombre, pero usted no deberia ser capaz de cambiar el nombre fuera de la clase. Lo mismo se aplica a los atributos $ancho y $alto de Rectangulo que deben ser protegidos. Al igual que la mayoria de los conceptos de programacion orientada a objetos, hay dos cosas que usted debe de aprender: como funciona la visibilidad y como se utiliza. Para tener claro como funciona el control de acceso, vamos a usar un ejemplo ficticio donde solo juega un papel la accesibilidad de los atributos. Despues de esto el tema de visibilidad sera mas claro:



  

 <!DOCTYPE html>
<html lang="es">
<head>
 <meta charset="utf-8">
 <title>Visibilidad</title>
</head>
<body>
<?php
 // Esta pagina define y usa las clases Prueba y PequenaPrueba.

 # *** CLASES *** #
 /* Clase Prueba
 * Esta clase contiene tres atributos:
 * - public $public
 * - protected $protected
 * - private $_private
 * La clase define un metodo: imprimirVariable().
 */

 class Prueba{
  // Declaramos los atributos:
  public $public = 'publica';
  protected $protected = 'protegida';
  private $_private = 'privada';

  // Funcion para imprimir el valor de la variable:
  function imprimirVariable($var){
   echo "<p>En prueba, \$$var: '{$this->$var}'.</p>";
  }
 } // Fin de la clase Prueba

 /* PruebaPequena extiende la clase Prueba
 * PruebaPequena sobreescribe imprimirVariable().
 */
 class PruebaPequena extends Prueba{
  function imprimirVariable($var){
   echo "<p>En PruebaPequena, \$$var: '{$this->$var}'.</p>";
  }
 } // Fin de la clase PruebaPequena

 # *** Fin de las clases *** #

 // Creamos los objetos:
 $padre = new Prueba();
 $hijo = new PruebaPequena();

 // Imprimimos el valor actual de $public
 echo '<h1>Public</h1>';
 echo '<h2>Inicializando...</h2>';
 $padre->imprimirVariable('public');
 $hijo->imprimirVariable('public');

 // Modificamos $public y lo reimprimimos:
 echo '<h2>Modificando $padre->public</h2>';
 $padre->public = 'modificado';
 $padre->imprimirVariable('public');
 $hijo->imprimirVariable('public');

 // Imprimimos el valor actual de $protected
 echo '<h1>Protected</h1>';
 echo '<h2>Inicializando...</h2>';
 $padre->imprimirVariable('protected');
 $hijo->imprimirVariable('protected');

 // Intento de modificar $protected y lo reimprimimos:
 echo '<h2>Modificando $padre->protected</h2>';
 $padre->protected = 'modificado';
 $padre->imprimirVariable('protected');
 $hijo->imprimirVariable('protected');

 // Imprimimos el valor actual de $_private
 echo '<hr><h1>Private</h1>';
 echo '<h2>Inicializando...</h2>';
 $padre->imprimirVariable('_private');
 $hijo->imprimirVariable('_private');

 // Intento de modificar $_private y lo reimprimimos:
 echo '<h2>Modificando $padre->_private</h2>';
 $padre->_private = 'modificado';
 $padre->imprimirVariable('_private');
 $hijo->imprimirVariable('_private');

 // Eliminamos los objetos:
 unset($padre,$hijo);
?>
</body>
</html>

- Los atributos publicos pueden ser accedidos por cualquiera y ser modificados:


- Intentar modificar un atributo protegido usando la sintaxis: $obj->var resultara en error fatal 


- El intento de hacer referencia a $this->_private dentro de la clase PruebaPequena - es lo que sucede cuando usted llama $hijo->imprimirVariable('_private') - crea una aviso, como la clase no tiene dicho atributo (por que ni lo ha heredado, ni definido), intentando referirse a $padre->_private resulta en un error faltal.




Indicando la visibilidad en UML

En un diagrama de clases UML, la accesibilidad de un miembro de la clase puede ser indicada como utilizando como prefijo lo siguiente para cada miembro de la clase:

* +, para public
* -, para private
* #, para protected

Por lo tanto la clase Mascota puede ser definida asi:

+nombre:string
+__construct($nombre:string):void


Muchos programadores podrian argumentar que todos los atributos deben ser protected o private, entonces ellos nunca accederian directamente desde fuera de la clase. Tu podrias entonces escribir metodos "get" y "set" para acceder a ellos cuando los necesites.

Un metodo diseñado para devolver un atributo es llamado getter o accessor. Un metodo diseñado para asignar valores a un atributo es llamado setter o mutator.

Utilizando el operador de resolucion de alcance

POO tiene algunos de sus propios operadores, como ya has visto con ->, utilizado por los objetos para acceder a sus miembros. Otro es el operador de resolucion de alcance: la combinacion de dos puntos juntos (::). Es usado para acceder a los miebros a traves de clases, no objetos.

    NombreClase::nombreMetodo();
    NombreClase::nombrePropiedad();


Hay dos lugares en los que se utiliza este constructor:

* Dentro de las clases, para evitar la confunsion cuando las clases heredadas tienen mismos atributos y metodos.
* Fuera de clases, para tener acceso a los miembros sin crear primero los objetos.

Fuera de una clase, tendra que especificar el nombre de la clase, como en el codigo anterior. Dentro de una clase, sin embargo, son palabras claves especiales las que usted debe utilizar. Mientras que usted puede usar $this dentro de una clase para hacer referencia a una instancia dentro del objeto actual, la palabra clave self es una referencia a la clase actual. 

class AlgunaClase{
        function __construct(){
            self::hacerEsto();
        }
        protected function hacerEsto(){
            echo '¡Hecho!';
        }
    }


En este codigo, self::hacerEsto() invocara el metodo hacerEsto() de la clase actual.

(Como nota al margen de compresion de visibilidad, la funcion hacerEsto() se define en AlgunaClase solo puede ser llamado dentro de AlgunaClase o por metodos dentro de clases heredadas, por que hacerEsto() se define como protegida)

Para hacer referencia a un miembro de una clase padre, utilice el operador de resolucion de alcance con la palabra clave parent:

class AlgunaOtraClase extends AlgunaClase{
        function __construct(){
            parent::hacerEsto();
        }
    }


En su mayor parte, va utilizar el operador de resolucion de alcance, para tener acceso a metodos sobreescritos. Tambien lo utilizan con miembros de clase estaticos y constantes, mientras tanto veremos como una demostracion utilizando de nuevo nuestras clases Mascota, Perro y Gato.



 <!DOCTYPE html>
<html lang="es">
<head>
 <meta charset="utf-8">
 <title>Mascotas</title>
</head>
<body>
<?php
 // Esta pagina define el uso de las clases Mascota, Perro y Gato.
 
 # *** CLASES *** #

 /* Clase Mascota
 * Esta clase contiene un atributo: nombre
 * Esta clase contiene 4 metodos:
 * - __construct()
 * - comer()
 * - dormir()
 * - jugar()
 */
 class Mascota{
  public $nombre;
  function __construct($nombre){
   $this->nombre = $nombre;
   self::dormir();
  }
  function comer(){
   echo "<p>$this->nombre esta comiendo.</p>";
  }
  function dormir(){
   echo "<p>$this->nombre esta durmiendo.</p>";
  }
  function jugar(){
   echo "<p>$this->nombre esta jugando.</p>";
  }
 } // Fin de la clase Mascota
 /* Clase Gato extiende Mascota.
 * Gato sobreescribe jugar().
 */
 class Gato extends Mascota{
  function jugar(){
   // Llamamos el metodo Mascota::jugar():
   parent::jugar();
   echo "<p>$this->nombre esta subiendo.</p>";
  }
 } // Fin de la clase Gato.
 /* Clase Perro extiende Mascota.
 * Perro sobreescribe jugar().
 */
 class Perro extends Mascota{
  function jugar(){
   // Llamamos al metodo Mascota::jugar():
   parent::jugar();
   echo "<p>$this->nombre esta devolviendo la pelota.</p>";
  }
 } // Fin de la clase Perro.

 # *** Fin de las CLASES *** #

 // Creamos un Perro:
 $Perro = new Perro('Satchel');

 // Creamos un Gato:
 $Gato = new Gato('Bucky');

 // Creamos un tipo desconocido de Mascota:
 $Mascota = new Mascota('Rob');

 // Les damos de comer:
 $Perro->comer();
 $Gato->comer();
 $Mascota->comer();

 // Hora de la siesta:
 $Perro->dormir();
 $Gato->dormir();
 $Mascota->dormir();

 // Los llevamos a jugar:
 $Perro->jugar();
 $Gato->jugar();
 $Mascota->jugar();

 // Eliminamos los objetos:
 unset($Perro,$Gato,$Mascota);
?>
</body>
</html>


El codigo modificado llama ahora el metodo jugar() de Mascota, cada vez que un Gato o un Perro juega.

En Perro y Gato se puede tambien utilizar Mascota::jugar(). Pero mediante el uso de parent::jugar(), se minimiza el riesgo de problemas en el futuro si se cambiesen las definiciones de las clases.

Creacion de miembros estaticos

Una variable estatica recuerda su valor cada vez que se le llama desde una funcion.

 <?php
 function prueba(){
  static $n = 1;
  echo "$n<br>";
  $n++;
 }
 prueba();
 prueba();
 prueba();
?>


Una variable estatica conserva su valor a lo largo de varias llamadas (en el mismo script).

Cada llamada de la funcion prueba() incrementa el valor de n por 1. Si $n no fuese declarado como estatico, cada llamada de la funcion imprimiria el numero 1.

Con atributos de clase estaticos, el concepto es el mismo, salvo que una variable estatica es recordada en todas las instancias de esa clase (en todos los objetos en funcion de la clase). Para declarar un atributo estatico, utilice la palabra clave static despues de el indicador de visibilidad:

class AlgunaClase{
        public static $var = 'valor';
    }



Las variables estaticas se diferencian de los atributos estandar en que no se puede acceder a ellos dentro de la clase utilizando $this. En su lugar debe utilizar self, seguido por el operador de resolucion de alcance (::), seguido del nombre de la variable con su signo inicial en dolar:

class AlgunaClase{
        public static $contador = 0;
        function __construct(){
            self::$contador++;
        }
    }


El codigo anterior crea un contador. Cada vez que un objeto nuevo se crea:

$obj = new AlgunaClase();

El $contador sube 1. Los metodos estaticos se crean de la misma manera:

class AlgunaClase{
        public static $contador = 0;
        public static function hacerEsto(){
            // Codigo
        }
    }
    echo AlgunaClase::$contador; // 0
    AlgunaClase::hacerEsto();



(De hecho, no solo se puede acceder a los miembros estaticos sin crear un objeto, las propiedades estaticas no pueden ser accedidas a traves de un objeto, aunque los metodos estaticos pueden ser).
Para jugar a esto, vamos a crear una nueva clase de Mascotas que utiliza un atributo estatico y un metodo estatico. El atributo se utilizara para contar el numero de animales en existencia. El metodo estatico devolvera el numero de animales. Como esta es una demostracion de este nuevo concepto, no se crearan otros metodos:

 <!DOCTYPE html>
<html>
<head>
 <meta charset="utf-8">
 <title>Estatico</title>
</head>
<body>
<?php
 // Esta pagina define el uso de las clases Mascota, Gato y Perro.
 # *** CLASES *** #
 /* Clase Mascota.
 * Esta clase toneien dos atributos:
 * - protected nombre
 * - private static _count
 * Esta clase contiene 3 metodos:
 * - __construct()
 * - __destruct()
 * - public static obtenerContador()
 */
 class Mascota{
  // Declaramos los atributos:
  protected $nombre;
  private static $_count = 0;

  // El constructor asigna el nombre de la Mascota
  // y incrementa el contador
  function __construct($nombre){
   $this->nombre = $nombre;

   // Incrementamos el contador:
   self::$_count++;
  }

  // El destructor decrementa el contador:
  function __destruct(){
   self::$_count--;
  }

  // Creamos un metodo estatico para retornar el contador:
  public static function obtenerContador(){
   return self::$_count;
  }
 } // Fin de la clase Mascota.

 /* La clase Gato extiende la clase Mascota */
 class Gato extends Mascota{

 } // Fin de la clase Gato.
 /* La clase Perro extiende la clase Mascota */
 class Perro extends Mascota{

 } // Fin de la clase Perro.

 /* La clase Huron extiende la clase Mascota */
 class Huron extends Mascota{

 }  // Fin de la clase Huron.

 /* La clase Mono extiende la clase Mascota */
 class Mono extends Mascota{

 } // Fin de la clase Mono.

 # *** Fin de las CLASES *** #

 // Creamos un nuevo Perro:
 $Perro = new Perro('Fiel Amigo');

 // Imprimimos el numero de mascotas:
 echo '<p>Despues de crear un Perro, Ahora tenemos: ' . Mascota::obtenerContador() . ' Mascota(s)</p>';

 // Creamos un Gato:
 $Gato = new Gato('Bucky');
 echo '<p>Despues de crear un Gato, Ahora tenemos: ' . Mascota::obtenerContador() . ' Mascota(s)</p>';

 // Creamos otra Mascota:
 $Huron = new Huron('Fungo');
 echo '<p>Despues de crear un Huron, Ahora tenemos: ' . Mascota::obtenerContador() . ' Mascota(s)</p>';

 // Una tragedia ocurre!

 unset($Perro);

 echo '<p>Despues de que la tragedia ocurre, Ahora tenemos: ' . Mascota::obtenerContador() . ' Mascota(s)</p>';

 // Los monos son lindos:
 $Mono = new Mono('Toodles');
 echo '<p>Despues de crear un Mono, Ahora tenemos: ' . Mascota::obtenerContador() . ' Mascota(s)</p>';

 // Eliminamos todos los objetos:
 unset($Gato,$Huron,$Mono);
?>
</body>
</html>

La clase Mascota contiene un atributo estatico, que puede ser utilizado para contar el numero de objetos creados a partir de clases derivadas.

Constantes de Clase

Constantes de clase son como atributos estaticos en las que son accesibles para todas las instancias de la clase (o derivadas de la clase). Pero como cualquier otra constante, el valor nunca puede cambiar. Las constantes de clase se crean utilizando la palabra clave const, seguido del nombre de la constante (sin un signo dolar), seguido por el operador de asignacion y el valor de la constante:

class AlgunaClase{
        const PI = 3.14;
    }


Las constantes solo pueden asignar un valor como en este ejemplo. El valor no puede basarse en otra variable, y no puede ser el resultado de una expresion o una llamada de funcion. Las constantes, como atributos estaticos, tambien no se pueden acceder a traves de objeto. No se puede hacer esto:

$obj->PI;
o

$obj::PI;

Pero usted puede usar NombreClase::NOMBRE_CONSTANTE (por ejemplo: AlgunaClase::PI) en cualquier lugar.
Tambien se puede utilizar self::NOMBRE_CONSTANTE dentro de los metodos de la clase.



[Parte 1] Programacion orientada a objetos con PHP


Introducción 

En esta parte aprenderemos un poco de Programación orientada a objetos, aunque PHP no es tan poderoso en esta parte como otros lenguajes de programación, sabremos que metodología utilizar cuando estemos realizando un proyecto ya sea de procedimiento o programación orientada a objetos.

Teoria de la programación orientada a objetos

Lo primero que hay que entender sobre la programacion orientada a objetos es que no presenta una nueva sintaxis, sino una nueva forma de pensar al resolver un problema. El error mas comun de los programadores que están empezando con el uso de programación orientada a objetos es aplicar incorrectamente la teoría de la programación orientada a objetos. PHP le puede decir donde esta un error sintactico pero un error lógico no...

Toda la programacion se reduce a tomar acciones con los datos: un usuario introduce datos en un formulario HTML, el código PHP que valida; son enviados correos electrónicos; se almacena en una base de datos; y así sucesivamente. Estos son simplemente verbos (acciones) y sustantivos (datos). Con la programacion de procedimiento el foco esta en los verbos: hacer esto, entonces esto, luego esto... En la programacion orientada a objetos se centra en los sustantivos: ¿con que tipo de cosas trabajara la aplicacion? En ambos enfoques, lo que se necesita para identificar tanto los sustantivos y los verbos requeridos, la diferencia esta el foco. En el diseño de la aplicacion.

Las dos condiciones mas importantes para la programación orientada a objetos son la clase y objeto. Una clase es una definicion generalizada de una cosa. Piense en clases como los planos. Un objeto es una aplicación especifica de esa cosa. Piense en objetos como la casa construida usando el plano como guía. Para programar usando POO (programacion orientada a objetos), tu diseñas tus clases, y luego las pones en practica como objetos en tus programas cuando sea necesario.

Uno de los principios de la programación orientada a objetos es la modularidad: rompiendo las aplicaciones en subpartes especificas. Los sitios webs hacen muchas, muchas cosas: interactuar con las bases de datos, manejar formularios, enviar mensajes de correo electronico, generar HTML, etc. Cada una de estas cosas puede ser un modulo, es decir, una clase. Al separar elementos no relacionados (aunque interactuando), usted puede desarrollar código de forma independiente, realizar mantenimiento y actualizaciones menos sucias, y simplicar la depuracion.

En cuanto a la modularidad es la abstraccion: las clases deben ser definidas en terminos generales. Esto es un error de principiante comun y comprensible. A modo de ejemplo, en lugar de diseñar una clase para interactuar con la base de datos MySQL, debe hacer uno que interactua con una base de datos especifica. A partir de ahi, el uso de la herencia y el primer orden, que le defina una clase mas especial para MySQL. Esta clase podria lucir y actuar como una clase de base de datos general, pero algunas de sus funciones se irian modificando para requisitos particulares.

Otro principio de la programación orientada a objetos es la encapsulacion: separar y ocultar como se logra algo. Una clase diseñada adecuadamente puede hacer lo que tiene que hacer sin que tu sepas como lo esta haciendo. Acopladas con la encapsulacion es el control de acceso o visibilidad, que dicta como los componentes estan disponibles en la clase. 

Estos son los principales conceptos detrás de la programación orientada a objetos. 

En cuanto a los aspectos negativos a la POO. El uso de los objetos puede ser menos eficiente que un enfoque de procedimiento. La diferencia de rendimiento entre el uso de un objeto no puede ser imperceptible en algunos casos, pero usted debe ser consciente de este efecto secundario potencial. 

Una segunda cuestion que se plantea. El mal uso y excesivo de los objetos.

Definiendo una clase

La programacion orientada a objetos comienza con clases, una clase debe de ser una definicion abstracta de una cosa: ¿Que información debe de ser almacenada y que funcionalidad debe hacer posible con esa informacion? Una clase usuario deberia ser capaz de almacenar informacion como el nombre de usuario, Identifiacion, Correo electronico, y asi sucesivamente. La funcionalidad de un usuario podria ser iniciar sesion, cerrar sesion, cambiar contraseña, y mucho mas.

Sintacticamente, una definicion de clase comienza con la palabra Class. La palabra class es una palabra reservada. Despues de el nombre de la clase que es escrito comenzando con una mayuscula como convencion, la definicion de la clase se coloca dentro de unas llaves:

Class Nombredelaclase{  }
Las clases contienen variables y funciones, que son referidos como atributos (o propiedades y metodos), respectivamente. Colectivamente, las propiedades y métodos de la clase son sus miembros.

Las funciones son faciles de agregar a una clase:


Class Nombredelaclase {
        function nombredelafuncion(){
            // codigo
        }
    }
Los metodos que se definen dentro de una clase se definen igual que una funcion fuera de la clase. Ellos pueden tomar argumentos, tener valores por defecto, devolver valores, y asi sucesivamente. 

Las propiedades dentro de las clases son un poco diferente fuera de la clase. En primer lugar, todas las propiedades deben estar precedidas de una palabra clave que indica la visibilidad de la variable. Las opciones son public, private y protected. Por lo pronto estos valores no significaran nada para usted hasta que vea herencia, por lo cual usaremos para todo public.


Class Nombredelaclase {
        public $var1, $var2;
        function nombredelafuncion(){
            // codigo
        }
    }
Como se muestra aqui las propiedades de la clase se enumeran antes que cualquier definicion de metodo. La segunda distincion entre las propiedades y las variables normales es que si una propiedad se inicializa con un valor establecido, ese valor debe ser un valor literal y no un resultado de una expresion:


class ClaseBuena{
        public $var1 = 123;
        public $var2 = 'cadena';
        public $var3 = array(1,2,3);
    }

class ClaseMala{
        // esto no funciona
        public $hoy = getdate();
        public $cuadrado = $num * $num;
    }
Tenga en cuenta que usted no tiene que inicializar las propiedades con un valor. Y, aparte de la declaracion de las variables, todos los otros codigos de una clase va dentro de sus metodos. No se pueden ejecutar sentencias fuera de un metodo de una clase.

class ClaseMala{
        // esto no funciona
        public $num = 2;
        public $cuadrado;
        $square = $num * $num; // NO!
    }
Con todo esto en mente vamos a crear una clase, de forma facil y casi inutil para asegurarse de que hemos estado trabajando de manera correcta. La clase dira "Hola Mundo" en diferentes idiomas.

<?php
 class HolaMundo {
  function diHola($lenguaje = 'Espanol'){
   echo '<p>';
   switch ($lenguaje) {
    case 'Dutch':
     echo 'Hallo, Wereld!';
     break;
    case 'French':
     echo 'Bonjour, mode!';
     break;
    case 'German':
     echo 'Hallo, Welt!';
     break;
    case 'Italian':
     echo 'Ciao, mondo!';
     break;
    case 'Ingles':
     echo 'Hello, World!';
     break;
    case 'Espanol':
    default:
     echo 'Hola, Mundo!';
     break;
   }
echo '</p>'; 
 }
 }
?>


1.- Comenzamos definiendo la clase: class HolaMundo { usamos una sintaxis "uper case camel" donde cada palabra comienza con mayuscula

2.- Definimos el metodo: function diHola($lenguaje = 'Espanol'){ La clase actual no contiene propiedades (variables) estos deben ser declarados antes que los metodos. Este metodo se llama diHola() y usa "lower case camel" comenzando siempre con letra minuscula esto es usado como convencion.
3.- Agregamos un switch alternando en el lenguaje: 
switch ($lenguaje) {
                case 'Dutch':
                    echo 'Hallo, Wereld!';
                    break;
                case 'French':
                    echo 'Bonjour, mode!';
                    break;
                case 'German':
                    echo 'Hallo, Welt!';
                    break;
                case 'Italian':
                    echo 'Ciao, mondo!';
                    break;
                case 'Ingles':
                    echo 'Hello, World!';
                    break;
                case 'Espanol':
                default:
                    echo 'Hola, Mundo!';
                    break;
            }


El switch cambia dependiendo del lenguaje que eligamos, como lenguaje por defecto tenemos el Español.
Los metodos de la clase tambien pueden tener una visibilidad, precediendo la definicion de la funcion con la palabra clave adecuada. Si no se indica, todos los metodos todos los metodos tienen la palabra clave asumida:

public function Nombredelafuncion(){ }

La clase stdClass esta en uso internamente por PHP y no puede ser declarada en su propio codigo.

Creando un objeto

Usando POO es un proceso de dos pasos. Lo primero es la definicion de la clase, que acabas de hacer cuando escribiste la clase HolaMundo. El segundo paso es hacer uso de esa clase por la creación de un objeto (o una instancia de la clase).

Volviendo a la analogia de la clase usuario, una instancia de esta clase puede ser para el usuario con un nombre de usuario arthusu. El usuario podria tener propiedades para el mismo, ID 138, y una direccion de correo electronico arthusu@most-security.com, esta es una instancia de la clase usuario. Un segundo ejemplo, Zangetsu, tiene ese nombre de usuario, el ID 2, y un correo electronico Zangetsu@most-security.com. Estos son objetos separados de la misma clase, pero con diferente especificacion. 

La creacion de un objeto es muy facil en PHP ya despues de haber definido la clase. Para ello solo requerimos de la palabra clave new.

$objeto = new Nombredelaclase();

Ahora la variable $objeto existe y es de tipo Nombredelaclase (en lugar de tipo cadena o array). Mas tecnicamente ponemos, $objeto en una instancia Nombredelaclase.

Para llamar a los metodos de la clase, se utiliza esta sintaxis:

$objeto->nombreMetodo();

El -> puede ser llamado el operador del objeto. Si un metodo tiene argumentos, usted puede proporcionarselos dentro del parentesis, como cualquier otra llamada a una funcion:

$objeto->nombreMetodo('valor',32,true);

Para acceder a las propiedades de un objeto utilizamos:

$objeto->nombrePropiedad;

Tenga en cuenta que al llamar a la propiedad no utilizamos el signo dolar $ como prefijo, lo cual nos causaria errores de analisis:

$objeto->$nombrePropiedad; // Error!

(Como se vera mas adelante, la capacidad de hacer referencia a un metodo o alguna propiedad de un objeto, depende de la visibilidad del mismo). Una vez que haya terminado con el objeto puede eliminarlo, como se hace con cualquier otra variable:

unset($objeto);


<!DOCTYPE html>
<html lang="es">
<head>
 <meta charset="utf-8" />
 <title>Hola, Mundo!</title>
</head>
<body>
<?php
 // Incluimos la definicion de la clase:
 require('HolaMundo.php');

 // Creamos el objeto:
 $obj = new HolaMundo();
 // Llamamos al metodo diHola():
 $obj->diHola();

 // Decimos Hola en diferents lenguajes:
 $obj->diHola('Dutch');
 $obj->diHola('French');
 $obj->diHola('Italian');

 // Eliminamos el objeto:
 unset($obj);
?>
</body>
</html>

1.- Incluimos la definicion de la clase: require('HolaMundo.php');
Con el fin de acceder a la clase, utilizamos require en lugar de include ya que asi se pararia el script en caso de que la clase no se haya incluido.
2.- Creamos un nuevo objeto: $obj = new HolaMundo();
Esta linea de codigo se explica por si misma, la variable $obj puede ser el nombre que usted desee $holaMundo, $prueba, etc.
3.- Invocamos al metodo diHola(): $obj->diHola(); 
Esta linea del codigo llama a el metodo diHola() y como no tiene ningun argumento arroja el lenguaje por defecto que es Español.
4.- Llamamos el metodo diHola() y le damos varios lenguajes como argumento:
$obj->diHola('Dutch');
$obj->diHola('French');
$obj->diHola('Italian');
6.- Borramos el objeto completamente: unset($obj);
Tecnicamente no tiene que borrar el objeto ya que se borra en cuanto el script termina, pero es una buena practica de programacion poner esto en orden.

Los nombres de las clases no distinguen entre mayusculas y minusculas. Sin embargo los nombres del objeto, al igual que cualquier variable de PHP, distinguen entre mayusculas y minusculas.


El atributo $this

La clase HolaMundo en realidad hace algo, lo cual es bueno, pero es un ejemplo bastante minimo. La clase incluye un metodo, pero no contiene ninguna propiedad (variables). 

Las propiedades:

* Son variables
* Deben ser declaradas como public, private o protected 
* Si se inicializan se debe de dar un valor estatico (no el resultado de una expresion)

Esas son las reglas para la definicion de propiedades en una clase, pero utilizando esas propiedades requiere una pieza mas de informacion. Como ya se ha explicado, a traves del objeto, se puede acceder a las propiedades del objeto con el operador de notacion (->).

$objeto->nombrePropiedad;

La cuestion es que dentro de la propia clase (es decir, dentro de los metodos de una clase), debe utilizar una sintaxis alternativa para acceder a las propiedades de la clase. No se puede hacer esto:

class ClaseMala{
        public $var;
        function hacer(){
            // Esto no trabaja:
            print $var;
        }
    }


El metodo hacer() no puede acceder a $var de esa manera. La solucion es una variable especial llamada $this. La variable $this en una clase siempre se refiere a la instancia actual (es decir, al objeto involucrado). Dentro de un metodo se puede hacer referencia a la instancia de una clase y sus propiedades utilizando la sintaxis $this->nombrePropiedad. En lugar de sobre explicar este concepto. Vamos hacer una practica. El siguiente ejemplo definira una clase que representa un rectangulo.

<?php
 /* 
  Esta pagina define la clase rectangulo
  La clase contiene dos atributos ancho y alto.
  Esta clase contiene 4 metodos:
  - establecerTamano()
  - obtenerArea()
  - obtenerPerimetro()
  - esCuadrado()
 */

 class Rectangulo{
  // declaramos las propiedades:
  public $ancho = 0;
  public $alto = 0;

  // Metodo para establecer las dimensiones:
  function establecerTamano($w = 0, $h= 0){
   $this->ancho = $w;
   $this->alto = $h;
  }

  // Metodo para calcular y devolver el area.
  function obtenerArea(){
   return ($this->ancho * $this->alto);
  }

  // Metodo para calcular y devolver el perimetro.
  function obtenerPerimetro(){
   return (($this->ancho + $this->alto) * 2 );
  }

  // Metodo para determinar el area del rectangulo:
  function esCuadrado(){
   if($this->ancho == $this->alto){
    return true; // Es cuadrado
   }
  }
 }
?>

1.- Definimos la clase rectangulo: class Rectangulo{ 
2.- Declaramos las propiedades:
public $ancho = 0;
public $alto = 0;
La clase tiene dos propiedades para el rectangulo alto y ancho, ambas se inicializan en 0.
3.- Creamos un metodo para establecer las dimensiones del rectangulo:
function establecerTamano($w = 0, $h= 0){
            $this->ancho = $w;
            $this->alto = $h;
        }

Toma dos valores el alto y el ancho y se inicializan en cero para posibles inconveniencias, establecemos las propiedades los argumentos que le demos al metodo.
4.- Creamos un metodo que calcule y retorne el area del rectangulo:
function obtenerArea(){
            return ($this->ancho * $this->alto);
        }

Este metodo no necesita tomar ningun argumento, ya que accede directamente a las propiedades ancho y alto utilizando $this para referirse, y hace una multiplicacion.
5.- Creamos un metodo para devolver y calcular el perimetro: 
function obtenerPerimetro(){
            return (($this->ancho + $this->alto) * 2 );
        }

Este metodo es como obtenerArea(), a excepcion de que utiliza una formula diferente.
6.- Creamos un metodo que indique si el rectangulo tambien es cuadrado:
function esCuadrado(){
            if($this->ancho == $this->alto){
                return true; // Es cuadrado
            }
        }

Este metodo compara si el ancho es igual al alto, y si son los mismos devuelve true en otro caso false.


Vamos a usar la clase Rectangulo:

<!DOCTYPE html>
<html lang="es">
<head>
 <meta charset="utf-8">
 <title>Rectangulo</title>
</head>
<body>
<?php
 /*
 Esta pagina usa la clase rectangulo
 Esta pagina muestra un grupo de informacion acerca del rectangulo.
 */

 // incluimos la definicion de la clase:
 require('Rectangulo.php');

 // Definimos las variables necesarias:
 $ancho = 42;
 $alto = 7;

 // Imprimimos un poco de introduccion:
 echo "<h2>Con el ancho de $ancho y el alto de $alto ...</h2>";

 // Creamos un nuevo objeto:
 $r = new Rectangulo();

 // Asignamos dimensiones al rectangulo:
 $r->establecerTamano($ancho,$alto);

 // Imprimimos el area:
 echo '<p>El area del rectangulo es:'. $r->obtenerArea() .'</p>';

 // Imprimimos el perimetro:
 echo '<p>El perimetro del rectangulo es:'. $r->obtenerPerimetro() .'</p>';

 // ¿Es esto un cuadrado?
 echo '<p>Este rectangulo: ';
 if ($r->esCuadrado()) {
  echo "tambien";
 }else{
  echo "no";
 }
 echo ' es cuadrado</p>';

 // Eliminamos el objeto:
 unset($r);
?>
</body>
</html>
1.- Incluimos la definicion de la clase: require('Rectangulo.php'); 
2.- Definimos las variables necesarias y imprimimos una introduccion:
$ancho = 42;
    $alto = 7;

    // Imprimimos un poco de introduccion:
    echo "<h2>Con el ancho de $ancho y el alto de $alto ...</h2>";


3.- Creamos un objeto y asignamos las dimensiones del rectangulo:
$r = new Rectangulo();

    // Asignamos dimensiones al rectangulo:
    $r->establecerTamano($ancho,$alto);

4.- Imprimimos el area del rectangulo:
echo '<p>El area del rectangulo es:'. $r->obtenerArea() .'</p>';
5.- Imprimimos el perimetro del rectangulo:
echo '<p>El perimetro del rectangulo es:'. $r->obtenerPerimetro() .'</p>';
6.- Indicamos si el rectangulo tambien es cuadrado:
echo '<p>Este rectangulo: ';
    if ($r->esCuadrado()) {
        echo "tambien";
    }else{
        echo "no";
    }
    echo ' es cuadrado</p>';

7.- Eliminamos el objeto:
unset($r);

Tener métodos de obtener y establecer en una clase es muy común. Los métodos que comienzan con establecer son para asignar valores para las propiedades de la clase. Los métodos que comienzan con obtener son usados para devolver valores: o bien las propiedades o los resultados de los calculos.

Los metodos pueden llamarse unos a otros, tal como seria en cualquier otra funcion, pero usted tendra que usar $this de nuevo. Lo siguiente es innecesario pero valido:

function obtenerArea(){
        if($this->esCuadrado()){
            return ($this->ancho * $this->alto);
        }else{
            return ($this->ancho * $this->alto);
        }
    }



Creacion de constructores

Un constructor es un tipo especial de metodo que difiere de los estandar de tres maneras:

* Su nombre es siempre __construct
* Es de forma automatica e inmediatamente llamado cada vez que un objeto de esa clase se crea.
* No puede tener una sentencia return.

La sintaxis para definir un constructor  es por lo tanto:

class NombreClase{
        public $var;
        function __construct(){
            // Codigo de la funcion
        }
    }


Un constructor podria ser utilizado para conectarse a una base de datos, establecer cookies, o establecer valores iniciales. Basicamente vamos a usar los constructores, para hacer cualquier cosa que siempre deba y hacer primero, cuando se haga un objeto de esta clase.

Debido a que el constructor es todavia mas que otro metodo, puede tomar argumentos y valores, para que se le puedan proporcionar valores cuando el objeto es creado.

class Usuario{
        function __construct($id){
            // codigo de la funcion
        }
    }
    $me = new Usuario(2345);


La clase Rectangulo podria beneficiarse de tener un constructor que asigne las dimensiones cuando el Rectangulo se crea.

<?php
 /* 
  Esta pagina define la clase rectangulo
  La clase contiene dos atributos ancho y alto.
  Esta clase contiene 4 metodos:
  - establecerTamano()
  - obtenerArea()
  - obtenerPerimetro()
  - esCuadrado()
 */

 class Rectangulo{
  // declaramos las propiedades:
  public $ancho = 0;
  public $alto = 0;

  function __construct($w = 0, $h = 0){
   $this->ancho = $w;
   $this->alto = $h;
  }

  // Metodo para calcular y devolver el area.
  function obtenerArea(){
   return ($this->ancho * $this->alto);
  }

  // Metodo para calcular y devolver el perimetro.
  function obtenerPerimetro(){
   return (($this->ancho + $this->alto) * 2 );
  }

  // Metodo para determinar el area del rectangulo:
  function esCuadrado(){
   if($this->ancho == $this->alto){
    return true; // Es cuadrado
   }
  }
 }
?>

Como vez hemos agregado la funcion __construct y hemos eliminado la funcion establecerTamano() ya que practicamente hacen lo mismo, solo que es mejor con __construct ya que si no llamasemos a al metodo establecerTamano() habria un error en los demas metodos, pero como estamos utilizando __construct() se inicia siempre aunque no le demos valores, con los valores por defecto de 0.

Al llamarlo lo hacemos de la siguiente forma:

<!DOCTYPE html>
<html lang="es">
<head>
 <meta charset="utf-8">
 <title>Rectangulo</title>
</head>
<body>
<?php
 /*
 Esta pagina usa la clase rectangulo
 Esta pagina muestra un grupo de informacion acerca del rectangulo.
 */

 // incluimos la definicion de la clase:
 require('Rectangulo.php');

 // Definimos las variables necesarias:
 $ancho = 142;
 $alto = 7;

 // Imprimimos un poco de introduccion:
 echo "<h2>Con el ancho de $ancho y el alto de $alto ...</h2>";

 // Creamos un nuevo objeto:
 $r = new Rectangulo($ancho,$alto);

 // Imprimimos el area:
 echo '<p>El area del rectangulo es:'. $r->obtenerArea() .'</p>';

 // Imprimimos el perimetro:
 echo '<p>El perimetro del rectangulo es:'. $r->obtenerPerimetro() .'</p>';

 // ¿Es esto un cuadrado?
 echo '<p>Este rectangulo: ';
 if ($r->esCuadrado()) {
  echo "tambien";
 }else{
  echo "no";
 }
 echo ' es cuadrado</p>';

 // Eliminamos el objeto:
 unset($r);
?>
</body>
</html>

Un constructor como el que se acaba de agregar a la clase Rectangulo, se llama un constructor por defecto, ya que proporciona valores predeterminados para sus argumentos. Esto significa que un objeto Rectangulo puede ser creado utilizando cualquiera de estas dos formas:

$r = new Rectangulo($ancho,$alto);
$r = new Rectangulo();

Usted puede llamar directamente a un constructor (aunque raramente se necesita):

$o = new AlgunaClase();
$o->__construct();

Con el ejemplo de Rectangulo, esto dejaria deshacerse del metodo establecerTamano() sin perder la capacidad de cambiar el tamaño del Rectangulo.

En PHP 4 como en otros lenguajes de programacion (como c++), un constructor se declara mediante la creacion de un metodo con el mismo nombre de la clase.






Creando destructores

El corolario de un constructor es un destructor. Mientras que un constructor es invocado automaticamente cuando el objeto es creado, el destructor es llamado cuando el objeto se destruye. Esto puede ocurrir cuando se quita abiertamente el objeto:


    $obj = new NombreClase();
    unset($obj); // llama tambien al destructor


O esto puede ocurrir cuando termina un script (en el punto en que PHP libera memoria utilizada por las variables). El destructor se crea de este modo:

class NombreClase{
        // Propiedades y metodos
        function __destruct(){
            // codigo de la funcion
        }
    }


Los destructores no se diferencian de los constructores y otros metodos en que no pueden tomar argumentos.

Vamos a ver un ejemplo de cuando los constructores y destructores son llamados:

<!DOCTYPE html>
<html lang="es">
<head>
 <meta charset="utf-8">
 <title>Constructores y Destructores</title>
</head>
<body>
<?php
 /*
 Esta pagina define una clase demo y una funcion demo()
 Ambas seran usadas para mostrar cuando los constructores y destructores son
 llamados.
 */

 // Definimos la clase:

 class Demo{
  // Sin propiedades

  // Constructor:
  function __construct(){
   echo '<p>En el constructor</p>';
  }

  // Destructor:
  function __destruct(){
   echo '<p>En el destructor</p>';
  }
 } // Fin de la clase Demo

 // Definimos una funcion prueba():
 function prueba(){
  echo '<p>En la funcion. Creamos un nuevo objeto...</p>';
  $f = new Demo();
  echo '<p>A punto de salir de la funcion.</p>';
 }

 // Creamos un objeto:
 $o = new Demo();

 // Llamos a la funcion prueba():
 echo '<p>Llamando a la funcion...</p>';
 prueba();

 // Eliminamos el objeto:
 echo '<p>A punto de eliminar el objeto...</p>';
 unset($o);

 echo '<p>Terminamos el script</p>';

?>
</body>
</html>

Autocarga de clases

Cuando se define una clase en un script que hace referencia a otro script, usted tiene que asegurarse de que el segundo script incluye el primero, o habra errores. 
Con este fin PHP 5 es compatible con la funcion especial llamada __autoload (tenga en cuenta que las funciones en PHP que comienzan con dos _ guiones bajos son especiales). La funcion __autoload() se invoca cuando el codigo intenta crear una instancia de un objeto de una clase que aun no se ha definido. El objetivo de la funcion __autoload() es incluir el archivo correspondiente. En forma mas simple esto podria ser:

function __autoload($class){
        require($class . '.php');
    }

Para cada nuevo tipo de objeto creado en el siguiente codigo, la funcion sera invocada:

    $obj = new Clase();
    $yo = new Humano();
    $r = new Rectangulo();

Gracias a la funcion __autoload() esas tres lineas incluiran automaticamente: Clase.php, Humano.php y Rectangulo.php (dentro del directorio actual). Tenga en cuenta que esta funcion __autoload() se define fuera de cualquier clase; en su lugar, es colocado al crear una nueva instancia para un objeto. 

El diseño de clases con UML

Esto es una introduccion al Lenguaje Unificado de Modelado (UML) una forma de representar graficamente sus diseños POO. 

Una clase en su nucleo tiene tres componentes:

* El nombre
* Las propiedades
* Los metodos

UML representa una clase graficamente mediante la creacion de un diagrama de clases: una caja de tres partes para cada clase, con el nombre de la clase en la parte superior. La siguiente seccion de la caja identificara las propiedades de la clase, y el tercero seria enumerar los metodos. 

Nombre de la clase
Propiedad
Propiedad
Metodo()
Metodo()

Para las propiedades, el tipo de propiedad (por ejemplo: cadena, matriz, etc.) aparece despues del nombre de la propiedad, como en:
UsuarioId:number
Usuario:string

Si la propiedad tiene un valor predeterminado, podria reflejar eso tambien:
ancho:number = 0

Para definir un metodo en un diagrama de clase, seria comenzar con el nombre de metodo, colocando sus argumentos y tipos dentro del parentesis. Esto es normalmente seguido por el tipo del valor que el metodo devuelve:
diHola(langueje:string):void 

El metodo diHola() no devuelve nada, por lo que su tipo de retorno es nulo.

Beneficios de un diseño de clase

Al hacer un diseño formal de clases UML puede parecer a primera vista mas que hacer un ejercicio mas que cualquier otra cosa, pero hay un monton de beneficios para crear uno. En primer lugar si usted esboza el diseño antes de hacer el codigo, puede mejorar las posibilidades de que el codigo sea correcto desde el inicio. En otras palabras, si pone esfuerzo en su diseño visual, y reflexiona sobre si el diseño refleja plenamente el numero de veces que tendra que actualizar sus definiciones de clase en el camino. 
En segundo lugar, un principio de programacion orientada a objetos es la encapsulacion: separar y ocultar como se logra algo. Un UML, con su lista de propiedades, metodos y argumentos, puede actuar como una guia de usuario para esas clases. 
Cualquier codigo que requiere clases que han sido modeladas debe ser capaz de utilizar las clases, sus metodos y propiedades, sin tener que mirar el codigo subyacente. De hecho, se puede distribuir el UML, junto con el codigo como servicio a los clientes.

Con esto en mente usted puede completar el diagrama de clases para la clase HolaMundo


HolaMundo
diHola(lenguaje: string):void

 Para la clase Rectangulo:



Rectangulo
Ancho:number = 0
alto:number = 0
__construct(ancho:number = 0, alto:number = 0):void
obtenerTamano(ancho:number = 0, alto:number = 0):void
obtenerArea():number
obtenerPerimetro():number
esCuadrado():Boolean

Asegurese de actualizar el diseño de su clase en caso de mas adelante cambiar su definicion de clase.

Mejorando la documentacion con phpDocumentor

Junto con la creacion de un diseño de clases UML, otro tema es la creacion de una mejor documentacion utilizando phpDocumentor (http://www.phpdoc.org/). Un codigo correctamente documentado genera menos errores, esto nos causa menos inconvenientes con los clientes que lo van a usar, con los compañeros de trabajo, hasta con los que te ayudaran a mejorar el codigo, y para ti mismo.

Aunque se puede documentar su codigo utilizando comentarios simples, hay dos beneficios obvios para la adoptacion de un enfoque formal phpDocumentor:

* Transmite mucho mejores practicas y estilos recomendados
* phpDocumentor generará documentacion, en HTML y otros formatos para usted. El HTML generado tambien puede ser un recurso valioso para cualquier persona que utilice su codigo, en especial sus clases.

phpDocumentor crea documentacion para la lectura del codigo PHP y sus comentarios. Para facilitar ese proceso deberia empezar a escribir sus comentarios en una forma que phpDocumentor lo comprenda. Para empezar usted debe utilizar la sintaxis del docblock de la documentacion:

    /*
    *
    * Descripcion corta
    *
    *
    * Descripcion larga
    */



La descripcion corta debe ser una sola descripcion de linea. La descripcion larga puede ir atraves de multiples lineas e incluso utilizar algunas HTML. Ambas son opcionales.

Cada etiqueta precedida por @ y phpDocumentor soporta varios tipos, depende de lo que utilice sera lo que esta documentando. 

Un bloque de documentacion se puede colocar antes de cualquiera que de lo siguiente:

* Definicion de una clase
* Definicion de una funcion o metodo
* Declaracion de variables
* Definicion de constantes
* Inclusion de archivos

Un docblock debe ser escrito en la parte superior del script, con el fin de documentar todo el archivo.
Editamos el archivo HolaMundo documentandolo de la siguiente manera:

<?php
 /**
 * Esta pagina define la clase HolaMundo
 *
 *
 * La clase Holamundo dice "Hola, Mundo" en diferentes lenguajes
 *
 *
 * La clase HolaMundo es mas para
 * propositos de demostracion
 * No es buena realmente para utilizar en POO.
 */

 class HolaMundo {
  /**
  * La funcion dice "Hola, Mundo!" en diferentes lenguajes
  * @param string $lenguaje Por defecto es "Ingles"
  * @returns void
  */
  function diHola($lenguaje = 'Espanol'){
   echo '<p>';
   switch ($lenguaje) {
    case 'Dutch':
     echo 'Hallo, Wereld!';
     break;
    case 'French':
     echo 'Bonjour, mode!';
     break;
    case 'German':
     echo 'Hallo, Welt!';
     break;
    case 'Italian':
     echo 'Ciao, mondo!';
     break;
    case 'Ingles':
     echo 'Hello, World!';
     break;
    case 'Espanol':
    default:
     echo 'Hola, Mundo!';
     break;
   }
   echo '</p>';
  }
 }
?>

Instalamos phpDocumentor utilizando el canal de PEAR:

pear channel-discover pear.phpdoc.org
pear install phpdoc/phpDocumentor
 
 
Si no sabes como instalar PEAR desde la terminal usamos:

sudo apt-get install php-pear

Nos movemos al directorio donde se encuentra el archivo de clase HolaMundo:

cd /var/www

En mi caso esa era la ruta.
Documentamos un solo archivo utilizando:

phpdoc -f HolaMundo.php -t docs/

Esto nos generara la documentacion en el directorio docs/ del archivo HolaMundo.
Al terminar abrimos docs/ y el archivo index.html donde vendra la documentacion del archivo:




Yo no estoy utilizando la version mas nueva, pero para saber como se ve en realidad pueden ver la demo de la web oficial: http://demo.phpdoc.org/Clean/

Hasta aqui terminamos esta parte, nos vemos en la proxima.

Creado para Most-Security.com, Son libres de distribuir utilizando siempre la pagina donde se ha creado.