Saltar al Contenido | Saltar al Menú de Navegación

[PHP] Re-aprendiendo #1: Hola Mundo para avanzados

Publicado por Kuroir el 26 de septiembre de 2009
Ver Respuestas

16cfg No sé si muchos lo sepan, pero a la fecha me dedico -a diario- a desarrollar aplicaciones en PHP, entre otros lenguajes, y es por eso que me he decidido a traerles la primera parte de la serie:
Re-Aprendiendo PHP”.

Aclaro que esta serie de artículos no son para gente novata -en cuanto a programación se refiere- o que no tiene conocimiento alguno sobre PHP. Como el nombre lo dice se trata de re-aprender, por lo que hablaré de las buenas prácticas, temas intermedio-avanzado, orientación a objetos, etc.

Como en todos los lenguajes, de scripting o ya lenguajes como tal, es común comenzar con un sencillo “Hola mundo”. Y para no perder la costumbre, en haremos lo mismo en la primera parte de re-aprendiendo PHP.

Así que sin más, vamos a comenzar con un simple “Hola Mundo” hecho con Programación Orientada a Objetos.

Hola mundo “avanzado”

Yo se que deben saber aunque sea lo básico, así que pondré una lista de las cosas que vamos a tratar en esta práctica de “Hola mundo para avanzados”, lo se.. suena MUY gracioso. Cabe aclarar que no es necesario entender todo esto a la perfección, ya que iré explicando y poniendo la documentación oficial.

  1. Interfaces
  2. Clases
  3. Definición de Variables y Matrices(arrays) en una Clase
  4. Visibilidad de las variables y métodos
  5. Constructores
  6. Controles de flujo (if, else) y sus mejores prácticas
  7. Métodos siguiendo put/get (pon/dar)
  8. El uso de una variable de salida para usar como buffer.
  9. Control de errores por medio de try/catch

1. Planificando la aplicación

Cuando comenzamos a crear código, siempre es recomendable tener una idea del objetivo final. Así, una vez que sepamos dónde llegar, nos ponemos a averiguar y planear qué tenemos que hacer para llegar a nuestra meta.

Así que haciendo caso a esa premisa, comenzamos por definir lo siguiente:

  1. ¿Qué es lo que queremos hacer con este “programa”?
    • En este caso, necesito que el programa imprima la típica frase “Hello World”.
  2. ¿Qué características quiero que tenga?
    • Saludos predefinidos y que me permita decidir cuál de todos usar.
    • Saludos personalizables, necesito poder generar saludos aunque no estén predefinidos.
    • Que pueda imprimir los mensajes cuantas veces quiera, creando 1,2,3 etc mensajes diferentes.
    • Control de errores, que imprima todo lo que hace el programa.
    • Que todo se guarde en una variable, para que pueda definir cuándo, dónde y cuántas veces quiero que se imprima el contenido/saludo.

Lo sé, pensarán que esto es mucho para el simple “Hola mundo” que puedes hacer en PHP vía el típico:


<?php echo "Hola Mundo"; ?>

Pero digamos que para mi este ejemplo de "Hola Mundo" puede abarcar mucho más de lo que esa simple línea de código propone. Es por eso que a partir de ahora, veremos el motivo "Hola Mundo" como una excusa para explicarles los diferentes métodos de la programación orientada a Objetos en PHP.

Así que ahora que ya hemos concretado lo que queremos hacer con la aplicación, comenzamos definiendo la estructura general del mismo:

2. Interfaces: Creando la estructura

PHP como sabrán es un lenguaje muy flexible en cuanto a su código. Algunos verán eso como bueno y otros lo verán como la perdición, sobre todo cuando se trata de las variables; sin embargo, esta misma flexibilidad puede causarnos problemas. Ya que a veces perdemos el hilo de nuestra aplicación y terminamos haciendo un revoltijo de métodos y variables duplicadas/innecesarias.

Así que el primer paso para hacer nuestra aplicación es tener una idea de los métodos que emplearemos; los que usaremos de forma obligatoria en nuestra clase.

