At the moment it isn't possible to restrict/define the arguments for a
closure which is defined as parameter for a method. Please look at this
small example.
interface Broker {
public function scan(Request $request, Closure $onFound);
}
An implementation of the interface could be as follows:
class BrokerImpl implements Broker {
/**
* @var Service
*/
private $service = null;
public function scan(Request $request, Closure $onFound) {
if ($request->contains('some value')) {
$onFound($this->service);
}
}
}
The problem is that I can pass every closure to the scan method.
$broker = new BrokerImpl();
$broker->scan($request, function() { /* do something */ });
Sometimes I would like to restrict the closure passed to this method.
So that only closures of a certain type which has an argument "Service
$service" could be passed to this method.
$broker = new BrokerImpl();
$broker->scan($request, function(Service $service) { /* do something */
});
Would it not be possible to extend the Closure class and then define an
abstract method signature for the __invoke method.
class OnFoundClosure extends Closure {
public abstract function __invoke(Service $service);
}
And then you can define the interface as follows:
interface Broker {
public function scan(Request $request, OnFoundClosure $onFound);
}
Now if you pass a closure to the scan method which doesn't follow the
signature of the __invoke method, the engine should throw an error.
What do you think?
On Oct 12, 2012 10:59 AM, "Christian Kaps" christian.kaps@mohiva.com
wrote:
At the moment it isn't possible to restrict/define the arguments for a
closure which is defined as parameter for a method. Please look at this
small example.interface Broker {
public function scan(Request $request, Closure $onFound);
}
An implementation of the interface could be as follows:
class BrokerImpl implements Broker {
/** * @var Service */ private $service = null; public function scan(Request $request, Closure $onFound) { if ($request->contains('some value')) { $onFound($this->service); } }
}
The problem is that I can pass every closure to the scan method.
$broker = new BrokerImpl();
$broker->scan($request, function() { /* do something */ });Sometimes I would like to restrict the closure passed to this method. So
that only closures of a certain type which has an argument "Service
$service" could be passed to this method.$broker = new BrokerImpl();
$broker->scan($request, function(Service $service) { /* do something */
});Would it not be possible to extend the Closure class and then define an
abstract method signature for the __invoke method.class OnFoundClosure extends Closure {
public abstract function __invoke(Service $service);
}
And then you can define the interface as follows:
interface Broker {public function scan(Request $request, OnFoundClosure $onFound);
}
Now if you pass a closure to the scan method which doesn't follow the
signature of the __invoke method, the engine should throw an error.What do you think?
--
Honestly, I would suggest using a class directly if you want that kind of
type control. Closures are meant to be a conscience, not the end all be all
implementation.
I understand what you are looking for. But to me, unless we implemented
function pointers (typeable callbacks), I can't see the generalized use
case. At least that isn't already solvable using classes, interfaces and
polymorphism...
Anthony
Hi!
Now if you pass a closure to the scan method which doesn't follow the
signature of the __invoke method, the engine should throw an error.What do you think?
You are trying to take typing way beyond what PHP (or probably any
mainstream dynamic language that exists now) provides. There are
languages which provide static type systems capable of doing such
things, but PHP isn't one of them and I don't think it should be. PHP
has no static type control, and IMHO doing type safety validation at
runtime does not seem to be a good proposition for PHP.
Stanislav Malyshev, Software Architect
SugarCRM: http://www.sugarcrm.com/
(408)454-6900 ext. 227
Hi
Now if you pass a closure to the scan method which doesn't follow the
signature of the __invoke method, the engine should throw an error.What do you think?
You are trying to take typing way beyond what PHP (or probably any
mainstream dynamic language that exists now) provides. There are
languages which provide static type systems capable of doing such
things, but PHP isn't one of them and I don't think it should be. PHP
has no static type control, and IMHO doing type safety validation at
runtime does not seem to be a good proposition for PHP.
I thought it would be a good idea to make the closure functionality
consistent with the rest of the language. Because closures are currently
implemented as class. And with classes it is possible to define static
type checks at runtime. The other thing is that I can define a static
type control for closures. It works only the other way around. Because
the caller can define the static type control and not the interface
designer.
$closure = function(Foo $foo, Bar $bar) {};
function execute(Closure $closure) {
$closure(1, 2);
}
execute($closure); // PHP Catchable fatal error: Argument 1 passed to
{closure}() must be an instance of Foo, integer given
Normally as interface designer I would like to define what a caller of
the interface should be passed to a certain method. Yes I know with
primitive types, this isn't possible in PHP. But with closure I have the
option to restrict the interface. Sure I can do this only for one type
of a closure. Quasi the the smallest common denominator. But it's possible.
So when we look at the above example then it throws an error, because
the caller passes the wrong type of a closure to the interface. But what
is wrong, I have passed a closure to the method! So it seems that the
interface lies. And for me this is the inconsistency in the
implementation. I cannot tell the caller, what type of closure he must
pass to the interface. And yes, for me a closure can be of a different
type. If closures have different parameter signatures than they are of a
different type.
But this is only my subjective opinion. And I'm guessing by the
reactions of my post that I'm all alone with it (o;
Cheers,
Christian
On Fri, Oct 12, 2012 at 10:58 AM, Christian Kaps
christian.kaps@mohiva.com wrote:
At the moment it isn't possible to restrict/define the arguments for a
closure which is defined as parameter for a method. Please look at this
small example.interface Broker {
public function scan(Request $request, Closure $onFound);
}
An implementation of the interface could be as follows:
class BrokerImpl implements Broker {
/** * @var Service */ private $service = null; public function scan(Request $request, Closure $onFound) { if ($request->contains('some value')) { $onFound($this->service); } }
}
The problem is that I can pass every closure to the scan method.
$broker = new BrokerImpl();
$broker->scan($request, function() { /* do something */ });Sometimes I would like to restrict the closure passed to this method. So
that only closures of a certain type which has an argument "Service
$service" could be passed to this method.$broker = new BrokerImpl();
$broker->scan($request, function(Service $service) { /* do something */ });Would it not be possible to extend the Closure class and then define an
abstract method signature for the __invoke method.class OnFoundClosure extends Closure {
public abstract function __invoke(Service $service);
}
And then you can define the interface as follows:
interface Broker {public function scan(Request $request, OnFoundClosure $onFound);
}
Now if you pass a closure to the scan method which doesn't follow the
signature of the __invoke method, the engine should throw an error.What do you think?
Please also don't forget that PHP doesn't have strict function
signatures. E.g. you can write
function($foo) {
echo $foo;
}
but you could also write
function() {
$foo = func_get_arg(0);
echo $foo;
}
So I'm not sure just how much sense function signature checking makes in PHP ;)
Nikita
Am 12.10.2012 23:06, schrieb Nikita Popov:
On Fri, Oct 12, 2012 at 10:58 AM, Christian Kaps
christian.kaps@mohiva.com wrote:At the moment it isn't possible to restrict/define the arguments for a
closure which is defined as parameter for a method. Please look at this
small example.interface Broker {
public function scan(Request $request, Closure $onFound);
}
An implementation of the interface could be as follows:
class BrokerImpl implements Broker {
/** * @var Service */ private $service = null; public function scan(Request $request, Closure $onFound) { if ($request->contains('some value')) { $onFound($this->service); } }
}
The problem is that I can pass every closure to the scan method.
$broker = new BrokerImpl();
$broker->scan($request, function() { /* do something */ });Sometimes I would like to restrict the closure passed to this method. So
that only closures of a certain type which has an argument "Service
$service" could be passed to this method.$broker = new BrokerImpl();
$broker->scan($request, function(Service $service) { /* do something */ });Would it not be possible to extend the Closure class and then define an
abstract method signature for the __invoke method.class OnFoundClosure extends Closure {
public abstract function __invoke(Service $service);
}
And then you can define the interface as follows:
interface Broker {public function scan(Request $request, OnFoundClosure $onFound);
}
Now if you pass a closure to the scan method which doesn't follow the
signature of the __invoke method, the engine should throw an error.What do you think?
Please also don't forget that PHP doesn't have strict function
signatures. E.g. you can writefunction($foo) { echo $foo; }
but you could also write
function() { $foo = func_get_arg(0); echo $foo; }
So I'm not sure just how much sense function signature checking makes in PHP ;)
Nikita
What did you mean with strict function signatures?
Is this not a strict function signature?
function(Foo $foo) {}
Christian