Texto/Compilado por Zhu Xianzhong
1. Introducción
Afortunadamente, la tecnología de sobrecarga de objetos se introdujo en PHP 5.0. Este artículo explorará la posibilidad de sobrecargar los métodos __call(), __set() y __get(). Después de una breve introducción a la teoría de la sobrecarga, iremos directamente al tema a través de dos ejemplos: el primer ejemplo es implementar una clase de almacenamiento persistente, el segundo ejemplo es encontrar una manera de implementar un captador/definidor dinámico.
2. ¿Qué es la sobrecarga de objetos?
Cuando hablamos de sobrecarga de objetos en PHP, tenemos que distinguir dos tipos:
·Sobrecarga de métodos
·Sobrecarga de atributos
En el caso de sobrecarga de métodos, tenemos que definir un método mágico __call(), que implementará una llamada genérica a un método indefinido. en la clase correspondiente. Este método general se llama solo cuando desea acceder a un método no definido en la clase. Sin sobrecarga de métodos, el siguiente ejemplo hará que PHP muestre un mensaje de error fatal: Llame al método no definido ThisWillFail::bar() en/some/directory/example.php en la línea 9 y cancele la ejecución del programa:
< ?php
clase EstoFallará {
función pública foo() {
devolver "¡Hola mundo!";
}
}
$clase = nuevo ThisWillFail;
$clase->bar();
?>
Con la ayuda de la sobrecarga de métodos, el código puede captar esta llamada y manejarla con elegancia.
La sobrecarga de propiedades es similar a la sobrecarga de métodos. En este caso, la clase redirige (también llamada proxy) operaciones de lectura/escritura a propiedades de la clase que no están definidas explícitamente en la clase. Los métodos especializados aquí son __set() y __get(). Dependiendo del nivel de informe de errores, el traductor de PHP generalmente emitirá una notificación al acceder a una propiedad no definida o diferirá y potencialmente definirá la variable. Si utiliza la sobrecarga de atributos, el traductor puede llamar a __set() al configurar un atributo indefinido y llamar a __get() al acceder a un valor de atributo indefinido.
En resumen, el uso de tecnología de sobrecarga puede acortar en gran medida el tiempo de desarrollo de software cuando se utilizan lenguajes dinámicos como PHP.
En este punto, se presenta la teoría y la codificación específica se analiza a continuación.
3. Ejemplos de clases de almacenamiento persistente
El siguiente código implementa la clase de almacenamiento persistente mencionada anteriormente con menos de 50 líneas de código PHP mediante el uso de tecnología de sobrecarga de atributos. El término persistente significa que la clase puede describir un elemento de una estructura de datos y permanecer sincronizada con el sistema de almacenamiento subyacente. En términos de codificación, el código externo puede usar clases para seleccionar una fila de una tabla de base de datos. De esta forma, cuando el programa se está ejecutando, puede acceder directamente a los atributos de la clase para manipular los elementos de la fila (lectura/búsqueda). Al final del script, PHP será responsable de enviar los datos de la fila actualizados a la base de datos.
Estudiar detenidamente el siguiente código le ayudará a comprender qué es la sobrecarga de atributos.
<?php
//Carga el <a href=" http://pear.php.net/package/DB/ "> paquete DB</a> de PEAR
require_once "DB.php";
clase persistente {
privado $datos = matriz();
privado $tabla = "usuarios";
función pública __construct($usuario) {
$this->dbh = DB::Connect("mysql://usuario:contraseña@localhost/base de datos");
$consulta = "SELECCIONAR identificación, nombre, correo electrónico, país DE ".
$this->table "DONDE nombre =?";
$this->data = $this->dbh->getRow($consulta, matriz($usuario),
DB_FETCHMODE_ASSOC);
}
función pública __get($miembro) {
if (isset($this->datos[$miembro])) {
devolver $this->datos[$miembro];
}
}
función pública __set($miembro, $valor) {
//El ID del conjunto de datos es de solo lectura if ($member == "id") {
devolver;
}
if (isset($this->datos[$miembro])) {
$this->datos[$miembro] = $valor;
}
}
función pública __destruct() {
$consulta = "ACTUALIZAR" $this->table "SET nombre =?,
correo electrónico =?, país =?
$this->dbh->query($consulta, $this->nombre, $this->correo electrónico,
$este->país, $este->id);
}
}
$clase = nueva Persistente("Martin Jansen");
$clase->nombre = "Juan Pérez";
$clase->país = "Estados Unidos";
$clase->correo electrónico = " [email protected] ";
?>
El primer problema que puede encontrar es __construct(), el nuevo método constructor introducido en PHP 5. En los días de PHP 4, los constructores siempre coincidían con los nombres de sus clases. Este ya no es el caso en PHP 5. No necesita saber mucho sobre el método constructor, excepto que llamarlo crea una instancia de una clase y observe que aquí se usa un parámetro: se ejecuta una base de datos en función de este parámetro; Este constructor asigna los resultados de la consulta al atributo de clase $data.
A continuación, el programa define dos métodos especiales __get() y __set(). Ya deberías estar familiarizado con ellos: __get() se usa para leer valores de atributos indefinidos y __set() se usa para modificar valores de atributos indefinidos.
Esto significa que siempre que se lee/escribe una propiedad indefinida desde una clase de almacenamiento persistente, estos métodos especializados son responsables de administrar la información en la variable de matriz de propiedades $data, en lugar de cambiar directamente las propiedades de la clase (recuerde: la variable $data contiene una fila de la base de datos!).
El último método de una clase es lo opuesto a __construct(): el destructor __destruct(). PHP llama al destructor durante la "fase de cierre del script", que normalmente está cerca del final de la ejecución de un script PHP. El destructor escribe la información del atributo $data en la base de datos. Esto es exactamente lo que significa el término anterior sincronización.
Es posible que hayas notado que el código aquí utiliza el paquete de capa de abstracción de base de datos de PEAR. De hecho, no importa. Comunicarse con la base de datos a través de otros métodos también puede ilustrar el tema de este artículo.
Si observa detenidamente, encontrará que la descripción de esta clase de almacenamiento persistente es relativamente simple. El ejemplo solo involucra una tabla de base de datos y no considera modelos de datos más complejos, como el uso de LEFT JOIN y otras técnicas complejas de operación de bases de datos. Sin embargo, no es necesario que esté sujeto a esto y, con la ayuda de la sobrecarga de propiedades, puede utilizar su propio modelo de base de datos ideal. Con solo un poco de código, puede aprovechar las funciones complejas de la base de datos en esta clase de almacenamiento persistente.
También hay un pequeño problema: no se introduce ningún mecanismo de manejo de errores cuando la consulta falla en el destructor. Es la naturaleza de los destructores la que hace imposible mostrar un mensaje de error apropiado en este caso, porque la creación del marcado HTML a menudo finaliza antes de que PHP llame al destructor.
Para resolver este problema, puede cambiar el nombre de __destruct() a algo como saveData() y ejecutar este método manualmente en algún lugar del script de llamada. Esto no cambia el concepto de almacenamiento persistente para las clases; son solo unas pocas líneas más de código. Alternativamente, puede usar la función error_log() en el destructor para registrar el mensaje de error en un archivo de registro de errores de todo el sistema.
Así funciona la sobrecarga de propiedades. A continuación analizamos la sobrecarga de métodos.
4. Ejemplos de sobrecarga de métodos
1. Métodos Getter/Setter dinámicos
El siguiente código implementa los métodos getter/setter "dinámicos" para controlar la clase con la ayuda de la sobrecarga de métodos. Analicémoslo según el código fuente:
<?php
clase DynamicGetterSetter {
privado $nombre = "Martin Jansen";
private $starbucksdrink = "Remolino de capuchino y caramelo";
función __call($método, $argumentos) {
$prefijo = strtolower(substr($método, 0, 3));
$propiedad = strtolower(substr($método, 3));
if (vacío($prefijo) || vacío($propiedad)) {
devolver;
}
if ($prefijo == "obtener" && isset($this->$property)) {
devolver $this->$propiedad;
}
si ($prefijo == "establecer") {
$this->$propiedad = $argumentos[0];
}
}
}
$clase = nuevo DynamicGetterSetter;
echo "Nombre: " $clase->getName() "n";
echo "Sabor favorito de Starbucks: " $class->getStarbucksDrink() "nn";
$clase->setName("Juan Pérez");
$clase->setStarbucksDrink("Café clásico");
echo "Nombre: " $clase->getName() "n";
echo "Sabor favorito de Starbucks: " $class->getStarbucksDrink() "nn";
?>
Obviamente, los dos atributos $name y $starbucksdrink aquí son privados, lo que significa que no se puede acceder a estos atributos desde fuera de la clase. En la programación orientada a objetos, es muy común implementar métodos getter/setter públicos para acceder o modificar los valores de propiedades no públicas. Implementarlos es tedioso y requiere tiempo y esfuerzo.
Este problema se puede resolver fácilmente con la ayuda de la sobrecarga de métodos. En lugar de implementar métodos getter/setter para cada propiedad, lo anterior solo implementa un método __call() general. Esto significa que cuando se llama a un método getter/setter indefinido como setName() o getStarbucksdrink(), PHP no generará un error fatal ni abortará, sino que ejecutará (o delegará) el método mágico __call().
Estas son algunas breves introducciones. Hagamos un análisis en profundidad de __call().
2. Análisis detallado del método __call ().
El primer parámetro de __call () es el método original e indeterminado (como setName). El segundo parámetro es una matriz unidimensional con un índice numérico, que contiene todos los métodos originales. parámetro. Llamar a un método indefinido con dos parámetros ("Martin" y 42) producirá la siguiente matriz:
$class->thisMethodDoesNotExist("Martin", 42);
/Guía para el segundo parámetro de __call()
Formación
(
[0] => Martín
[1] => 42
)
Dentro del método __call(), si el método original comienza con get o set, se deben realizar algunos cálculos para determinar si el código llama a un método getter/setter. Además, este método analizará más a fondo otro componente del nombre del método (excepto los primeros tres caracteres), porque la última parte de la cadena representa el nombre del atributo al que hace referencia el captador/definidor.
Si el nombre del método indica un captador/definidor, entonces el método devuelve el valor de propiedad correspondiente o establece el valor del primer parámetro del método original. Si no, no hace nada y continúa ejecutando el programa como si nada.
3. Para lograr el objetivo
En esencia, correspondiente a cualquier atributo, existe un método que permite que el código llame dinámicamente a cualquier método getter/setter. Este algoritmo existe. Esto es conveniente cuando se desarrolla un prototipo de programa a corto plazo: en lugar de dedicar mucho tiempo a implementar captadores/definidores, el desarrollador puede concentrarse en modelar la API y garantizar que la aplicación sea fundamentalmente correcta. Incorporar el método __call() en una clase abstracta puede incluso permitirle reutilizar el código en el desarrollo futuro de proyectos PHP
4. ¡Además de las deficiencias,
existen ventajas y desventajas! El enfoque anterior tiene varios inconvenientes: los proyectos más grandes pueden usar herramientas como phpDocumentor para rastrear la estructura de la API. Con el método dinámico presentado anteriormente, por supuesto, todos los métodos getter/setter no aparecerán en el documento generado automáticamente, lo que no requiere más explicación.
Otro inconveniente es que el código fuera de la clase puede acceder a todas las propiedades privadas dentro de la clase. Cuando se utilizan métodos captadores/definidores reales, es posible distinguir entre propiedades privadas a las que se puede acceder mediante código externo y propiedades privadas "reales" que no son visibles fuera de la clase, porque tenemos sobrecarga de métodos y tenemos captadores y definidores virtuales. Se pueden utilizar métodos.
5. Conclusión
Este artículo analiza cuidadosamente las dos situaciones de sobrecarga de objetos en PHP 5.0 a través de dos ejemplos. Tengo muchas esperanzas de que el método de este artículo pueda ayudarle a mejorar la eficiencia de la programación PHP. Al mismo tiempo, también debería ver claramente las deficiencias de este método.