Determining, if a variable is a valid closure in PHP - php

Using the following function:
function is_closure($t) { return ( !is_string($t) && is_callable($t)); }
Can this return true for anything else, than an anonymous closure function? If so, what would be the correct way to determine, if a variable is a closure?
Many thanks

The most deterministic way to check if a callback is an actual closure is:
function is_closure($t) {
return $t instanceof \Closure;
}
All anonymous functions are represented as objects of the type Closure in PHP. (Which, coming back to above comment, happen to implement the __invoke() method.)

I think you can use instanceof Closure though the manual states this should not be relied upon. I guess it works for now.
Anonymous functions are currently implemented using the Closure class. This is an implementation detail and should not be relied upon.
Update
The Closure manual page has updated its guidance on this. It appears that this behaviour can now be relied upon.
Anonymous functions, implemented in PHP 5.3, yield objects of this type. This fact used to be considered an implementation detail, but it can now be relied upon.

php.net suggests using reflections to figure out if the variable contains a valid closure or not
I use this little helper
function isClosure($suspected_closure) {
$reflection = new ReflectionFunction($suspected_closure);
return (bool) $reflection->isClosure();
}

This is supported with Reflection http://www.php.net/manual/en/reflectionfunctionabstract.isclosure.php

If you get an error about that does not exist ReflectionFunction, use backslash before class:
// Closure
$closure = function () {};
$reflection = new \ReflectionFunction($closure);
// checkout if it is a closure
$test->isTrue($reflection->isClosure());

Related

How to check if object has method in Symfony2

I want to use the same piece of code for managing multiple entities but it might be a little different depending if it has some method or not. Thats why I need to check if object has method by name. Is there any way to do that?
You can simply use is_callable:
if (is_callable([$entity, 'methodName']))
doSomething();
A cleaner approach is to check for the class of an object with instanceof. Because methods will come and go, but the character of an object is determined by its class:
if ($entity instanceof \Some\Bundle\Entity\Class)
doSomething();
This has nothing to do with Symfony, it's basic PHP thing: use method_exists PHP function.
bool method_exists ( mixed $object , string $method_name )
PHP Docs
While this is a perfectly fine way to go around it, you might want to look into interfaces as an alternative: PHP Interfaces
If you do decide to use them, you can just check if object is an instance of your interface:
interface MyAwesomeInterface
{
public function myFunction();
}
if ($myObject instanceof MyAwesomeInterface) {
$myObject->myFunction();
}

PHP - is there a way to save an already defind function in a variable?

I am interested in something google couldn't really help me with...
I know that its possible to use anonymous functions and also store functions in a variable in PHP like that
$function = function myFoo() { echo "bar"; }
and call it using the variable: $function();
So far so good but what if I have a function or method declared somewhere but not saved on intializing?
I have a function that shall expect a callable, of course call_user_func() can help me here but then I need to pass the method name in my callback handler which I think is pretty unsafe because in the moment I add the callback I cant say if it really is a function and exists when I store it.
Thatswhy I would like to realize the following szenario:
This function:
function anyFunction() {
echo "doWhatever...!";
}
should be saved in a variable at a later point in time:
$myOtherFunction = get_registered_func("anyFunction");
I know get_registered_func() doesnt exist but I want to know if this is possible somehow!
With this I could now have another function
function setCallback(callable $theCallbackFunction) { }
And use it like this:
setCallback($myOtherFunction);
This would have a great advantage that an exception / a fatal is thrown when the parameter is no function or does not exist.
So in short, is there a way to store a previously defined, already existing function or method in a variable?
PHP's callable meta type can be:
a string
an array
an anonymous function
Only the latter one is somewhat "type safe", i.e. if you get an anonymous function you know it's something you can call. The other two options are merely formalised informal standards (if that makes sense) which are supported by a few functions that accept callbacks; they're not actually a type in PHP's type system. Therefore there's basically no guarantee you can make about them.
You can only work around this by checking whether the callable you got is, well, callable using is_callable before you execute them. You could wrap this into your own class, for example, to actually create a real callable type.
I see no reason why this shouldn't be possible, other than there not being a PHP function to do it. The anonymous function syntax is newly introduced in PHP, I wouldn'be surprised if it was still a little rough around the edges.
You can always wrap it:
function wrap_function ($callback) {
if (is_callable($callback) === false) {
throw new Exception("nope");
}
return function () {
call_user_func($callback, func_get_args());
}
}
$foo = new Foo();
$ref = wrap_function(array($foo, "bar"));
Not a good way, but maybe this helps you:
function foo($a) {
echo $a;
}
$callFoo = 'foo';
$callFoo('Hello World!'); // prints Hello

PHP detect closures [duplicate]

