2012-05-15 29 views
13

私は、ツリーを通るパスを格納するためにスタックとして使用している配列を持っています。各要素はツリー内のノードを指しています。最後の要素をポップしてから、その要素が参照するオブジェクトをnullに設定します。基本的にはPHPで参照を間接参照することはできますか?

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

はCっぽい言語がそうであるようにPHPが '*' 演算子を持っていたと仮定。私はパスを含む配列がで作成されるため、これは醜いと言う

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

:のように今私は私が撮った子の親ノードと思い出すから始まり、その後、nullにその設定の醜いソリューションを持っています私のツリークラスのパブリック関数。私は、PHPの特質(?)を扱う実装の詳細を公開することなく、ツリーのパス内のノードで直接作業する能力を公開したいと思います。 ATM戻り値(この場合は$ goLeft)にブール値を含める必要があるため、参照を参照解除することができない場合があります。

これは私がこの問題に遭遇したときの2回目です。だから、誰かが私がコードの最初のブロックに似た何かをする方法を知っていたら、共有してください!

(EDIT)

&年代と配列の多くの順列を使って実験した後に、それは基本的な問題は、私は私がなっていたエラーの理由を誤解していたことだったことが判明。

私は

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

を試してみましたが、 "構文エラー、予期しない '&'" を得ました。これは、問題が$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で解決されています。初めて読んだときに沈んだことを願います!

+1

これはあなたが望むものですが、 '$ parent-> left = null;の代わりに' unset($ parent-> left); 'を使うことができます。 – Leri

+4

@PLB: unset'ではなく、 'unlink'を実行します。 –

+1

@Rocketもちろん、します。私はとても疲れている。 – Leri

答えて

7

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

これは私が何を意味するか(ロケットのコードに基づいて)です:PHPの

$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

+0

うわー、きちんとした。それは実際に動作します! –

+0

@bfavaretto:あなたはそれを解決しました!素晴らしい、そしてとてもシンプル!私は、私が望むことをするためのきれいなやり方があることを賞賛されます。すべての助けをいただきありがとうございます、スタックオーバーフローのルール! – kahulio

+0

Heh - それは私が家に帰る前に誰かがそこに着くだろうと思っていたと思ったほど単純だった:Dトリックは配列の参照を使っている。 – CD001

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) 
} 
+0

彼が望むのは、 "元の"オブジェクトが設定されていないことです( '$ test [2]')。 'array_pop'の戻り値はなぜ重要ですか?いずれにせよ '$ test2'を修正しています。 –

+0

それは説明から得るのが難しいです。 :) – Narf

1

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

PHPはメモリの割り当て解除やガベージコレクションを強制するメソッドを持っていないようですので、あなたの参照を注意深く処理しない限り、スタックしません。

これは

P.S.ことはできません私はあなたがしようとしていることについて、まだ本当に混乱しています。ロケットの説明は役に立ちますが、$pathとは何ですか?それは2番目のブロックにどのように関連していますか?

+0

私の元の質問はあまりにも具体的だったと思います。私がスタックを使って作業しているか、何かをnullにしようとしていることは、実際には問題になりません。私は自分自身を説明することでより良くなる必要があります。 私は何かへの参照を保持する変数を持っているとしましょう - オブジェクト、別の変数、それは重要ではありません。例: '$ a = &$b; ' ここでは、' $ a'によって参照されるもの(この場合は '$ b')に対して操作を行いたいと思います。多分、 '$ b'をnull、文字列" alice "、または別のオブジェクトに設定したいと思うかもしれません。関係ない。とにかく、これは私が達成しようとしているものです。 – kahulio

+0

@kahulioこれは説明するのが少し難しいです。基本的に '$ a =&$ b'は' $ a'から '$ b'までのシンボルテーブルエイリアスを作成します。つまり、 '$ a'に行うことは' $ b'に直接影響します。 '$ b'がオブジェクトの場合、' $ a = $ b'はオブジェクト参照を '$ b'から' $ a'にコピーします。オブジェクト '$ a'に対する操作は、オブジェクト' $ b'と同じ効果がありますが、別のシンボルテーブルエントリです。 '$ a'(' $ a = 'blah'; ')に書き込むと、' $ b'に全く影響しません。 'array_pop'は参照(エイリアス)を返さない*ことができないので、戻り値に書き込んでも元のオブジェクトには何の影響もありません。 –

0
$one = 1; 
$two = 2; 
$array = array(&$one, &$two); 

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

var_dump($two); 
// NULL 

リファレンスを使用すると、オブジェクトを変更することができます。

関連する問題