En este caso, empleando las ideas del paso 1 ("planificando la aplicación"):

  1. Constructor:
    Usaremos el constructor para permitirle al usuario que automáticamente seleccione el mensaje por defecto, por medio de la variable $auto que por defecto tiene que estar puesta como false para que sea opcional.
    • public function __construct($auto = false);
  2. Método para definir el Saludo:
    Ahora este método es el que tiene definir el saludo usando la variable $tipo como índice de la matriz de saludos predefinidos, en caso de no existir tiene que intenta crear uno usando la segunda variable(opcional) $mensaje. Desde aquí tiene que enviarse al control de errores.
    • public function ponSaludo($tipo, $mensaje = '');
  3. Método para devolver el Saludo como una cadena de caracteres (string)
    Lo que debe hacer este método es devolver la salida, como una cadena de caracteres para que pueda ser impresa por medio de echo.
    • public function darSaludo();
  4. Método para control de los errores y excepciones:
    Este método básicamente guardará el error que se le enviará como una variable obligatoria: $error y guardará el error la variable de clase $Error, permitiéndonos decidir si queremos o no imprimir los errores.
    Otra característica agregada, es que podemos definir qué etiquetas HTML rodearán el error por medio de la variable privada $this->error_wrapper.
    • public function ponError($error);
  5. Método para imprimir los Errores:
    Como el método para devolver los saludos, esta función imprimirá los errores y excepciones que ocurran a lo largo de nuestra aplicación.
    • public function darError();

Nuestra interface creada:


interface SaludandoMundos
{
	public function __construct($auto = false);
	public function ponSaludo($tipo, $mensaje = '');
	public function darSaludo();
	public function ponError($error);
	public function darError();
}

3. Creando la clase e implementando la interfaz

Ya tenemos la interfaz definida; ahora tendremos que implementarla. Para hacer esto, comenzaremos creando las funciones vacías usando lo que ya tenemos definido y ya mencionamos con anterioridad. De esta forma podremos trabajar sin recibir el siguiente error:

Fatal error: Class HolaMundo contains 4 abstract methods and must therefore be declared abstract or implement the remaining methods (SaludandoMundos::ponSaludo, SaludandoMundos::darSaludo, SaludandoMundos::ponError, ...) in prueba.php on line 32

Este error significa que no implementamos las funciones requeridas por la interfaz. Así que deberían terminar con algo similar a esto:


class HolaMundo implements SaludandoMundos
{
	public function __construct($auto = false)
	{
	}
	
	public function ponSaludo($tipo, $mensaje = '')
	{
	}
	

	public function darSaludo()
	{

	}
	
	public function darError()
	{
	}
	
	public function ponError($error)
	{
	}
}

Con esto ya tenemos definido lo que es la base de la aplicación; sólo nos queda hacer el desarrollo de los métodos.

4. Desarrollando los métodos

Aquí comenzamos con la parte entretenida. Para comenzar vamos a definir las variables de "configuración" que usaremos en la clase, estas variables son las que usaremos en nuestros métodos.

Recuerden documentar su aplicación mientras la programan.

4.1 Definiendo las variables de configuración

Es recomendable usar variables de configuración para evitar terminar con un programa desechable. Ya que recuerden que siempre tienen que programar aplicaciones reusables, para evitar terminar programando de más.

  1. Configuración del saludo
    En este caso usaremos un prefijo y un sufijo para nuestro saludo, donde el prefijo predeterminado será: "Hola mundo, desde ", y el sufijo tendrá 2 opciones de forma predefinida, permitiéndole al usuario elegir entre esas dos o bien crear un nuevo sufijo.
    • private $saludo = "Hola mundo, desde ";
    • private $desde = array( "normal" => "PHP.", "exolimpo" => "Exolimpo.com" );
  2. Variable de Salida
    Nuestra variable de salida donde se guardará todo hasta que necesitemos imprimirla. En este caso será privada para evitar que sea accedida directamente.
    • private $salida = '';
  3. Configuración de control de Errores 
    Necesitamos una variable que habilite o deshabilite en su totalidad el control de errores y definiremos la variable de salida para los errores, en este caso especificamos la cabecera(opcional). 
    • private $Error_activo = true;
    • private $Error = "<h3>Errores Encontrados:</h3>";
  4. Envoltorios del saludo y los errores (HTML):
    Definimos los envoltorios predefinidos; el usuario puede definir nuevos en la ejecución del programa.
    1. private $saludo_wrapper= "p";
    2. private $error_wrapper = "p";

