15

ツリーを通るパスを格納するためのスタックとして使用している配列があります。各要素はツリー内のノードを指しており、最後の要素をポップして、その要素が参照するオブジェクトを null に設定したいと考えています。

基本的:

$node = array_pop($path);
*$node = null;

C言語のようにPHPに「*」演算子があると仮定します。現在、親ノードから始めて、どの子を取得したかを覚えてから、次のようにそれを null に設定するという醜い解決策があります。

if($goLeft) {
    $parent->left = null;
} else {
    $parent->right = null;
}

パスを含む配列がツリー クラスのパブリック関数によって作成されるため、これは醜いと言います。PHP の特異性 (機能?) に対処する実装の詳細を公開することなく、ツリーを介してパス内のノードで直接作業する機能を公開したいと思います。ATM 戻り値 (この場合は $goLeft) にブール値を含める必要があるのは、参照を逆参照できないことを回避できるようにするためです。

この問題に遭遇したのはこれが 2 回目なので、最初のコード ブロックと同様の方法を誰かが知っている場合は、共有してください。

(編集)

& と配列の多くの順列を試した結果、基本的な問題は、エラーの理由を誤解していたことにあることがわかりました。

私は試した

$a = ($x > $y) ? &$foo[$bar] : $blah;

「構文エラー、予期しない '&'」が発生しました。これは、問題が &-operator on を使用していたことを意味すると解釈しました$foo[$bar]。実際には、犯人は ? 演算子であることが判明しました。

if($x > $y) {
    $a = &$foo[$bar];
} else {
    $a = null;
}

完全に正常に動作します。そこで私は、存在しなかった問題の回避策を探して、猛烈な追跡を続けました。& のチェーンを壊さない限り、PHP は、(変数自体ではなく) 変数によって参照されるオブジェクトを操作するという、私が望むことを実行します。例

$a1 = new SomeClass;
$a2 = &$a1;
$a3 = &$a2;
$a4 = &$a3;

$a4 = 42;    // This actually sets $a1 to 42
var_dump($a1); // Emits 42

私を混乱させたのは、とにかくオブジェクトが参照によって渡されると思っていた (これは間違っている) ため、式がオブジェクトに解決された場合に & が必要だとは思わなかったということです。つまり:

class A {
    public $b;
}

class B {}

$a = new A;
$a->b = new B; 

$c1 = $a->b; 
$c2 = &$a->b;

$c1 = 42; // Merely assigns 42 to $c1
$c2 = 42; // Assigns 42 to $a->b

この正確な問題はhttp://www.php.net/manual/en/language.oop5.references.phpで対処されていることが判明しました。初めて読んだときに沈んだ願い!

4

4 に答える 4

7

非常に興味深い質問です!回避策を見つけたかもしれません。配列にオブジェクト参照を入力し、&演算子を使用すると、その配列値をに設定することで元のオブジェクトを破棄できますNULL。によって返される変数を使用する代わりに、配列を直接操作する必要がありますarray_pop。その後、配列をポップしてその位置を解放できます(NULL値が含まれます)。

これは私が意味することです(ロケットのコードに基づく):

$a=(object)'a';
$b=array(&$a);
$b[0] = NULL;
// array still contains an element
array_pop($b);
// now array is empty
var_dump($a); // NULL

http://codepad.org/3D7Lphde

于 2012-05-15T16:47:43.667 に答える
1

どこでこれを読んだか思い出せたらいいのですが、PHP は特定のオブジェクトへの参照のカウンターを維持することで機能します。Treeいくつかのノードへの参照を持ついくつかのオブジェクト(たとえば a )があります。を使用するarray_popと、ノード オブジェクトへの参照が返されます (つまり、追加の参照が作成されます) が、元の参照は引き続き存在します。参照をunsetポップすると、それは破棄されますが、元のオブジェクトはTreeまだその参照を持っているため、破棄されません。そのオブジェクトのメモリを解放する唯一の方法は、Treeそれを個人的に破棄することです (これは、2 番目のコード ブロックで行っているようです)。

PHP には、メモリの割り当て解除やガベージ コレクションを強制する方法がないようです。

これは不可能です

PS私はあなたがやろうとしていることについてまだ本当に混乱しています. ロケットの説明は役に立ちますが$path、 とは何ですか? 2 番目のブロックとどのように関係していますか?

于 2012-05-15T16:31:53.670 に答える
0

array_pop()戻り値を割り当てないでください。

php > $test = array(1, 2, 3);
php > $test2 = array(0 => &$test[0], 1 => &$test[1], 2 => &$test[2]);
php > array_pop($test2);
php > var_dump($test);
array(3) {
  [0]=>
  &int(1)
  [1]=>
  &int(2)
  [2]=>
  int(3)
}
php > var_dump($test2);
array(2) {
  [0]=>
  &int(1)
  [1]=>
  &int(2)
}
于 2012-05-15T16:27:31.333 に答える
0
$one = 1;
$two = 2;
$array = array(&$one, &$two);

// magic
end($array);
$array[key($array)] = NULL;

var_dump($two);
// NULL

PHP で参照すると、オブジェクトを変更できます。

于 2012-05-15T17:03:15.823 に答える