PHP / Scope / Callback

时间:2010-07-29 07:54:19

标签: php scope callback

class myClass {         $ myVariable ='myCallback';

    function myFunction() {
        $body = false;
        $callback = $this->myVariable;

        function test($handle, $line) {
            global $body, $callback;

            if ($body) {
                call_user_func($callback, $line);
            }

            if ($line === "\r\n") {
                $body = true;
            }

            return strlen($line);
        }

        ...
        curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'test');
        ...
    }
}

function myCallback($data) {
    print $data;
}

$myCls = new myClass();
$myCls->myFunction();

警告:call_user_func()[function.call-user-func]:第一个参数应该是一个有效的回调!

我的$回调值为空,如何解决此问题? 限制:myCallback功能无法更改!

3 个答案:

答案 0 :(得分:10)

重要提示:这仅适用于PHP> = 5.3。 OP不使用PHP 5.3,但我会留下答案,以防有人遇到类似问题并使用PHP 5.3。


$callback不是全局变量,它在方法范围内是本地变量。来自documentation

  

闭包还可以从父作用域继承变量。 必须在函数头中声明任何此类变量。从父作用域继承变量与使用全局变量不同。全局变量存在于全局作用域中,无论执行什么函数,它都是相同的。闭包的父作用域是声明闭包的函数(不一定是从中调用它的函数)。

利用use(并将函数分配给变量):

$test = function($handle, $line) use ($callback, $body){

    if ($body) {
        call_user_func($callback, $line);
    }

    if ($line === "\r\n") {
        $body = true;
    }

    return strlen($line);
};

以后:

curl_setopt($ch, CURLOPT_WRITEFUNCTION, $test);

答案 1 :(得分:2)

除了声明$myVariable时丢失的关键字之外,这不应该抛出错误,因为test()函数$body内部是NULL除非您定义它在全球范围内。换句话说,永远不应该调用 myCallback 。显然,您确实在全局范围内定义了$body,并使其成为使用全局变量导致各种意外行为的一个很好的例子。如果你要在全局范围内定义$callback来保存'myCallback'它应该可以工作,但是你不想要全局变量。

并帮自己一个忙,摆脱方法中的功能:

class myClass {

    protected $_myVariable = 'myCallback';

    public function myFunction()
    {
        // calling callback that calls callback (should make you think ;))
        // that would be your curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'test');
        echo call_user_func_array(
            array($this, '_test'),
            array('body', 'foo', 'bar'));
    }

    protected function _test($body, $handle, $line)
    {
        if ($body) {
            call_user_func($this->_myVariable, $line);
        }
        if ($line === "\r\n") {
            $body = true;
        }
        return strlen($line);
    }
}

test()函数现在是您班级中的一种方法。与将代码流放入方法中的某个函数相比,这更清晰,更易于维护。请注意,我传入$body作为第一个参数。我不知道cURL如何接受回调或它传递给它们的内容。如果您无法将$body作为第一个参数,请将其作为类成员检查其状态为$this->body而不是as now shown by Philippe below

答案 2 :(得分:2)

只为了另一个的乐趣......(虽未测试)。

class myClass
{
    protected $callback = 'myCallback';
    protected $body = false;

    public function myFunction()
    {
        ...
        curl_setopt($ch, CURLOPT_WRITEFUNCTION, array($this, 'test'));
        ...
    }


    public function test($handle, $line)
    {
        if ($this->body) {
            call_user_func($this->callback, $line);
        }

        if ($line === "\r\n") {
            $body = true;
        }

        return strlen($line);
    }
}

function myCallback($data) {
    print $data;
}

$myCls = new myClass();
$myCls->myFunction();