Texte/Compilé par Zhu Xianzhong
1. Introduction
Heureusement, la technologie de surcharge d'objets a été introduite dans PHP 5.0. Cet article explorera la possibilité de surcharger les méthodes __call(), __set() et __get(). Après une brève introduction à la théorie de la surcharge, nous passerons directement au sujet à travers deux exemples : le premier exemple consiste à implémenter une classe de stockage persistante ; le deuxième exemple consiste à trouver un moyen d'implémenter un getter/setter dynamique.
2. Qu'est-ce que la surcharge d'objets ?
Lorsqu'on parle de surcharge d'objets en PHP, il faut distinguer deux types :
· Surcharge de méthodes
· Surcharge d'attributs
Dans le cas de surcharge de méthodes, il faut définir une méthode magique __call(), qui implémentera un appel générique à une méthode non définie. dans la classe correspondante. Cette méthode générale est appelée uniquement lorsque vous souhaitez accéder à une méthode non définie dans la classe. Sans surcharge de méthode, l'exemple suivant provoquera l'affichage par PHP d'un message d'erreur fatal : Appel à la méthode non définie ThisWillFail::bar() dans/some/directory/example.php à la ligne 9 et abandon de l'exécution du programme :
< ?php
classe ThisWillFail {
fonction publique foo() {
renvoyer « Bonjour tout le monde ! » ;
}
}
$class = nouveau ThisWillFail ;
$class->bar();
?>
Grâce à la surcharge de méthodes, le code peut intercepter cet appel et le gérer avec élégance.
La surcharge de propriétés est similaire à la surcharge de méthodes. Dans ce cas, la classe redirige (également appelée proxy) les opérations de lecture/écriture vers des propriétés de la classe qui ne sont pas explicitement définies dans la classe. Les méthodes spécialisées ici sont __set() et __get(). En fonction du niveau de rapport d'erreurs, le traducteur PHP émettra généralement une notification lors de l'accès à une propriété non définie, ou différera et définira potentiellement la variable. Si vous utilisez la surcharge d'attributs, le traducteur peut appeler __set() lors de la définition d'un attribut non défini et appeler __get() lors de l'accès à une valeur d'attribut non définie.
Pour résumer, l’utilisation de technologies de surcharge peut réduire considérablement le temps de développement logiciel lors de l’utilisation de langages dynamiques tels que PHP.
À ce stade, la théorie est introduite et le codage spécifique est analysé ci-dessous.
3. Exemples de classes de stockage persistantes
Le code suivant implémente la classe de stockage persistante mentionnée ci-dessus avec moins de 50 lignes de code PHP en utilisant la technologie de surcharge d'attributs. Le terme persistant signifie que la classe peut décrire un élément d'une structure de données et rester synchronisée avec le système de stockage sous-jacent. En termes de codage, le code externe peut utiliser des classes pour sélectionner une ligne dans une table de base de données. De cette façon, lorsque le programme est en cours d'exécution, vous pouvez accéder directement aux attributs de la classe pour manipuler les éléments de la ligne (lecture/récupération). À la fin du script, PHP se chargera de renvoyer les données de ligne mises à jour à la base de données.
Étudier attentivement le code suivant vous aidera à comprendre ce qu'est la surcharge d'attributs.
<?php
//Charger le <a href=" http://pear.php.net/package/DB/ "> DB package</a> de PEAR
require_once "DB.php" ;
classe Persistable {
privé $données = tableau();
private $table = "utilisateurs" ;
fonction publique __construct ($ utilisateur) {
$this->dbh = DB::Connect("mysql://user:password@localhost/database");
$query = "SELECT identifiant, nom, email, pays FROM " .
$this->table . " OÙ nom = ? ";
$this->data = $this->dbh->getRow($query, array($user),
DB_FETCHMODE_ASSOC);
}
fonction publique __get($membre) {
if (isset($this->data[$member])) {
return $this->data[$member];
}
}
fonction publique __set ($ membre, $ valeur) {
//L'ID de l'ensemble de données est en lecture seule if ($member == "id") {
retour;
}
if (isset($this->data[$member])) {
$this->data[$member] = $value;
}
}
fonction publique __destruct() {
$query = "UPDATE " . $this->table . " SET nom = ?,
email = ?, pays = ? OÙ id = ?";
$this->dbh->query($query, $this->name, $this->email,
$this->pays, $this->id);
}
}
$class = new Persistable("Martin Jansen");
$class->name = "John Doe";
$class->country = "États-Unis" ;
$class->email = " [email protected] ";
?>
Le premier problème que vous pourriez rencontrer est __construct(), la nouvelle méthode constructeur introduite dans PHP 5. À l'époque de PHP 4, les constructeurs correspondaient toujours à leurs noms de classe. Ce n'est plus le cas en PHP 5. Vous n'avez pas besoin de connaître grand-chose sur la méthode constructeur, sauf que son appel crée une instance d'une classe et remarquez qu'un paramètre est utilisé ici - une base de données est exécutée en fonction de ce paramètre. Ce constructeur attribue les résultats de la requête à l'attribut de classe $data.
Ensuite, le programme définit deux méthodes spéciales __get() et __set(). Vous devriez déjà les connaître : __get() est utilisé pour lire des valeurs d'attribut non définies et __set() est utilisé pour modifier des valeurs d'attribut non définies.
Cela signifie que chaque fois qu'une propriété non définie est lue/écrite à partir d'une classe de stockage persistante, ces méthodes spécialisées sont responsables de la gestion des informations dans la variable du tableau de propriétés $data, plutôt que de modifier directement les propriétés de la classe (rappelez-vous : la variable $data contient une ligne de la base de données !).
La dernière méthode d'une classe est l'opposé de __construct() - le destructeur __destruct(). PHP appelle le destructeur pendant la « phase d'arrêt du script », qui se situe généralement vers la fin de l'exécution d'un script PHP. Le destructeur réécrit les informations de l'attribut $data dans la base de données. C’est exactement ce que signifie le terme précédent synchronisation.
Vous avez peut-être remarqué que le code ici utilise le package de couche d'abstraction de base de données de PEAR. En fait, cela n'a pas d'importance. Communiquer avec la base de données par d'autres méthodes peut également illustrer le thème de cet article.
Si vous regardez attentivement, vous constaterez que la description de cette classe de stockage persistant est relativement simple. L'exemple implique uniquement une table de base de données et ne prend pas en compte des modèles de données plus complexes, tels que l'utilisation de LEFT JOIN et d'autres techniques d'exploitation de bases de données complexes. Cependant, vous n'êtes pas obligé d'être lié par cela et, grâce à la surcharge de propriétés, vous pouvez utiliser votre propre modèle de base de données idéal. Avec juste un peu de code, vous pouvez profiter des fonctionnalités de bases de données complexes de cette classe de stockage persistant.
Il existe également un petit problème : aucun mécanisme de gestion des erreurs n'est introduit lorsque la requête échoue dans le destructeur. C'est la nature des destructeurs qui rend impossible l'affichage d'un message d'erreur approprié dans ce cas, car la construction du balisage HTML se termine souvent avant que PHP n'appelle le destructeur.
Pour résoudre ce problème, vous pouvez renommer __destruct() en quelque chose comme saveData() et exécuter cette méthode manuellement quelque part dans le script appelant. Cela ne change pas le concept de stockage persistant pour les classes ; ce sont juste quelques lignes de code supplémentaires. Vous pouvez également utiliser la fonction error_log() dans le destructeur pour enregistrer le message d'erreur dans un fichier journal des erreurs à l'échelle du système.
C’est ainsi que fonctionne la surcharge de propriété. Nous discutons ensuite de la surcharge des méthodes.
4. Exemples de surcharge de méthodes
1. Méthodes Getter/Setter dynamiques
Le code suivant implémente les méthodes getter/setter « dynamiques » pour contrôler la classe à l'aide de la surcharge de méthodes. Analysons-le en fonction du code source :
<?php
classe DynamicGetterSetter {
privé $nom = "Martin Jansen" ;
privé $starbucksdrink = "Tourbillon de cappuccino au caramel" ;
fonction __call($méthode, $arguments) {
$prefix = strtolower(substr($method, 0, 3));
$property = strtolower(substr($method, 3));
if (vide ($ préfixe) || vide ($ propriété)) {
retour;
}
if ($prefix == "get" && isset($this->$property)) {
renvoie $this->$property ;
}
si ($préfixe == "set") {
$this->$property = $arguments[0];
}
}
}
$class = nouveau DynamicGetterSetter ;
echo "Nom : " $class->getName() .
echo "Saveur Starbucks préférée : " . $class->getStarbucksDrink() .
$class->setName("John Doe");
$class->setStarbucksDrink("Café Classique");
echo "Nom : " $class->getName() .
echo "Saveur Starbucks préférée : " . $class->getStarbucksDrink() .
?>
Évidemment, les deux attributs $name et $starbucksdrink ici sont privés, ce qui signifie que ces attributs ne sont pas accessibles depuis l'extérieur de la classe. En programmation orientée objet, il est très courant d'implémenter des méthodes getter/setter publiques pour accéder ou modifier les valeurs de propriétés non publiques. Leur mise en œuvre est fastidieuse et demande du temps et des efforts.
Ce problème peut être facilement résolu à l’aide de la surcharge de méthodes. Au lieu d'implémenter des méthodes getter/setter pour chaque propriété, ce qui précède implémente uniquement une méthode générale __call(). Cela signifie que lorsqu'une méthode getter/setter non définie telle que setName() ou getStarbucksdrink() est appelée, PHP ne générera pas d'erreur fatale et n'abandonnera pas, mais exécutera (ou déléguera) la méthode magique __call().
Voici quelques brèves introductions. Faisons une analyse approfondie de __call().
2. Analyse détaillée de la méthode __call().
Le premier paramètre de __call() est la méthode originale et indéterminée (comme setName). Le deuxième paramètre est un tableau unidimensionnel avec un index numérique, qui contient toutes les méthodes originales. .paramètre. L'appel d'une méthode non définie avec deux paramètres ("Martin" et 42) produira le tableau suivant :
$class->thisMethodDoesNotExist("Martin", 42);
/Guide du deuxième paramètre de __call()
Tableau
(
[0] =>Martin
[1] => 42
)
À l'intérieur de la méthode __call(), si la méthode d'origine commence par get ou set, certains calculs doivent être effectués pour déterminer si le code appelle une méthode getter/setter. De plus, cette méthode analysera plus en détail un autre composant du nom de la méthode (à l'exception des trois premiers caractères), car la dernière partie de la chaîne représente le nom de l'attribut référencé par le getter/setter.
Si le nom de la méthode indique un getter/setter, alors la méthode renvoie la valeur de propriété correspondante ou définit la valeur du premier paramètre de la méthode d'origine. Sinon, il ne fait rien et continue d’exécuter le programme comme si de rien n’était.
3. Pour atteindre l'objectif
En substance, correspondant à tout attribut, il existe une méthode qui permet au code d'appeler dynamiquement n'importe quelle méthode getter/setter. Cet algorithme existe. Ceci est pratique lors du développement d'un prototype de programme à court terme : au lieu de passer beaucoup de temps à implémenter des getters/setters, le développeur peut se concentrer sur la modélisation de l'API et s'assurer que l'application est fondamentalement correcte. L'intégration de la méthode __call() dans une classe abstraite peut même vous permettre de réutiliser du code dans le futur développement d'un projet PHP
4. En plus des inconvénients,
il y a des avantages et des inconvénients ! L'approche ci-dessus présente plusieurs inconvénients : les projets plus importants peuvent utiliser des outils comme phpDocumentor pour suivre la structure de l'API. Avec la méthode dynamique introduite ci-dessus, bien entendu, toutes les méthodes getter/setter n'apparaîtront pas dans le document généré automatiquement, ce qui ne nécessite aucune explication supplémentaire.
Un autre inconvénient est que le code en dehors de la classe peut accéder à toutes les propriétés privées de la classe. Lors de l'utilisation de méthodes getter/setter réelles, il est possible de faire la distinction entre les propriétés privées accessibles par du code externe et les propriétés privées "réelles" qui ne sont pas visibles en dehors de la classe - car nous avons une surcharge de méthodes et nous avons des getters et setters virtuels. Des méthodes peuvent être utilisées.
5. Conclusion
Cet article analyse minutieusement les deux situations de surcharge d'objets en PHP 5.0 à travers deux exemples. J'espère vraiment que la méthode décrite dans cet article pourra vous aider à améliorer l'efficacité de la programmation PHP. En même temps, vous devriez également voir clairement les lacunes de cette méthode !