おぎろぐはてブロ

なんだかんだエンジニアになって10年以上

最近やってること

PHP Extensionの関数の中で、あたかも関数スコープをもたせること。
Cで、このように書くと

PHP_FUNCTION(hogehoge)
{
    zend_eval_string("echo 'hello world';", NULL, "hoge" TSRMLS_CC);
}

これとほぼ等価。

<?php
function hogehoge()
{
    eval "echo 'hello world';";
    // ↑ 結局 echo 'hello world';
}
?>

なのだけれど、Cの方は、関数スコープに入るわけではない。呼び出し前のスコープと同じレベルで動作する。
要は、

<?php
function hogehoge()
{
    $b = 2;
    var_dump(get_defined_vars());
}

$a = 1;
hogehoge();
?>

というコードを上のようなコードで用意したときに、PHPスクリプトでは、

$ php tmp.php
array(1) {
  ["b"]=>
  int(2)
}

なのだけれど、Cのextensionでの関数は、$aも$bも含まれるし、関数を抜けたあとも、$bが残る。

なんでそういう仕様なのかというと、ふつうに「そういうことをしないから」。evalしてたらCで書く意味ないし、PHPスクリプトレベルの変数を直接読み書きすることもないので、汚染の問題もないから。(こんな感じで引数を受け取る)

と、長くなったけど、スコープを作るには、EG(active_symbol_table)を待避させればよい。

  • EG(active_symbol_table)のポインタを待避
  • HashTableを作成、初期化して、EG(active_symbol_table)にアロケート
  • コード実行 (スコープの中)
  • 作ったシンボルテーブルを破棄
  • EG(active_symbol_table)のポインタを戻す

で、それはできた。(ようにみえるけど、スーパーグローバルとか大丈夫か不安。。)

さらに、EG(function_table)に関数テーブルがあるんだけれど、これ待避させたら、そのスコープだけに存在する関数を定義できる?
と思って、試してたのだけれど、まだうまく動かない。。。

#実行環境でないので、コード間違えてるかも