php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #45925 Callback as Closure object
Submitted: 2008-08-26 16:33 UTC Modified: 2008-08-26 22:14 UTC
Votes:2
Avg. Score:5.0 ± 0.0
Reproduced:2 of 2 (100.0%)
Same Version:1 (50.0%)
Same OS:0 (0.0%)
From: david at grudl dot com Assigned:
Status: Wont fix Package: Feature/Change Request
PHP Version: 5.3.0alpha1 OS: -
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: david at grudl dot com
New email:
PHP Version: OS:

 

 [2008-08-26 16:33 UTC] david at grudl dot com
Description:
------------
It should be useful to encapsulate PHP pseudotype callback using new magic method __invoke(). But this type of "callable" objects are not distinguishable by any interface or class name (compare it with ArrayAccess or Countable interfaces).

// this is simple callback encapsulation
class Callback 
{
	private $callback;

	public function __construct($callback)
	{
		$this->callback = $callback;
	}

	public function __invoke()
	{
		$args = func_get_args();
		return call_user_func_array($this->callback, $args);
	}
}


// a Callback object:
$callback = new Callback(array('MyClass', 'anyMethod'));

// a Closure object:
$closure = function() { ... };


The problem: there is nothing common between Callback and Closure object, what can be used (for example) as type hinting. 

First solution using interface:

interface Callable { 
    function __invoke()
}

class Callback implements Callable { ... }

function event(Callable $obj)
{
	$obj($sender, $param);
}

event($callback);
event($closure); // do not work

The class Closure is not Callable implementor thus it do not work. Problematic is __invoke method's parameters too.

The other way:

class Callback extends Closure { ... } // do not work

function event(Closure $obj)
{
	$obj($sender, $param);
}

event($callback);
event($closure);

This is not possible, because Closure is final. Solution is make Closure non-final.

The third way - create static factory to encapsulate PHP callback as Closure:

function event(Closure $obj)
{
	$obj($sender, $param);
}

$callback = Closure::factory(array('MyClass', 'anyMethod'));
event($callback);
event($closure);

Maybe the most easy way.


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2008-08-26 20:08 UTC] colder@php.net
__invoke takes arbitrary arguments, which means you can't have an interface that covers it.
 [2008-08-26 20:17 UTC] david at grudl dot com
Thats right (this is mentioned in text). But interface Callable can exists without any method (so-called "marker interface"). 

What about two others solutions?
 [2008-08-26 22:14 UTC] colder@php.net
You want to be able to type hint the fact that an object can be invoked.

You may want __invoke on a class without having anything related to closures, so the other solutions don't sound reasonable as well. But if you really feel they are, write an RFC and post it on the internals ML.


 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Dec 26 21:01:28 2024 UTC