3

後で使用するために変数参照を保持しようとしています。

これが可能かどうかは定かではありませんが、配列要素を初期化し、変数で参照できることを望んでいます。次に、その配列要素の値を何かに設定して、参照された変数から値にアクセスできるようにします。

たとえば、これは機能します:

class Test{

    private $_vars = array();

    public function bind($key, &$var){
        $this->_vars[$key] = &$var;
        return $this;
    }

    public function fetch($key, &$var){
        $var = $this->_vars[$key];
        return $this;
    }

}

$test = new Test();
$string_set = 'This is a string';

$test->bind('string', $string_set)
    ->fetch('string', $string_get);

var_dump($string_get);
// expected:  string(16) "This is a string"
// actual:    string(16) "This is a string"

ここに問題があります。メソッド呼び出しの順序。関数は格納された匿名関数の戻り値を渡す必要があるため、関数が へcall()の参照を返すことはできません(そうでない場合は、呼び出しをの代わりに並べ替えます)$thiscall()->call()->fetch()->fetch()->call()

とにかく、fetch()メソッドはキーで適切な要素を設定$_varsNULL既存の値を空にするか、初期化します)、その要素を渡された に参照する必要があり$varます。

匿名関数が呼び出されると(バインディングが完了した後fetch())、 が呼び出されbind()、要素が$_vars何にでもバインドされます(この場合はa$string_setを含むThis is a string) 私のロジックが正しい場合、fetch()バインドされた変数($string_getこの場合は )は配列を参照する必要があります$_varsを参照している要素には、$string_setが含まれていますThis is a string

そのようには見えませんが。失敗しているコードは次のとおりです (簡潔にするために省略されていますが、重要な部分はすべてそこにあります) 。

class Test{

    private $_vars = array();
    private $_function;

    public static function factory(){
        return $test = new self(function() use(&$test){
            $string_set = 'This is a string';
            $test->bind('string', $string_set);
            return true;
        });
    }

    private function __construct($function){
        $this->_function = $function;
    }

    public function bind($key, &$var){
        $this->_vars[$key] = &$var;
        return $this;
    }

    public function fetch($key, &$var){
        $this->_vars[$key] = null;
        $var = &$this->_vars[$key]; // edited; was not assigning by reference
        return $this;
    }

    public function call(){
        return (bool) call_user_func($this->_function);
    }

}

$return = Test::factory()
    ->fetch('string', $string_get)
    ->call();

var_dump($return, $string_get);
// expected:  bool(TRUE), string(16) "This is a string"
// actual:    bool(TRUE), NULL

私はここでヒナギクを追いかけていますが、これは可能ですか? いずれにせよ、この問題を一目見ただけでも感謝します。どんな洞察も本当に感謝しています。

編集: fetch()-の行は$var = $this->_vars[$key];、参照によって配列要素を割り当てていませんでした。に編集しました$var = &$this->_vars[$key];が、一見効果はありません。

ボーナス: この問題が解決可能であれば、それは明らかに素晴らしいことです。私は実際には、参照ではなく値bind()を取ることができることを望んでいます。$varメソッドのシグネチャは のように変更されますset($key, $value)。とにかく、事前にもう一度感謝します。


一見好奇心旺盛な(あなたの方向 @Tomalak を見て)詳しく説明するために、より完全なクラスと使用シナリオを提供します。

class Action{

    private static $_cache = array();
    private static $_basePath;

    private $_vars = array();
    private $_function;

    public static function setBasePath($basePath){
        $basePath = rtrim($basePath, '/') . '/';
        if(!is_dir($basePath)){
            // throw exception, $basePath not found
        }
        self::$_basePath = $basePath;
    }

    public static function load($actionPath){
        $actionPath = self::$_basePath . $actionPath;
        if(array_key_exists($actionPath, self::$_cache)){
            return self::$_cache[$actionPath];
        }
        if(!is_file($actionPath)){
            // throw exception, $actionPath not found
        }
        $action = call_user_func(function() use(&$action, $actionPath){
            return require($actionPath);
        });
        if(!($action instanceof self)){
            // throw exception, $action of invalid type
        }
        self::$_cache[$actionPath] = $action;
        return $action;
    }

    public function __construct($function){
        if(!is_callable($function)){
            // throw exception, $function not callable
        }
        $this->_function = $function;
    }

    public function bindReturn($key, &$var){
        $this->_vars[$key] = &$var;
        return $this;
    }

    public function fetchInto($key, &$var){
        $this->_vars[$key] = null;
        $var = &$this->_vars[$key];
        return $this;
    }

    public function run(){
        return (bool) call_user_func_array($this->_function, func_get_args());
    }

}

############################################################################

// actions/test.php

return new Action(function($name)
    use(&$action){

        if($name == 'Alice'){
            return false;
        }

        $data = "Hi, my name is {$name}.";
        $action->bindReturn('data', $data);

        return true;

    });

############################################################################

// index.php (or whatever)

$result = Action::load('actions/test.php') // loaded
    ->fetchInto('data', $data)
    ->run('Alice');

// Failed
echo $result
    ? 'Success - ' . $data
    : 'Failed';

$result = Action::load('actions/test.php') // called from cache
    ->fetchInto('data', $data)
    ->run('Bob');

// Success - Hi, my name is Bob
echo $result
    ? 'Success - ' . $data
    : 'Failed';
4

2 に答える 2

2

問題があるようです

public function fetch($key, &$var){
    $this->_vars[$key] = null;
    $var = $this->_vars[$key];
    return $this;
}

キーを削除する場合は、null に設定せずに設定を解除します。

編集:初期化されていない変数の例外を避けるためにコードを変更しました。

public function fetch($key, &$var){
    if(isset($this->_vars[$key]))
    {
        $var = $this->_vars[$key];
        unset($this->_vars[$key]);
    }
    else
    {
        $var = null;
    }
    return $this;
}
于 2011-08-12T17:42:49.550 に答える
2

参照を「リダイレクト」できないため、やりたいことは(少なくとも参照では)不可能です。何が起こるかは次のとおりです。

$instance->fetch('foo', $myVar);

public function fetch($key, &$var){
    // Here $var is a reference to $myVar.
    $var = &$this->_vars[$key]; // now $var is a reference to $this->_vars[$key]
                                // it is not connected to $myVar anymore.
}

できることは次のとおりです。fetch()配列への参照を渡し、その配列内の要素を参照に設定するか、オブジェクトを$this->_vars[$key]渡してメンバー変数を参照に設定することができます。fetch()


ああ、当然のことを見逃していました。もちろん、bindReturn()提示したユースケースで関数を使用することもできます。それは問題なく動作します。

于 2011-08-12T21:23:16.193 に答える