2

いくつかの cron ジョブに単純なロック メカニズムを実装したかったので、通常とは異なる方法で実装することにしました。ソケットの作成/バインド/リッスンに関しては、PHP に少しバグがあるようです。

動作しているコード:

<?php
echo 'EXECUTING: '. __METHOD__ . \PHP_EOL;

if(false === ($socket = \socket_create(\AF_INET, \SOCK_STREAM, \SOL_TCP))) {
    die('create');
}

if(false === ($bind = \socket_bind($socket, '127.0.0.1', 4444))) {
    die('bind');
}

if(false === ($listen = \socket_listen($socket))) {
    die('listen');
}

var_dump($socket, $bind, $listen);

これによりソケットが作成され、着信接続を待機するインターフェースにバインドされます。次のように呼び出して確認できます。

netstat -anp | grep LIST | grep tcp

同じ PHP コードを単純なクラスに入れると、バインド/リッスンしません。これが私が話しているコードです:

<?php

class Test
{
    public function lock()
    {
        echo 'EXECUTING: '. __METHOD__ . \PHP_EOL;

        if(false === ($socket = \socket_create(\AF_INET, \SOCK_STREAM, \SOL_TCP))) {
            die('create');
        }

        if(false === ($bind = \socket_bind($socket, '127.0.0.1', 4444))) {
            die('bind');
        }

        if(false === ($listen = \socket_listen($socket))) {
            die('listen');
        }

        var_dump($socket, $bind, $listen);
    }
}

$t = new Test();
$t->lock();

echo 'Working...'. \PHP_EOL;
sleep(60);
echo 'Done.';

このコードを実行すると、var_dump が次のように表示されることがわかります。

  1. $socketリソースです(これが必要です)
  2. $bind = true
  3. $listen = true

しかし、コードは実際にはバインド/リッスンしていません。

私が間違っていることは何ですか?

編集:

テスト済み:

  • PHP 5.4.4 (Linux)
  • PHP 5.3.3 (Linux)
4

1 に答える 1

3

答えは簡単です。$socket変数はローカル変数であり、メソッド スコープではなく参照がありません。つまり、メソッドが実行されると、PHP はすべてのローカル変数を破棄し$socketます。私はe。ソケットを正常に作成し、PHP は同じ瞬間にそれをアンセットします (メソッドが実行を終了するため)。ローカル変数の設定を解除しても、すぐにメモリを解放するわけではないことに注意してください。ガベージ コレクション サイクルはコストがかかるため、PHP はメモリ制限に達した場合にのみ実行します。

違いを確認するには、sleep()ソケットの作成後にメソッド内に呼び出しを配置し​​ます。PHP にはバージョン 5.3 以降のガベージ コレクションがあるため、試したバージョンは影響を受けます。ライブで確認するには、次のスニペットを確認してください。

class Foo
{

    public function __destruct()
    {
        echo('destroyed'.PHP_EOL);
    }
}

class Bar
{
    public function test()
    {
        echo('starting method'.PHP_EOL);
        $obj = new Foo();
        echo('ending method'.PHP_EOL);
    }
}
echo('start script'.PHP_EOL);
$obj = new Bar;
$obj->test();
echo('end script'.PHP_EOL);

結果で

スクリプトを開始
起動方法
終了方法
破壊されました
終了スクリプト

$obj-ご覧のとおり、ローカル変数は他のどこにも参照されていないため、メソッド呼び出しを終了した直後にクラス デストラクタが呼び出されました。

于 2013-11-02T16:22:04.020 に答える