不気味な怖いPHP

William Shakespeare
William Shakespeareオリジナル
2025-02-25 09:25:08599ブラウズ

Spooky Scary PHP

カボチャのキャンディーとサイダーの準備はできていますか?毎年恒例のハロウィーンが再びここにあります!世界中の狂信主義は米国ほど良くありませんが、私はまだこのフェスティバルを祝うために「恐ろしい」PHPのヒントを共有したいと思っています。この投稿は簡単で楽しく、PHP自体の驚くべき(しかし論理的な)行動のいくつかと、一部の人々がPHPを使用してタスクを完了するために不気味な(そしておそらく非常に非論理的な)行動を示します。あなたはそれを私のホリデーギフト、プログラマーの「スピリチュアルキャンディー」の少しと考えることができます。

キーポイントの概要

概要

  • PHPは、最初のforeachループの外側に参照を保持するなど、予期しない動作を示す可能性があり、予期しない出力結果が得られます。この問題は、配列のキーを使用して文字列を再割り当てすることで軽減できます。
  • PHPを使用してより複雑なタスク(シェルスクリプトなど)を実行する場合、フォーク時に実行環境がどのようにクローン化されるか、およびすべてのプロセスでさまざまなリソースがどのように影響を受けるかを理解することが重要です。たとえば、データベースに接続する場合、フォークチャイルドプロセスの後に親プロセスに接続することが最善であり、必要に応じて子プロセスを単独で接続します。
  • シングルトンパターン(実際には、派手なオブジェクト指向のグローバル変数にすぎません)は、デバッグを困難にする可能性があります。可能な限りシングルトンモードを避けることをお勧めします。
  • 「不気味な怖いPHP」のような型破りなコーディングプラクティスは興味深く、教育コードを書くための良い慣行とは考えられていません。

hazed array

昔々、それほど遠くない開発スタジオで、アーサーは夜遅くにコードを書いていました。彼は、彼が使用しようとしていたアレイが幽霊だったことを知りませんでした!キーボードをタップするたびに、彼は背骨から寒さが滑るのを感じましたが、彼はこの微妙な予感を愚かに無視しました。

<code class="language-php"><?php
$spell = array("double", "toil", "trouble", "cauldron", "bubble");
foreach ($spell as &$word) {
    $word = ucfirst($word);
}
foreach ($spell as $word) {
    echo $word . "n";
}</code>

わかりました、この配列は実際には幽霊ではありませんが、出力は確かに予想外です:

<code>Double
Toil
Trouble
Cauldron
Cauldron</code>
この「恐ろしい」動作の理由は、PHPが最初の

ループの外側に参照を保持する方法です。 2番目のループが開始されると、foreachはまだ参照であり、配列の最後の要素を指します。 2番目のループの最初のイテレーションは、「double」を$wordに割り当て、最後の要素を上書きします。 2番目の反復では、「苦労」を$wordに割り当て、最後の要素を再び上書きします。ループが最後の要素の値を読み取ると、数回上書きされます。この動作についての洞察を得るために、トピックに関するヨハネス・シュルターのブログ投稿「参照とforeach」を読むことをお勧めします。このわずかに変更されたバージョンを実行して、その出力をチェックして、PHPが何をしているのかをよりよく理解することもできます。

<code class="language-php"><?php
$spell = array("double", "toil", "trouble", "cauldron", "bubble");
foreach ($spell as &$word) {
    $word = ucfirst($word);
}
foreach ($spell as $word) {
    echo $word . "n";
}</code>

アーサーはその夜に非常に重要な教訓を学び、文字列を再割り当てするために配列のキーでコードを修正しました:

<code>Double
Toil
Trouble
Cauldron
Cauldron</code>

ゴーストデータベース接続

PHPは、毎日Webページを生成するだけでなく、ますます求められています。 PHPで記述されたシェルスクリプトの数は増加しており、開発者が開発言語を統合することの利点を見ているため、これらのスクリプトによって実行されるタスクはますます複雑になっています。通常、これらのスクリプトのパフォーマンスは受け入れられ、利便性のために行われたトレードオフが証明されています。スーザンは、コードが次のような並列処理タスクを書いています。

彼女のコードは、子のプロセスを並行していくつかの長期にわたる作業を実行するために子どものプロセスを分岐しますが、親プロセスは子どものプロセスを監視し続け、すべての子供が終了したときに結果を報告します。
<code class="language-php"><?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";
}</code>

しかし、スーザンのリーダーシップは、標準の出力に出力するのではなく、ログにステータス情報をログに記録するように依頼しました。スーザンは、既に会社のコードベースに含まれていたSingleton Pattern PDOデータベース接続メカニズムを使用してコードを拡張しました。
<code class="language-php"><?php
foreach ($spell as $key => $word) {
    $spell[$key] = ucfirst($word);
}</code>

スーザンは、
<code class="language-php">#! /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";</code>
テーブルの行が更新されていることを期待しています。プロセス。残念ながら、実行は例外をスローし、データベースは彼女の期待を反映していません。

timings

<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>
アーサーの配列のように、スーザンのデータベースは幽霊ですか?さて、次の手がかりを与えたら、この謎をつなぎ合わせることができるかどうかを確認してください。1。プロセスが分岐した場合、親プロセスは子プロセスとしてコピーされます。これらの複製されたプロセスは、それから並行して実行されます。 2。静的メンバーは、クラスのすべてのインスタンスの中で共有されます。
<code class="language-php">#! /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;
    }
}</code>

PDO接続はシングルトンとして包まれているため、アプリケーション内のそれを参照することはメモリ内の同じリソースを指します。

