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();
Warning: call_user_func() [function.call-user-func]开发者_Python百科: First argument is expected to be a valid callback !
My $callback value is empty, how can I resolve this issue ? Restriction : myCallback function cannot be changed !
Important: This is only possible in PHP >= 5.3. The OP does not use PHP 5.3 but I will leave the answer here in case someone has a similar problem and uses PHP 5.3.
$callback
is not a global variable, it is local in the methods scope. From the documentation:
Closures may also inherit variables from the parent scope. Any such variables must be declared in the function header. Inheriting variables from the parent scope is not the same as using global variables. Global variables exist in the global scope, which is the same no matter what function is executing. The parent scope of a closure is the function in which the closure was declared (not necessarily the function it was called from).
Make use of use
(and assign the function to a variable):
$test = function($handle, $line) use ($callback, $body){
if ($body) {
call_user_func($callback, $line);
}
if ($line === "\r\n") {
$body = true;
}
return strlen($line);
};
and later:
curl_setopt($ch, CURLOPT_WRITEFUNCTION, $test);
Just for the fun of it another one ... (not tested though).
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();
With the exception of the missing keyword when declaring $myVariable
, this should not throw an error at all, because inside the test()
function $body
is NULL
unless you defined it in the global scope. In other words, your myCallback should never get called. Apparently, you did define $body
in the global scope though and made it a great example of why using globals will lead to all sorts of unexpected behavior. If you would define $callback
in the global scope to hold 'myCallback' it should work, but you dont want globals.
And do yourself a favor and get rid of the function in the method:
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);
}
}
The test()
function is now a method inside your class. This is much clearer and more maintainable than putting the code flow into some function inside a method. Note that I pass in $body
as the first argument. I dont know how cURL accepts callbacks or what it passes to them. If you cannot make $body
the first argument, make it a class member check for it's state with $this->body
instead (as now shown by Philippe below)
精彩评论