呼び出し元のスコープに変数を直接設定することは、おそらく良い考えではないことを私は知っています。ただし、PHPextract()
関数はまさにそれを実行します。の独自のバージョンを作成したいextract()
のですが、呼び出し元で変数を実際に設定する方法がわかりません。何か案は?私が来た最も近いのは、呼び出し元のargs
を使用して変更するdebug_backtrace()
ことですが、これはまったく同じことではありません...
4 に答える
親スコープ内のローカル変数を変更することはできません-extract()が使用するメソッドはPHPによって公開されていません。
また、debug_stacktrace()から返されるものは、実際のスタックに魔法のようにリンクされていません。あなたはそれを変更することはできません、そしてあなたの変更が生きていることを願っています!
あなたはPHP拡張でのみそれを行うことができました。内部PHP関数を呼び出すと、新しいPHPスコープでは実行されません(つまり、新しいシンボルテーブルは作成されません)。したがって、グローバルを変更することで「親スコープ」を変更できますEG(active_symbol_table)
。
基本的に、関数のコアは次のようなことを行いますextract
。そのコアは次のとおりです。
if (!EG(active_symbol_table)) {
zend_rebuild_symbol_table(TSRMLS_C);
}
//loop through the given array
ZEND_SET_SYMBOL_WITH_LENGTH(EG(active_symbol_table),
Z_STRVAL(final_name), Z_STRLEN(final_name) + 1, data, 1, 0);
ただし、微妙な違いがいくつかあります。の実装をextract
参照してください。ただし、必要なことを実行する関数は、それほど複雑である必要はないことに注意してください。のコードのほとんどは、extract
受け入れるいくつかのオプションを処理するためにあります。
$ GLOBALSスコープを悪用して、関数の呼び出し元から変数を読み書きできます。以下のサンプル関数を参照してください。この関数は、呼び出し元のスコープから変数を読み書きします。
はい、$ GLOBALスコープを悪用するのは汚いことは知っていますが、問題を解決するためにここにいますね。:)
function set_first_name($firstname) {
/* check if $firstname is defined in caller */
if(array_key_exists('firstname', $GLOBALS)) {
$firstname_was = $GLOBALS['firstname'];
} else {
$firstname_was = 'undefined';
}
/* set $firstname in caller */
$GLOBALS['firstname'] = $firstname;
/* show onscreen confirmation for debugging */
echo '<br>firstname was ' . $firstname_was . ' and now is: ' . $firstname;
}
set_first_name('John');
set_first_name('Michael');
この関数は次の出力を返します。
<br>firstname was undefined and now is: John
<br>firstname was John and now is: Michael
これを行う必要があるかどうかによって異なります。ソースビューティーのみの場合は、別の方法を見つけてください。何らかの理由で、本当に親スコープをいじる必要がある場合は、常に方法があります。
解決策1
最も安全な方法は、トリックを知っているので、このジョブに実際にextract自体を使用することです。配列の要素を抽出するが、すべての名前が逆になっている関数を作成したいとします-かなり奇妙です!-、単純な配列から配列への変換でこれを行いましょう:
function backwardNames($x) {
$out = [];
foreach($x as $key=>$val) {
$rev = strrev($key);
$out[$rev] = $val;
}
return $out;
}
extract(backwardNames($myArray));
ここには魔法はありません。
解決策2
抽出が行う以上のものが必要な場合は、 evalとvar_exportを使用してください。はい私は知っています私は知っていますみんな落ち着いてください。いいえ、評価は悪ではありません。Evalは動力工具であり、注意せずに使用すると危険な場合があるため、注意して使用してください。(var_exportによって生成されたものだけを評価する場合、間違いを犯すことはありません。信頼できないソースから配列に値を入れても、侵入に道を譲ることはありません。配列要素は適切に動作します。)
function makeMyVariables() {
$vars = [
"a" => 4,
"b" => 5,
];
$out = var_export($vars,1);
$out = "extract(".$out.");";
return $out;
}
eval(makeMyVariables()); // this is how you call it
// now $a is 4, $b is 5
これはほとんど同じですが、evalでさらに多くのことができる点が異なります。もちろん、かなり遅くなります。
ただし、実際には、1回の呼び出しでそれを行う方法はありません。