class HolaMundo implements SaludandoMundos
{
	// Prefijo predefinido del saludo.
	private $saludo        = "Hola mundo, desde ";
	// Sufijo predefinido del saludo. 
	private $desde         = array(
                                "normal"   => "PHP.",
					"exolimpo" => "Exolimpo.com"
					);
	// Variable que contendrá todo el contenido.
	private $salida        = '';
	// Define si se mostrarán los errores.
	private $Error_activo  = true;
	// Cabecera, de la consola de errores y variable de salida para los errores.
	private $Error         = "<h3>Errores Encontrados:</h3>";
	// Etiqueta de envoltorio del saludo
	private $saludo_wrapper= "p";
	// Etiqueta de envoltorio para los errores.
	private $error_wrapper = "p";

4.2 Constructor

El constructor, es lo que se ejecuta apenas iniciamos la clase, por lo que aquí definiremos una pequeña característica: permitir que el usuario especifique que se genere el saludo de forma automática pasando true como parámetro al iniciar la clase:

	/**
	  * Constructor de nuestra aplicación
	  * @param auto bool $auto 
	  */
	public function __construct($auto = false)
	{
		if($auto)
		{
			// Aún no esta especificada: $this->ponSaludo('normal');
		}
	}

4.3 Métodos relacionados con el Saludo

Siguiendo la metodología de poner y dar. Crearemos dos funciones principales para el manejo de los saludos:

  1. public function ponSaludo($tipo, $mensaje = '')
    Este método es el más importante, y es el que construye el saludo usando el prefijo y los sufijos de acuerdo a lo que se especifique. Además de que tiene el control de errores por medio de try/catch.
  2. public function darSaludo()
    Este método es el responsable de devolver la variable privada de salida, para que se pueda imprimir el saludo.

Nota: Documenté lo mejor posible esta función línea por línea para que se entienda, si tiene alguna duda pueden hacerla por medio de comentario.


/**
  * Método que agrega el saludo a nuestra variable de salida.
  * @param $tipo string define el tipo de sufijo, usando uno predefinido o creandolo
  * @param $mensaje string define el nuevo sufijo
  */
public function ponSaludo($tipo, $mensaje = '')
{
	// Fragmento de control de excepciones
	try
	{
		// Verificamos si el "tipo" esta especificado en nuestra matríz de
		// sufijos predefinidos.
		if(isset($this->desde[$tipo]))
		{
			// El sufijo existe, por lo que lo guardamos en nuestra variable
			// de salida
			$this->salida .= '<'.$this->saludo_wrapper.'>'.$this->saludo.$this->desde[$tipo].'</'.$THIS->saludo_wrapper.'>';
		} else {
			// No se encontró, por lo que lanzamos una excepción
			throw new Exception('No existe el Saludo "'.$tipo.'", intentando crearlo...');
		}
	} catch (Exception $e) {
		// Atrapamos cualquier excepción y la guardamos usando nuestra función
		// de control de errores.
		$this->ponError($e->getMessage());
		// Fragmento secundario de excepciones
		try
		{
			// Verificamos si se especificó un mensaje:
			if($mensaje !== '')
			{
				// Se crea el sufijo, usando los dos elementos pasados en la
				// función.
				$this->desde[$tipo] = $mensaje;
				// Hacemos un llamado recursivo; el sufijo ya debe existir
				// porque fue creado.
				$this->ponSaludo($tipo);
			
			// No se pudo crear el saludo porque mensaje no fue especificado.
			} else {
				throw new Exception('No se pudo crear el nuevo saludo, $mensaje no fue definido en darSaludo().');
			}
		// Atrapamos la excepción y la guardamos.
		} catch(Exception $e) {
			$this->ponError($e->getMessage());
		}
	}
}

/**
 * Método que devuelve la salida, en string.
 * @return string Salida
*/
public function darSaludo()
{
	// Regresamos la variable de salida.
	return $this->salida;
}

4.4 Métodos relacionados con los Errores

Siguiendo la metodología de poner y dar. Crearemos dos funciones principales para el manejo de errores:

  1. public function ponError($tipo, $mensaje = '')
    Este método agrega los errores a la variable de salida de Errores siempre y cuando los Errores estén habilitados, ya que de lo contrario serán ignorados.
  2. public function darError()
    Este método es el responsable de devolver la variable privada de salida, para que se pueda imprimir el Error. Si los errores están habilitados se verificará que existe una error por medio de la longitud de la cadena.

Nota: Documenté lo mejor posible esta función línea por línea para que se entienda, si tiene alguna duda pueden hacerla por medio de comentario.


/**
 * Método que agrega el error a la variable de salida, dando formato al string.
 * @param $error string Error que se guardará en el string con formato.
 * @return boool
*/
public function ponError($error)
{
	// Vaerificamos que los errores esten habilitados.
	if ($this->Error_activo === true)
	{
		if( ! isset($this->Error_len))
		{
			// Guardamos la longitud de la cadena original
			// En caso de que exista una cabecera.
			$this->Error_len = mb_strlen($this->Error, "UTF-8");
		}
		// Guardamos el error en una variable de salida
		$this->Error .= '<'.$this->saludo_wrapper.'>'.$error.'</'.$THIS->saludo_wrapper.'>';
		return true;
	}
	return false;
}

/**
 * Método que imprime los errores. De no existir error se avisará.
 * @return string Errores
*/
public function darError()
{
	// Vaerificamos que los errores esten habilitados.
	if($this->Error_activo === true)
	{
		// Verificamos la longitud de la cadena Error post-errores con la longitud
		// pre-errores de la misma variable, para saber si agregó un error.
		if(mb_strlen($this->Error, "UTF-8") > $this->Error_len)
		{
			return $this->Error;
		} else {
			return '

No hay Error

'; } } }

5. Usando la aplicación

Para usar la aplicación simplemente tenemos que crear una nueva instancia y usar los métodos pon/dar, ejemplo:


// Creamos una nueva instancia de la clase.
$mundo = new HolaMundo();

// Ponemos un Saludo con sufijo existente.
$mundo->ponSaludo('normal');

// Ponemos un Saludo con sufijo existente.
$mundo->ponSaludo('exolimpo');

// Ponemos un Saludo con sufijo inexsitente, lo creamos.
$mundo->ponSaludo('extra', 'el mundo Extra, porque este mensaje es personalizado.');

// Saludo con sufijo inexistente:
$mundo->ponSaludo('crear');

// Imprimimos todos los saludos:
echo $mundo->darSaludo();

// Imrpimimos todos los Errores.
echo $mundo->darError();

Que imprime en el navegador lo siguiente:

image

6. Ejercicio Completo

Una vez completad todo el proceso deberíamos terminar con el siguiente código, completamente usable:


<?php

interface SaludandoMundos
{
	public function __construct($auto = false);
	public function ponSaludo($tipo, $mensaje = '');
	public function darSaludo();
	public function ponError($error);
	public function darError();
}

class HolaMundo implements SaludandoMundos
{
	// Prefijo predefinido del saludo.
	private $saludo        = "Hola mundo, desde ";
	// Sufijo predefinido del saludo. 
	private $desde         = array(
                                "normal"   => "PHP.",
					"exolimpo" => "Exolimpo.com"
					);
	// Variable que contendrá todo el contenido.
	private $salida        = '';
	// Define si se mostrarán los errores.
	private $Error_activo  = true;
	// Variable de salida de errores:
	private $Error         = "<h3>Errores Encontrados:</h3>";
	// Etiqueta de envoltorio del saludo
	private $saludo_wrapper= "p";
	// Etiqueta de envoltorio para los errores.
	private $error_wrapper = "p";
	
	/**
	  * Constructor de nuestra aplicación
	  * @param auto bool $auto 
	  */
	public function __construct($auto = false)
	{
		if($auto)
		{
			$this->ponSaludo('normal');
		}
	}
	/**
	  * Método que agrega el saludo a nuestra variable de salida.
	  * @param $tipo string define el tipo de sufijo, usando uno predefinido o creandolo
	  * @param $mensaje string define el nuevo sufijo
	  */
	public function ponSaludo($tipo, $mensaje = '')
	{
		// Fragmento de control de excepciones
		try
		{
			// Verificamos si el "tipo" esta especificado en nuestra matríz de
			// sufijos predefinidos.
			if(isset($this->desde[$tipo]))
			{
				// El sufijo existe, por lo que lo guardamos en nuestra variable
				// de salida
				$this->salida .= '<'.$this->saludo_wrapper.'>'.$this->saludo.$this->desde[$tipo].'</'.$THIS->saludo_wrapper.'>';
			} else {
				// No se encontró, por lo que lanzamos una excepción
				throw new Exception('No existe el Saludo "'.$tipo.'", intentando crearlo...');
			}
		} catch (Exception $e) {
			// Atrapamos cualquier excepción y la guardamos usando nuestra función
			// de control de errores.
			$this->ponError($e->getMessage());
			// Fragmento secundario de excepciones
			try
			{
				// Verificamos si se especificó un mensaje:
				if($mensaje !== '')
				{
					// Se crea el sufijo, usando los dos elementos pasados en la
					// función.
					$this->desde[$tipo] = $mensaje;
					// Hacemos un llamado recursivo; el sufijo ya debe existir
					// porque fue creado.
					$this->ponSaludo($tipo);
				
				// No se pudo crear el saludo porque mensaje no fue especificado.
				} else {
					throw new Exception('No se pudo crear el nuevo saludo, $mensaje no fue definido en darSaludo().');
				}
			// Atrapamos la excepción y la guardamos.
			} catch(Exception $e) {
				$this->ponError($e->getMessage());
			}
		}
	}
	
	/**
	 * Método que devuelve la salida, en string.
	 * @return string Salida
	*/
	public function darSaludo()
	{
		// Regresamos la variable de salida.
		return $this->salida;
	}
	
	/**
	 * Método que agrega el error a la variable de salida, dando formato al string.
	 * @param $error string Error que se guardará en el string con formato.
	 * @return boool
	*/
	public function ponError($error)
	{
		// Vaerificamos que los errores esten habilitados.
		if ($this->Error_activo === true)
		{
			if( ! isset($this->Error_len))
			{
				// Guardamos la longitud de la cadena original
				// En caso de que exista una cabecera.
				$this->Error_len = mb_strlen($this->Error, "UTF-8");
			}
			// Guardamos el error en una variable de salida
			$this->Error .= '<'.$this->saludo_wrapper.'>'.$error.'</'.$THIS->saludo_wrapper.'>';
			return true;
		}
		return false;
	}
	
	/**
	 * Método que imprime los errores. De no existir error se avisará.
	 * @return string Errores
	*/
	public function darError()
	{
		// Vaerificamos que los errores esten habilitados.
		if($this->Error_activo === true)
		{
			// Verificamos la longitud de la cadena Error post-errores con la longitud
			// pre-errores de la misma variable, para saber si agregó un error.
			if(mb_strlen($this->Error, "UTF-8") > $this->Error_len)
			{
				return $this->Error;
			} else {
				return '

No hay Error

'; } } } } // Creamos una nueva instancia de la clase. $mundo = new HolaMundo(); // Ponemos un Saludo con sufijo existente. $mundo->ponSaludo('normal'); // Ponemos un Saludo con sufijo existente. $mundo->ponSaludo('exolimpo'); // Ponemos un Saludo con sufijo inexsitente, lo creamos. $mundo->ponSaludo('extra', 'el mundo Extra, porque este mensaje es personalizado.'); // Saludo con sufijo inexistente: $mundo->ponSaludo('crear'); // Imprimimos todos los saludos: echo $mundo->darSaludo(); // Imrpimimos todos los Errores. echo $mundo->darError(); ?>

Conclusiones

Con esto concluimos con el ejercicio, en este caso el "hola mundo" fue una simple excusa para presentarles algunas buenas prácticas, controles de flujo, control de errores, matrices, visibilidad de métodos y variables, etc.

Les recuerdo que para cualquier duda, estoy a su completa disposición. Simplemente dejen una pregunta e intentaré aclararla lo ante posible.

Espero que este primer capitulo haya sido de su agrado, opiniones son bien recibidas :)

Respuestas a "[PHP] Re-aprendiendo #1: Hola Mundo para avanzados"