Using the following function:
function is_closure($t) { return ( !is_string($t) && is_callable($t)); }
Can this return true for anything else, than an anonymous closure function? If so, what would be the correct way to determine, if a variable is a closure?
Many thanks
The most deterministic way to check if a callback is an actual closure is:
function is_closure($t) {
return $t instanceof \Closure;
}
All anonymous functions are represented as objects of the type Closure in PHP. (Which, coming back to above comment, happen to implement the __invoke() method.)
I think you can use instanceof Closure though the manual states this should not be relied upon. I guess it works for now.
Anonymous functions are currently implemented using the Closure class. This is an implementation detail and should not be relied upon.
Update
The Closure manual page has updated its guidance on this. It appears that this behaviour can now be relied upon.
Anonymous functions, implemented in PHP 5.3, yield objects of this type. This fact used to be considered an implementation detail, but it can now be relied upon.
php.net suggests using reflections to figure out if the variable contains a valid closure or not
I use this little helper
function isClosure($suspected_closure) {
$reflection = new ReflectionFunction($suspected_closure);
return (bool) $reflection->isClosure();
}
This is supported with Reflection http://www.php.net/manual/en/reflectionfunctionabstract.isclosure.php
If you get an error about that does not exist ReflectionFunction, use backslash before class:
// Closure
$closure = function () {};
$reflection = new \ReflectionFunction($closure);
// checkout if it is a closure
$test->isTrue($reflection->isClosure());

Using $this when not in object context ... stack issue?

I'm getting the error Using $this when not in object context when using the code below. Is this because the function is on the stack and has no access to the object?
array_walk($pins, function (&$array) {
$array->timestamp = $this->convertTime(strtotime($array->timestamp));
});
What's the best way to get around this? I was thinking of using a foreach, but wanted to learn more of PHP's lesser used functions that suit the purpose.
Solved it with
foreach($pins as $pin) {
$pin->timestamp = $this->convertTime(strtotime($pin->timestamp));
}
But I would still like to know how to get around the issue with array_walk.
try this:
$that =& $this;
array_walk($pins, function (&$array) use ($that) {
$array->timestamp = $that->convertTime(strtotime($array->timestamp));
});
Also, if you are actually walking an array, the correct syntax will probably be:
$that =& $this;
array_walk($pins, function (&$array) use ($that) {
$array['timestamp'] = $that->convertTime(strtotime($array['timestamp']));
});
What's the best way to get around this? I was thinking of using a foreach, but wanted to learn more of PHP's lesser used functions that suit the purpose.
I would say for your case, foreach is a very good solution because it's clear what it does. You might want to mimic the aliasing array_walk offers with your example:
foreach($pins as &$pin) {
$pin->timestamp = $this->convertTime(strtotime($pin->timestamp));
}
unset($pin);
This should come more closely to array_walk. Probably you want to reference the array itself as well (probably):
$pinsRef = &$pins;
foreach($pinsRef as &$pin) {
$pin->timestamp = $this->convertTime(strtotime($pin->timestamp));
}
unset($pin);
If you want to encapsulate the object itself ($this) inside an anonymous function with private access, this is not possible. Because there does not exists any $this in the context of the anonymous function (yet, a later PHP version might have that).
However one workaround is to pass the object instance into the local scope of the anonymous function by making use of the use clause.
$_this = $this;
$callback = function (&$array) use ($_this) {
$array->timestamp = $_this->convertTime(strtotime($array->timestamp));
});
array_walk($pins, $callback);
But this workaround is limited, as private members of $this are not accessible. Instead you can create the callback function as part of your object and specify it, private access is possible then and you can invoke it like any other object callback:
array_walk($pins, array($this, 'callback'));
Which brings me back to the beginning saying that foreach is probably the better weapon of choice than array_walk in your case.
I hope this is helpful to show you the different alternatives.
The reason is that you're passing a plain function which is not part of an object. As there is no object, there's nothing $thiscould point to. If convertTime is in global scope, simply omit $this->. Othwewise, consider passing an object as a callback to array_walk.
As of PHP 5.4.0, you can access $this from inside of anonymous functions.

What exactly is the difference between the is_callable and function_exists in PHP?

I am working on a project, in which I am using a deprecated function from the older version. But don't want my script to stop if used in the older version.
So I am checking if the function exists and if not then create it.
What is the difference between function_exists and is_callable in PHP and which one is better to use?
if (!is_callable('xyz')) {
function xyz() {
// code goes here
}
}
OR
if(!function_exists('xyz')) {
function xyz() {
// code goes here
}
}
The function is_callable accepts not only function names, but also other types of callbacks:
Foo::method
array("Foo", "method")
array($obj, "method")
Closures and other invokable objects (PHP 5.3)
So is_callable accepts anything that you could pass call_user_func and family, while function_exists only tells if a certain function exists (not methods, see method_exists for that, nor closures).
Put another way, is_callable is a wrapper for zend_is_callable, which handles variables with the pseudo-type callback, while function_exists only does a hash table lookup in the functions' table.
When used with a function (not a class method) there is no difference except that function_exists is slightly faster.
But when used to check the existence of methods in a class you cannot use function_exists. You'll have to use is_callable or method_exists.
When used in class context, is_callable returns true for class methods that are accessible ie public methods but method_exists returns true for all methods - public, protected and private. function_exists does same thing as method_exists outside class contexts.
If a function Plop exists then function_exists("Plop") will return true.
See function_exists
If a variable is callable then is_callable($var) will return true.
Now this could mean that $var is a function name.
But i could also be an object and method name combo.
See is_callable
One more different:
If you have a class which uses __call magic method, the is_callable($object, $method) will always return true for anything because __call basically accepts every method name. And as you might already know, method_exists will return false for this if the method is not defined in the class.
This is especially annoying if you use CakePHP Model class as they implemented __call magic method to provide magic queries, but not cool if you want the method to be absolutely defined.

Categories