1. Introducción
La implementación de tipos de objetos obligatorios en PHP a veces puede ser muy importante. Si falta, ya sea por falta de conocimiento (basado en suposiciones de programación incorrectas o simplemente por pereza), verás resultados en tu aplicación web particular que no esperas. Especialmente cuando se programa en PHP 4, es muy fácil utilizar la función "is_a()" (aunque existen otros métodos) para verificar el tipo de objeto con el que estás trabajando. Por supuesto, forzar tipos de objetos también se puede utilizar para filtrar objetos de entrada que deben pasarse como parámetros a otras clases PHP en la misma aplicación.
Sin embargo, PHP 4 no expone algunas debilidades sobre su modelo de objetos; ocasionalmente puede requerir escribir código adicional para implementar ciertas características que se encuentran en lenguajes maduros orientados a objetos. Este hecho es conocido por la comunidad PHP desde hace mucho tiempo. Sin embargo, con el lanzamiento de PHP 5, muchas de estas características extremadamente valiosas se agregaron como parte del modelo de objetos mejorado. Ayudarán a implementar más estrechamente el desarrollo de código basado en objetos, permitiéndole utilizar características específicas de los objetos.
En el caso anterior, se debe tener especial cuidado cuando se trata de coerción de tipo objeto. De hecho, PHP 5 proporciona a los desarrolladores al menos dos formas de verificar los tipos de objetos durante la ejecución de una aplicación web: son el operador "instancia de" y la función "sugerencia de tipo". Pasando ahora al tema principal de este artículo, presentaré el uso del operador "instanceof" en PHP 5. Pronto descubrirás que puede ser muy conveniente para determinar si el objeto con el que estás trabajando pertenece a un tipo específico;
Este artículo le ayudará a comprender cómo implementar tipos de objetos obligatorios en PHP 5 a través de algunos ejemplos orientados a objetos.
2. Lo que no debes hacer
Para mostrar cómo implementar la coerción de tipo de objeto en PHP 5, usaré la clase de widget (X)HTML y una clase de creación de páginas simple, con modificaciones simples para adaptarse al entorno de desarrollo de PHP 5.
Mi primer ejemplo enumera algunas clases de widgets (X)HTML que se derivan de una clase base abstracta "HTMLElement", que omite verificar el tipo de sus objetos de entrada. Mire primero la siguiente clase:
//Defina la clase abstracta 'HTMLElement'
clase abstracta HTMLElement{
atributos $ protegidos;
función protegida __construct($atributos){
if(!is_array($atributos)){
lanzar nueva excepción ('Tipo de atributo no válido');
}
$this->atributos=$atributos;
}
// Método abstracto 'getHTML()' función protegida abstracta getHTML();
}
//Definir la clase específica 'Div'-extiende HTMLElement
clase Div extiende HTMLElement{
privado $salida='<div ';
datos privados $;
función pública __construct($atributos=matriz(),$datos){
padre::__construct($atributos);
$this->datos=$datos;
}
// La implementación específica del método 'getHTML()' public function getHTML(){
foreach($this->atributos como $atributo=>$valor){
$this->output.=$atributo.'="'.$valor.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=$this->data.'</div>';
devolver $this->salida;
}
}
//Definimos la clase concreta 'Header1' - extiende HTMLElement
clase Header1 extiende HTMLElement{
privado $salida='<h1 ';
datos privados $;
función pública __construct($atributos=matriz(),$datos){
padre::__construct($atributos);
$this->datos=$datos;
}
// La implementación específica del método 'getHTML()' public function getHTML(){
foreach($this->atributos como $atributo=>$valor){
$this->output.=$atributo.'="'.$valor.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=$this->datos.'</h1>';
devolver $this->salida;
}
}
//Definir la clase concreta 'Párrafo' - extiende HTMLElement
El párrafo de clase extiende HTMLElement{
privado $salida='<p ';
datos privados $;
función pública __construct($atributos=matriz(),$datos){
padre::__construct($atributos);
$this->datos=$datos;
}
// La implementación específica del método 'getHTML()' public function getHTML(){
foreach($this->atributos como $atributo=>$valor){
$this->output.=$atributo.'="'.$valor.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=$this->datos.'</p>';
devolver $this->salida;
}
}
//Definir la clase concreta 'UnorderedList' - extiende HTMLElement
clase ListaUnorderedExtiende HTMLElement{
privado $salida='<ul ';
privado $elementos=matriz();
función pública __construct($atributos=matriz(), $elementos=matriz()){
padre::__construct($atributos);
si(!is_array($elementos)){
throw new Exception('Parámetro no válido para elementos de la lista');
}
$this->items=$items;
}
// La implementación específica del método 'getHTML()' public function getHTML(){
foreach($this->atributos como $atributo=>$valor){
$this->output.=$atributo.'="'.$valor.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
foreach($this->elementos como $elemento){
$this->output.='<li>'.$item.'</li>';
}
$this->salida.='</ul>';
devolver $this->salida;
}
}
Como puedes ver, las clases de widget (X)HTML anteriores son muy útiles para generar elementos específicos en una web, pero escribí intencionalmente el código para cada clase para que no puedan validar la efectividad de los parámetros de entrada. Como habrás imaginado, los parámetros de entrada se pasan directamente al constructor de la clase y se asignan como propiedades. Surge la pregunta: ¿hay algo de malo en hacer esto? Sí, lo hay. Ahora, voy a definir mi clase de creación de páginas más simple y la alimentaré con widgets como este para que puedas ver cómo la entrada a esta clase se mezcla con objetos incorrectos. Aquí está la firma de la clase generadora de páginas:
clase PageGenerator{
privado $salida='';
título $ privado;
función pública __construct($title='Página predeterminada'){
$this->título=$título;
}
función pública hacerEncabezado(){
$this->output='<html><head><title>'.$this-
>título.'</título></cabeza><cuerpo>';
}
función pública addHTMLElement($htmlElement){
$this->output.=$htmlElement->getHTML();
}
función pública doFooter(){
$this->output.='</body></html>';
}
función pública buscarHTML(){
devolver $this->salida;
}
}
Ahora, comenzamos a crear instancias de algunos objetos de widget (X)HTML y a pasarlos a las clases generadoras correspondientes, como se muestra en el siguiente ejemplo:
try{
//Generar algunos elementos HTML $h1=new Header1(array('name'=>'header1', 'class'=>'headerclass'), 'Contenido para H1
elemento va aquí');
$div=new Div(array('name'=>'div1','class'=>'divclass'),'Contenido del elemento Div
va aquí');
$par=new Paragraph(array('name'=>'par1','class'=>'parclass'),'Contenido del párrafo
elemento va aquí');
$ul=new UnorderedList(array ('nombre'=>'lista1', 'clase'=>'listaclase'), matriz
('elemento1'=>'valor1', 'elemento2'=>'valor2', 'elemento3'=>'valor3'));
//Crear una instancia de la clase generadora de páginas $pageGen=new Page Generator();
$pageGen->doHeader();
//Agregar objeto 'HTMLElement' $pageGen->addHTMLElement($h1);
$pageGen->addHTMLElement($div);
$pageGen->addHTMLElement($par);
$pageGen->addHTMLElement($ul);
$pageGen->doFooter();
//Mostrar página web echo $pageGen->fetchHTML();
}
captura(Excepción $e){
echo $e->getMessage();
salida();
}
Después de ejecutar el código PHP anterior, el resultado que obtiene es una página web simple: contiene algunos objetos (X)HTML creados anteriormente. En este caso, es fácil entender qué sucederá si por alguna razón la clase de creación de páginas recibe un objeto incorrecto y llama a su método "addHTML()". Aquí, he reelaborado la condición de conflicto, usando un objeto widget HTML (X) inexistente. Mire el siguiente código nuevamente:
intente {
//Generar algunos elementos HTML $h1=new Header1(array('name'=>'header1', 'class'=>'headerclass'), 'Contenido para H1
elemento va aquí');
$div=new Div(array('name'=>'div1','class'=>'divclass'),'Contenido del elemento Div
va aquí');
$par=new Paragraph(array('name'=>'par1','class'=>'parclass'),'Contenido del párrafo
elemento va aquí');
$ul=new UnorderedList(array ('nombre'=>'lista1', 'clase'=>'listaclase'), matriz
('elemento1'=>'valor1', 'elemento2'=>'valor2', 'elemento3'=>'valor3'));
//Crear una instancia de la clase generadora de páginas $pageGen=new Page Generator();
$pageGen->doHeader();
//Agregar objeto 'HTMLElement' $pageGen->addHTMLElement($fakeobj) //Pasar objeto inexistente a este método $pageGen->addHTMLElement($div);
$pageGen->addHTMLElement($par);
$pageGen->addHTMLElement($ul);
$pageGen->doFooter();
// Mostrar la página echo $pageGen->fetchHTML();
}
captura(Excepción $e){
echo $e->getMessage();
salida();
}
En este caso, como se muestra en la siguiente línea:
$pageGen->addHTMLElement($fakeobj)//Pasar objeto inexistente a este método.
Se pasa un objeto widget HTML (X)inexistente a la clase generadora de páginas, esto resultará en un error fatal:
Error fatal: llamada a una función miembro en un no objeto en
¿Qué pasa con
la ruta/al/archivo
?¡Esta es una penalización directa por no verificar el tipo de objeto pasado a la clase generadora! Así que asegúrese de tener esto en cuenta al escribir sus guiones. Afortunadamente, existe una solución sencilla para estos problemas, y aquí es donde entra en juego el poder del operador "instanceof". Si quieres ver cómo se utiliza este operador, sigue leyendo.
3. Utilice el operador "instanceof"
Como puede ver, el uso del operador "instanceof" es muy simple. Utiliza dos parámetros para completar su función. El primer parámetro es el objeto que desea verificar y el segundo parámetro es el nombre de la clase (en realidad, un nombre de interfaz) utilizado para determinar si el objeto es una instancia de la clase correspondiente. Por supuesto, utilicé la terminología anterior intencionalmente para que puedas ver cuán intuitivo es el uso de este operador. Su sintaxis básica es la siguiente:
if (objeto instancia del nombre de la clase){
//Haz algo útil
}
Ahora que comprende cómo se usa este operador en PHP 5, definamos la clase de creación de páginas web correspondiente para verificar el tipo de objeto pasado a su método "addHTMLElement()". Aquí está la nueva firma de esta clase, que mencioné anteriormente utiliza el operador "instanceof":
clase PageGenerator{
privado $salida='';
título $ privado;
función pública __construct($title='Página predeterminada'){
$this->título=$título;
}
función pública hacerEncabezado(){
$this->output='<html><cabeza><título>'.$this->título.'</título></cabeza><cuerpo>';
}
función pública addHTMLElement($htmlElement){
if(!$htmlElement instancia de HTMLElement){
lanzar nueva excepción ('elemento HTML (X) no válido');
}
$this->output.=$htmlElement->getHTML();
}
función pública doFooter(){
$this->output.='</body></html>';
}
función pública buscarHTML(){
devolver $this->salida;
}
}
Tenga en cuenta, en la clase anterior, cómo el operador "instanceof" se incluye en el método "addHTMLElement()" para garantizar que todos los objetos pasados sean instancias de la clase "HTMLElement" definida anteriormente. Ahora es posible reconstruir la página web que vio anteriormente, en cuyo caso asegúrese de que todos los objetos de entrada pasados a la clase de creación de páginas web sean objetos de widget HTML (X) reales. Aquí está el ejemplo correspondiente:
intente {
//Generar algunos elementos HTML $h1=new Header1(array('name'=>'header1', 'class'=>'headerclass'), 'El contenido del elemento H1 va aquí');
$div=new Div(array('name'=>'div1', 'class'=>'divclass'), 'El contenido del elemento Div va aquí');
$par=new Paragraph(array('name'=>'par1','class'=>'parclass'),'El contenido del elemento Paragraph va aquí');
$teststr='Esto no es un elemento HTML';
//Crear una instancia de la clase generadora de páginas $pageGen=new Page Generator();
$pageGen->doHeader();
//Agregar objeto 'HTMLElement' $pageGen->addHTMLElement($teststr) //Pasar una cadena simple a este método $pageGen->addHTMLElement($h1);
$pageGen->addHTMLElement($div);
$pageGen->addHTMLElement($par);
$pageGen->doFooter();
//Mostrar página web echo $pageGen->fetchHTML();
}
captura(Excepción $e){
echo $e->getMessage();
salida();
}
Como ha visto en el ejemplo anterior, estoy pasando una cadena de prueba simple (no un objeto "HTMLElement") a la clase de creación de páginas, lo que generará una excepción, detectada por un bloque "catch" específico, como se muestra a continuación:
Elemento HTML (X) no válido
En este momento, para determinar la validez del objeto de entrada, utilicé el operador "instanceof", para que la página web anterior pueda ser. Espero que realmente puedan apreciar la importancia de filtrar la entrada para Los métodos de su clase para evitar errores extraños al usar este operador. Entrada de datos
Después de mostrar la implementación correcta del operador "instanceof" dentro de la clase generadora de páginas web, hay más cosas que hacer similares a las que escribí para PHP 4 en el artículo anterior. (X). Para las clases de widgets HTML, me gustaría incluir este operador como parte de su método "getHTML()", permitiendo así la creación de páginas web que generen elementos (X)HTML anidados. Analicemos cómo se logra esto.
4. Amplíe el uso del operador "instanceof": los widgets HTML (X) anidados
son buenos. Ha visto que el operador "instanceof" funciona bien en la verificación de tipos en objetos de entrada que se inyectan directamente en la funcionalidad del generador de páginas. Ahora, iré un paso más allá y agregaré una rutina de verificación al constructor y al método "getHTML()" de la clase de widget (X)HTML para que puedan aceptar otros widgets como parámetros de entrada. Verifique las mejoras a continuación.
clase Div extiende HTMLElement{
privado $salida='<div ';
datos privados $;
función pública __construct($atributos=matriz(),$datos){
if(!$instancia de datos de HTMLElement&&!is_string($datos)){
lanzar nueva excepción ('Tipo de parámetro no válido');
}
padre::__construct($atributos);
$this->datos=$datos;
}
// La implementación específica del método 'getHTML()' public function getHTML(){
foreach($this->atributos como $atributo=>$valor){
$this->output.=$atributo.'="'.$valor.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=($this->instancia de datos de HTMLElement)?
$esto->datos->getHTML():$esto->datos;
$this->output.='</div>';
devolver $this->salida;
}
}
clase Header1 extiende HTMLElement{
privado $salida='<h1 ';
datos privados $;
función pública __construct($atributos=matriz(),$datos){
if(!$instancia de datos de HTMLElement&&!is_string($datos)){
lanzar nueva excepción ('Tipo de parámetro no válido');
}
padre::__construct($atributos);
$this->datos=$datos;
}
// La implementación específica del método 'getHTML()' public function getHTML(){
foreach($this->atributos como $atributo=>$valor){
$this->output.=$atributo.'="'.$valor.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=($this->instancia de datos de HTMLElement)?
$esto->datos->getHTML():$esto->datos;
$this->salida.='</h1>';
devolver $this->salida;
}
}
El párrafo de clase extiende HTMLElement{
privado $salida='<p ';
datos privados $;
función pública __construct($atributos=matriz(),$datos){
if(!$instancia de datos de HTMLElement&&!is_string($datos)){
lanzar nueva excepción ('Tipo de parámetro no válido');
}
padre::__construct($atributos);
$this->datos=$datos;
}
// La implementación específica del método 'getHTML()' public function getHTML(){
foreach($this->atributos como $atributo=>$valor){
$this->output.=$atributo.'="'.$valor.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
$this->output.=($this->instancia de datos de HTMLElement)?
$esto->datos->getHTML():$esto->datos;
$this->salida.='</p>';
devolver $this->salida;
}
}
clase ListaUnorderedExtiende HTMLElement{
privado $salida='<ul ';
privado $elementos=matriz();
función pública __construct($atributos=matriz(), $elementos=matriz()){
padre::__construct($atributos);
si(!is_array($elementos)){
throw new Exception('Parámetro no válido para elementos de la lista');
}
$this->items=$items;
}
//La implementación específica del método 'getHTML()'
función pública getHTML(){
foreach($this->atributos como $atributo=>$valor){
$this->output.=$atributo.'="'.$valor.'" ';
}
$this->output=substr_replace($this->output,'>',-1);
foreach($this->elementos como $elemento){
$this->output.=($item instancia de
HTMLElement)?'<li>'.$item->getHTML().'</li>':'<li>'.$item.'</li>';
}
$this->salida.='</ul>';
devolver $this->salida;
}
}
Como se muestra en las clases anteriores, para permitir que se implementen elementos (X)HTML anidados al generar las páginas web correspondientes, refactoricé sus constructores y métodos "getHTML()" respectivamente. Tenga en cuenta que incluí el siguiente bloque condicional en el constructor de cada clase:
if(!$datastanceofHTMLElement&&!is_string($data)){
lanzar nueva excepción ('Tipo de parámetro no válido');
}
En este punto, lo que realmente hago es asegurarme de que sólo se permitan datos de cadena y objetos de tipo "HTMLElement" como parámetros de entrada para cada clase. De lo contrario, el método respectivo generará una excepción y puede provocar que la aplicación detenga la ejecución. Entonces, este es el proceso de verificar los datos de entrada. Ahora, veamos la nueva firma del método "getHTML()", que también usa el operador "instanceof":
$this->output.=($this->datastanceofHTMLElement)?$this->data-
>getHTML():$this->data;
Como puede ver, en este caso, el operador this es muy útil para aprovechar las características polimórficas de la clase de widget (X)HTML. Si el atributo $data también es un widget, entonces su método "getHTML()" se llamará correctamente, lo que hará que se muestre el elemento web anidado. Por otro lado, si es solo una cadena, se agrega directamente a todas las salidas de la clase actual.
En este punto, es posible que haya comprendido el uso del operador "instanceof" en PHP 5 para garantizar que ciertos objetos pertenezcan a un tipo específico. Como puedes ver en este artículo, coaccionar tipos de objetos en PHP 5 es en realidad una tarea bastante sencilla. Por ahora, será mejor que desarrolles un ejemplo del uso de este método para filtrar objetos en tu aplicación PHP para profundizar tu comprensión.
5. Resumen
En este artículo, aprendiste cómo usar el operador "instanceof" en PHP 5 para verificar el tipo de tu objeto de entrada; sin embargo, el método que te mostré no es el único; En un artículo posterior, le explicaré cómo implementar la característica "sugerencia de tipo" en PHP 5, que es otra forma de imponer la escritura de objetos.
Autor: Compilador Zhu Xianzhong Fuente: Tianji Development