最初にオブジェクトリファレンスを返し、親プロセスフォーク、子プロセスが処理され続け、親プロセスが待機し、子プロセスが終了し、PHPが使用されるリソースをクリーンアップし、その後、親プロセスはデータベースオブジェクトを使用しようとしますまた。 MySQLへの接続は子プロセスで閉鎖されているため、最終的な呼び出しは失敗します。最終的なロギングクエリの前に再び接続を再度取得しようとすることは、スーザンに役立ちません。これは、同じ失敗したPDOインスタンスがシングルトンであるため返されるためです。シングルトンを避けることをお勧めします - それらは本当に派手なオブジェクト指向のグローバル変数であり、それがデバッグを困難にします。私たちの場合でも、接続は子供のプロセスによって閉じられますが、2番目のクエリの前に

が呼び出された場合、少なくともシングルトンなしで新しい接続を返します。しかし、より良い方法は、フォーク時に実行環境がどのようにクローン化され、すべてのプロセスでさまざまなリソースがどのように影響を受けるかを理解することです。この場合、フォークチャイルドプロセスの後に親プロセスのデータベースに接続することが最善であり、必要に応じてチャイルドプロセスはそれ自体で接続します。接続を共有しないでください。 DB::connection() DB::connection()

<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

メアリー・シェリーの「フランケンシュタイン」は、科学者が人生を創造する物語を語っていますが、彼はそのugさにうんざりし、それを放棄します。不必要な死と破壊の後、フランケンシュタイン博士は世界の終わりまで彼の創造を追求し、それを破壊しようとします。私たちの多くは、そのような醜いコードライフを与えてきたので、後で逃げることを望みました。コードはとてもugい、とても退屈で、混oticとしているので、嘔吐したくなりますが、愛と理解を望んでいます。数年前、私はデータベースインターフェイスと、「Everything Is a File」というUnixの哲学に従っている場合、データベースインターフェイスとそれらがどのように見えるかについてのアイデアを回っています。クエリは「ファイル」に書き込まれます。 「ファイル」から読んでください。私自身の死と破壊的なコーディングのいくつかの後、私は私の最初の考えとはほとんど関係がない次のクラスを書きました:

<code class="language-php"><?php
$spell = array("double", "toil", "trouble", "cauldron", "bubble");
foreach ($spell as &$word) {
    $word = ucfirst($word);
}
foreach ($spell as $word) {
    echo $word . "n";
}</code>

結果は天才ですが、嫌なことです。オブジェクト(実際のAPIメソッドなし)、配列、または文字列のように見えるインスタンス...

<code>Double
Toil
Trouble
Cauldron
Cauldron</code>

私はその後まもなくブログを書き、それを悪としてマークしました。ほぼすべてを見た友人や同僚は、「素晴らしい!今それを殺す...火をつけて燃やしました。それが実際に違反する唯一のルールは、query()result()などの当たり障りのない命名方法に対するプログラマーの期待です。代わりに、クエリ文字列自体をクエリメソッドとして使用し、オブジェクトはインターフェイスであり、結果セットが結果です。もちろん、SQLクエリのように見えるが、select()を持っているように見えるwhere()->のメソッドをリンクする過剰な一般化されたORMインターフェイスよりも悪くはありません。たぶん私のクラスはそんなに悪ではありませんか?多分それはただ愛されたいのですか?もちろん、私は北極圏で死にたくありません!

結論

この投稿を楽しんだことを願っています。これらの例は(あまりにも多く)悪夢をもたらさないことを願っています!また、あなたが幽霊やひどいコードについてのあなた自身の物語を持っていると思います。あなたがどこにいても、あなたは休日の楽しみをなくす必要はありませんので、以下のコメントであなたのひどいPHPのストーリーを自由に共有してください! Fotoliaの写真

(以下はFAQであり、元のコンテンツに従って調整および合理化されています)「不気味な怖いPHP」 についてのよくある質問

「不気味な怖いPHP」とは何ですか?

「Spooky Scary PHP」は、特定の結果を達成するために型破りまたは予期しない方法を使用することを伴う一意のPHPエンコーディング方法です。これには、あまり知られていない関数の使用、言語の機能を活用すること、さらには機能していないが機能するコードを使用することも含まれます。それはPHPの深さを探求する楽しくてエキサイティングな方法であり、多くの場合、驚くほど刺激的な発見につながります。

「不気味な怖いPHP」を学び始める方法は?

「不気味な怖いPHP」を学ぶ最良の方法は、PHPの基本をしっかりと理解することです。基本に満足したら、言語のより曖昧な角を探索し始めることができます。 「不気味な怖いPHP」に関する記事、チュートリアル、フォーラムの議論も非常に役立ちます。目標は、効率的または実用的なコードを書くことではなく、より深い方法で言語を探求して理解することです。

「不気味な怖いPHP」は良い練習ですか?

「不気味な怖いPHP」は、通常、生産コードを書くための良い慣行とは見なされません。通常、非効率的、不明確な、または予測不可能な機能または技術の使用が含まれます。ただし、言語についてさらに学び、PHPの理解に挑戦するのに最適な方法かもしれません。実用的なコーディングスタイルというよりは、学習ツールと楽しい実験のようなものです。

「不気味な怖いPHP」は有害ですか?

「不気味な怖いPHP」は楽しく教育的ですが、責任を持って使用してください。 「不気味な怖いPHP」で使用されるいくつかのテクノロジーは、言語の機能やエラーを活用するリアルタイム環境で使用する場合、害を引き起こす可能性があります。記述したコードを徹底的にテストし、プロジェクトの重要な部分で「不気味な怖いPHP」テクノロジーを使用しないでください。

以上が不気味な怖いPHPの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。