Êtes-vous prêt pour les bonbons de citrouille et le cidre? L'Halloween annuel est là! Bien que le fanatisme du monde entier ne soit pas aussi bon que les États-Unis, je veux toujours partager des conseils PHP "horribles" pour célébrer ce festival. Ce message est facile et amusant et vous montrera certains des comportements surprenants (mais logiques) de PHP lui-même, ainsi que ces façons effrayantes (et peut-être très illogiques) que certaines personnes utilisent PHP pour effectuer des tâches. Vous pouvez le considérer comme mon cadeau de vacances, un peu de «bonbons spirituels» du programmeur - après tout, pourquoi les enfants de bonbons uniquement qui ne donnent pas toutes les spécialités?
Résumé des points clés
foreach
, entraînant des résultats de sortie inattendus. Ce problème peut être atténué en réaffectant la chaîne à l'aide des clés du tableau. tableau de bizarrerie
Il était une fois, dans un studio de développement pas si lointain, Arthur écrivait toujours du code tard dans la nuit. Il ne savait pas que le tableau qu'il était sur le point d'utiliser était hanté! Avec chaque robinet sur le clavier, il sentit un froid glisser de sa colonne vertébrale, mais il a bêtement ignoré cette subtile prémonition.
<?php $spell = array("double", "toil", "trouble", "cauldron", "bubble"); foreach ($spell as &$word) { $word = ucfirst($word); } foreach ($spell as $word) { echo $word . "n"; }
D'accord, ce tableau n'est pas vraiment hanté, mais la sortie est en effet inattendue:
<code>Double Toil Trouble Cauldron Cauldron</code>
La raison de ce comportement "terrifiant" est de savoir comment PHP conserve les références en dehors de la première boucle foreach
. Lorsque la deuxième boucle commence, $word
est toujours une référence, pointant vers le dernier élément du tableau. La première itération de la deuxième boucle attribue "double" à $word
, qui écrase le dernier élément. La deuxième itération attribue "le travail" à $word
, en remplissant à nouveau le dernier élément. Lorsque la boucle lit la valeur du dernier élément, elle a été remplacée plusieurs fois. Pour avoir un aperçu de ce comportement, je recommande de lire le billet de blog de Johannes Schlüter sur le sujet, "Références et Foreach". Vous pouvez également exécuter cette version légèrement modifiée et vérifier sa sortie pour mieux comprendre ce que fait PHP:
<?php $spell = array("double", "toil", "trouble", "cauldron", "bubble"); foreach ($spell as &$word) { $word = ucfirst($word); } foreach ($spell as $word) { echo $word . "n"; }
Arthur a appris une leçon très importante cette nuit-là et a corrigé son code avec les clés du tableau pour réaffecter la chaîne:
<code>Double Toil Trouble Cauldron Cauldron</code>
Connexion de la base de données fantômes
PHP est de plus en plus demandé non seulement de générer des pages Web chaque jour. Le nombre de scripts shell écrits en PHP augmente, et les tâches effectuées par ces scripts deviennent de plus en plus complexes, car les développeurs voient les avantages de l'intégration des langages de développement. En règle générale, les performances de ces scripts sont acceptables et les compromis effectués pour la commodité sont prouvés. Susan écrit donc une tâche de traitement parallèle dont le code est similaire à ce qui suit:
<?php $spell = array("double", "toil", "trouble", "cauldron", "bubble"); foreach ($spell as &$word) { $word = ucfirst($word); } var_dump($spell); foreach ($spell as $word) { echo join(" ", $spell) . "n"; }
son code alimente les processus de l'enfant pour effectuer des travaux de longue durée en parallèle, tandis que le processus parent continue de surveiller les processus de l'enfant et rapporte les résultats lorsque tous les enfants se terminent.
<?php foreach ($spell as $key => $word) { $spell[$key] = ucfirst($word); }
Cependant, les dirigeants de Susan lui ont demandé de journaliser les informations sur l'état dans le journal au lieu de les sortir en sortie standard. Susan a prolongé son code à l'aide d'un mécanisme de connexion de la base de données PDO motif Singleton qui était déjà inclus dans la base de code de l'entreprise.
#! /usr/bin/env php <?php $pids = array(); foreach (range(0, 4) as $i) { $pid = pcntl_fork(); if ($pid > 0) { echo "Fork child $pid.n"; // record PIDs in reverse lookup array $pids[$pid] = true; } else if ($pid == 0) { echo "Child " . posix_getpid() . " working...n"; sleep(5); exit; } } // wait for children to finish while (count($pids)) { $pid = pcntl_wait($status); echo "Child $pid finished.n"; unset($pids[$pid]); } echo "Tasks complete.n";
Susan s'attend à voir des lignes dans le tableau timings
mise à jour; processus. Malheureusement, l'exécution lance une exception et la base de données ne reflète pas ses attentes.
<code>Fork child 1634. Fork child 1635. Fork child 1636. Child 1634 working... Fork child 1637. Child 1635 working... Child 1636 working... Fork child 1638. Child 1637 working... Child 1638 working... Child 1637 finished. Child 1636 finished. Child 1638 finished. Child 1635 finished. Child 1634 finished. Tasks complete.</code>
#! /usr/bin/env php <?php $db = Db::connection(); $db->query("UPDATE timings SET tstamp=NOW() WHERE name='start time'"); $pids = array(); foreach (range(0, 4) as $i) { ... } while (count($pids)) { ... } $db->query("UPDATE timings SET tstamp=NOW() WHERE name='stop time'"); class Db { protected static $db; public static function connection() { if (!isset(self::$db)) { self::$db = new PDO("mysql:host=localhost;dbname=test", "dbuser", "dbpass"); self::$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } return self::$db; } }
Comme le tableau d'Arthur, la base de données de Susan est-elle hantée? Eh bien, si je vous donne les indices suivants, voyez si vous pouvez reconstituer ce mystère: 1. Lorsqu'un processus est fourche, le processus parent est copié en tant que processus enfant. Ces processus répliqués s'exécutent ensuite en parallèle à partir de ce moment. 2. Les membres statiques sont partagés entre tous les cas de la classe.
La connexion PDO est enveloppée en singleton, donc toute référence dans l'application pointe la même ressource en mémoire. DB::connection()
Renvoie d'abord la référence de l'objet, la fourche du processus parent, le processus de l'enfant continue de traiter, tandis que le processus parent attend, le processus de l'enfant se termine et PHP nettoie les ressources utilisées, puis le processus parent essaie d'utiliser l'objet de base de données encore. La connexion à MySQL a été fermée dans le processus de l'enfant, donc l'appel final échoue. Essayer naïvement d'obtenir la connexion avant la dernière requête de journalisation n'aidera pas Susan car la même instance PDO échouée sera retournée car c'est un singleton. Je recommande d'éviter les singletons - ce ne sont vraiment que des variables mondiales axées sur les objets, ce qui rend le débogage difficile. Même dans notre cas, la connexion sera toujours fermée par le processus de l'enfant, mais si DB::connection()
est appelé avant la deuxième requête, il renverra au moins une nouvelle connexion sans singleton. Mais une meilleure façon consiste à comprendre comment l'environnement d'exécution est cloné lors de la fourche et comment les différentes ressources sont affectées dans tous les processus. Dans ce cas, il est préférable de se connecter à la base de données dans le processus parent après le processus de l'enfant de la fourche, et le processus de l'enfant se connectera par lui-même si nécessaire. Les connexions ne doivent pas être partagées.
<code>PHP Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error: 2006 MySQL server has gone away' in /home/susanbrown/test.php:21 Stack trace: #0 /home/susanbrown/test.php(21): PDO->query('UPDATE timers S...') #1 {main}</code>
dr. "Frankenstein" de Mary Shelley raconte l'histoire d'un scientifique créant la vie, mais il se sent dégoûté de sa laideur et l'abandonne. Après une mort et une destruction inutiles, le Dr Frankenstein poursuit sa création jusqu'à la fin du monde, essayant de le détruire. Beaucoup d'entre nous ont donné une vie en code aussi laide que nous souhaitons plus tard que nous pourrions y échapper - le code est si laid, si terne, si chaotique qu'il nous donne envie de vomir, mais il veut juste l'amour et la compréhension. Il y a quelques années, j'ai joué avec une idée des interfaces de base de données et à quoi ils ressembleraient s'ils suivaient plus strictement la philosophie d'Unix de "tout est un fichier": les requêtes seront écrites dans "Fichier", les ensembles de résultats seront être lu à partir du "fichier". Une chose mène à une autre, après une partie de ma propre mort et de mon codage destructeur, j'ai écrit la classe suivante qui a peu à voir avec mes pensées initiales: Le résultat est un génie, mais dégoûtant: une instance qui ressemble à un objet (pas de méthode API réelle), un tableau ou une chaîne ... J'ai écrit un blog peu de temps après et je l'ai marqué comme mal. Des amis et des collègues qui l'ont vu presque tous ont répondu de la même manière: "Génial! Tuez-le maintenant ... Brûlez-le avec le feu." Mais au fil des ans, j'avoue que je l'ai adouci. La seule règle qu'il viole vraiment est les attentes du programmeur pour les méthodes de dénomination fade comme Conclusion J'espère que vous avez apprécié ce post et que ces exemples ne vous font pas (trop) cauchemars! Je crois que vous avez également vos propres histoires sur du code hanté ou terrible, peu importe où vous êtes, vous n'avez pas besoin de laisser le plaisir des vacances disparaître, alors n'hésitez pas à partager votre terrible histoire de PHP dans les commentaires ci-dessous! images de Fotolia (Ce qui suit est la FAQ, qui a été ajustée et rationalisée en fonction du contenu d'origine) Les questions fréquemment posées sur "Spooky Scary PHP" Qu'est-ce que "PHP effrayant effrayant"? "PHP effrayant effrayant" est une méthode de codage PHP unique qui implique l'utilisation de méthodes non conventionnelles ou inattendues pour obtenir certains résultats. Cela peut inclure l'utilisation de fonctions moins connues, en profitant des fonctionnalités de la langue et même en utilisant du code qui ne semble pas fonctionner mais fonctionne. C'est une façon amusante et excitante d'explorer la profondeur de PHP et conduit souvent à des découvertes surprenantes et inspirantes. Comment commencer à apprendre "php effrayant effrayant"? La meilleure façon d'apprendre le "php effrayant effrayant" est d'avoir une solide compréhension des bases de PHP. Une fois que vous êtes satisfait des bases, vous pouvez commencer à explorer les coins les plus obscurs de la langue. La lecture d'articles, de tutoriels et de discussions sur le forum sur le "php effrayant effrayant" peut également être très utile. N'oubliez pas que l'objectif n'est pas d'écrire un code efficace ou pratique, mais d'explorer et de comprendre la langue de manière plus profonde. "Spooky effrayant PHP" est-il une bonne pratique? "SPOOKY SCARY PHP" n'est généralement pas considéré comme une bonne pratique pour rédiger du code de production. Il implique généralement l'utilisation de fonctions ou de techniques inefficaces, peu claires ou imprévisibles. Cependant, c'est peut-être un excellent moyen d'en savoir plus sur la langue et de défier votre compréhension de PHP. Cela ressemble plus à un outil d'apprentissage et à une expérience amusante qu'à un style de codage pratique. est-il "effrayant effrayant" nocif? Bien que "Spooky effrayant PHP" soit amusant et éducatif, assurez-vous de l'utiliser de manière responsable. Certaines technologies utilisées dans "Spooky Scary PHP" peuvent causer des dommages s'ils sont utilisés dans des environnements en temps réel, tels que ceux qui exploitent les fonctionnalités ou les erreurs dans la langue. Assurez-vous de tester soigneusement tout code que vous écrivez et n'utilisez jamais la technologie "Spooky Scary PHP" dans des parties importantes de votre projet. Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!<?php
$spell = array("double", "toil", "trouble", "cauldron", "bubble");
foreach ($spell as &$word) {
$word = ucfirst($word);
}
foreach ($spell as $word) {
echo $word . "n";
}
<code>Double
Toil
Trouble
Cauldron
Cauldron</code>
query()
et result()
. Au lieu de cela, il utilise la chaîne de requête elle-même comme méthode de requête, l'objet est l'interface et le jeu de résultats est le résultat. Bien sûr, ce n'est pas pire qu'une interface ORM trop généralisée, qui relie les méthodes select()
et where()
ensemble, qui ressemblent à des requêtes SQL, mais qui a plus ->
. Peut-être que ma classe n'est pas si mal? Peut-être que ça veut juste être aimé? Bien sûr, je ne veux pas mourir dans l'Arctique!