7

次のようなPHPコードがあります。

class A {
    public function __construct() {
        $this->b = new B(function($x) { return $x + 1; });
    }
};

class B {
    public function __construct($dataProcessingFunction) {
        $this->dataProcessingFunction = $dataProcessingFunction;
    }

    public function processData($data) {
        $f = $this->dataProcessingFunction;
        return $f($data);
    }
};

しかし、問題があります。A のデストラクタの前に B のデストラクタを呼び出す必要があります。ご覧のとおり、これは合理的なようです。B オブジェクトは A を必要としないので、問題はないはずです。

しかし、PHP 5.4.0 以降、クロージャは暗黙的に $this を自動的にキャプチャするようになりました。したがって、B に渡し、B によって格納されるラムダ関数には、A への参照が含まれています。

つまり、A には B へのポインターが含まれ、B には (クロージャーを介して) A へのポインターが含まれます。この種の状況では、デストラクタはガベージ コレクションでランダムな順序でのみ呼び出されると PHP のドキュメントに記載されています。B のデストラクタは常に A の前に呼び出されます。

これをエレガントな方法で解決する方法はありますか?

4

1 に答える 1

4

Explosion Pills のおかげで、Closureクラスで解決策を見つけました。

$this実際、次のように、クロージャー内に保存されているものを変更できます。

$cb = function($x) { return $x + 1; };
$cb = $cb->bindTo(null);

// now $cb doesn't contain a pointer to $this anymore

これを行うことはできません。そうしないと、構文エラーが発生することに注意してください。

// syntax error
$cb = (function($x) { return $x + 1; })->bindTo(null);
于 2012-12-12T21:07:05.307 に答える