Calling variable functions with static variables - php

Approach 1 would work, but Approach 2 would not - it whould result in a fatal error (Function name must be a string in...)
# Approach 1
$function = self::$function and $function();
# Approach 2
self::$function and self::$function();
Isn't this a bit strange? I hope someone could explain.
Edit: To give some context, here's a whole class:
class Example
{
static $function;
static function method()
{
self::$function();
}
}
function callback() {}
Example::$function = 'callback';
Example::method();

If you don't want to get into technical details of precedence and ambiguity, the short explanation is that self::$function() works according to the same logic as $obj->$method(); it tries to call the variable function $function() of self.

The syntax seems ambigous to me. Probably it is for PHP too. It would be more clean, and functional to either save the function name in a local variable:
static function method()
$method = self::$function;
$method();
}
Or use call_user_func():
static function method()
call_user_func(self::$function);
}

Why approach #1 works
It's an artifact of PHP's operator precedence.
$function = self::$function and $function();
is equivalent to
($function = self::$function) and $function();
which is of course equivalent to
$function = self::$function;
if ($function) $function();
The last line works fine because that's the syntax for variable functions.
Why approach #2 does not work
Because there's ambiguity, which the compiler resolves "the wrong way".
Consider this:
self::$function();
Does this mean that PHP should invoke a callback stored in the static property $function, or that it should invoke a static method whose name is the value of the variable $function?
PHP goes with the latter but there's no variable $function in scope, resulting first in a notice and then in an error ($function evaluates to null, which is not a string).

Related

How does PHP interpret and evaluate function and anonymous function when passed as an argument?

I am a experience developer in PHP, I already know what is a function and what is a anonymous function. I also know what is the use of anonymous function and functions in PHP or in other languages. I also know the difference between function and anonymous functions.
Defination of anynonymous function is available at:
http://php.net/manual/en/functions.anonymous.php
I got the use cases of anonymous function here:
Why and how do you use anonymous functions in PHP?
But My question is how does PHP interpret/evaluate functions as arguments?
Consider below example:
<?php
function callFunction($function)
{
$function();
}
//normal function
function test()
{
echo "here";
}
//anonymous function
$function = function () {
echo 'here';
};
//call normal function test
callFunction('test');
//call anonymous function $function
callFunction($function);
In above example both function are producing same output.
But I want to know how PHP execute/interpret/evaluate both functions in callFunction method. I researched on search engins for the same but unable to found exact answer which can explain the same correctly. Please help me to understand these two cases.
Let's see the two cases separately:
<?php
function callFunction($function)
{
$function();
}
//normal function
function test()
{
echo "here";
}
//call normal function test
callFunction('test');
In this case the actual parameter for callFunction is the value "here", so a string value is passed. However, the syntax of PHP supports the concept of making it a dynamic function call: variable functions.
PHP supports the concept of variable functions. This means that if a
variable name has parentheses appended to it, PHP will look for a
function with the same name as whatever the variable evaluates to, and
will attempt to execute it. Among other things, this can be used to
implement callbacks, function tables, and so forth.
Now, onto the second case:
<?php
function callFunction($function)
{
$function();
}
//anonymous function
$function = function () {
echo 'here';
};
//call anonymous function $function
callFunction($function);
In this case $function is a Closure, as it is mentioned in the reference you linked. It is the implemented way of the function object concept in PHP. The received Closure is then executed with the parentheses operator.
You may even enforce the parameter typing in order to separate it into two different cases with type hinting:
// NOTE: string type hinting only available since PHP7
function callFunction_string(string $function)
{
$function();
}
function callFunction_closure(Closure $function)
{
$function();
}
So basically the type of the parameter received by callFunction is entirely different (string vs. Closure), however the PHP syntax is the same for both of them to execute a function call. (It's not a coincidence, it was designed like that.)
Note: similar solutions are widespread in programming languages, even in strongly typed languages like C++: just look at how function pointers, functors and lamda objects can be passed as an - templated - argument to a function, and then executed with the parentheses operator.

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

How to get an Object's Object in PHP

I'm having some troubles with some object oriented programming in PHP.
I basically have a function within a class, which displays some text:
public function text() {
echo 'text';
}
Now I want to store the function name in an arra,y so I can reference it later:
$functions = array('text_func' => 'text');
And in an other function I want to call the above function with the Array reference, so I did the following:
public function display() {
$this->functions['text_func']();
}
The result will be basically:
text();
My question is that, how is it possible to make this function run? (The correct way it should be look like: $this->text()). However I can't do something like this, because it gives me an error:
$this->$this->functions['text_func']();
Any idea or solution for my problem?
The error message you carefully ignore probably warns you that $this cannot be converted to string. That gives you a pretty good clue of what's going on.
(Long answer is that method names are strings. Since PHP is loosely typed, when it needs a string it'll try to convert whatever you feed it with into string. Your class lacks a __toString() method, thus the error.)
You probably want this:
$this->{$this->functions['text_func']}();
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Here's an example from PHP.net that should help:
<?php
class Foo
{
function Variable()
{
$name = 'Bar';
$this->$name(); // This calls the Bar() method
}
function Bar()
{
echo "This is Bar";
}
}
$foo = new Foo();
$funcname = "Variable";
$foo->$funcname(); // This calls $foo->Variable()
?>
Source: http://www.php.net/manual/en/functions.variable-functions.php
You're confusing a lot of things. First of all, you can use the magic constants __METHOD__ and __CLASS__ to determine in which class type and method you are currently executing code.
Secondly, a callable in PHP is defined as either an array with an object instance or static class reference at index 0, and the method name at index 1, or since PHP 5.2 a fully qualified string such as MyClass::myFunction. You can only dynamically invoke functions stored as one of these types. You can use the type hint callable when passing them between functions.
$this does not contain a reference for itself, so you should try just
$this->display();
instead of
$this->$this->functions['text_func'](); // WRONG

Examples of forward declarations (of functions) in PHP?

I'm posting this because it wasn't readily apparent on Google or php.net
==> Please demonstrate several examples of the syntax for forward declaring functions, in the PHP language.
For example (in C++):
int foo(); // forward declaration
int x = foo(); // calling the function.
int foo() // the actual implementation
{
return 5;
}
How would this look in PHP? How about with multiple arguments? How about with default arguments? What are the best practices and why?
You don't need to do forward declaration in PHP, instead you need to have the function declared, in current script (even if it's after the invocation), or in any included/required script, givent that the include/require statement is executed before you call the function.
There's no forward declaration.
If on the current script, even at the end, after the invocation: it' ok
If it's on a script INCLUDEd/REQUIREd by the current script, the INCLUDE/REQUIRE statement should have been executed BEFORE invocation of the function.
If it's on a script that INCLUDE/REQUIRE the current script: it's ok (even if declared AFTER the INCLUDE/REQUIRE statement)
I'd say the requested example is not the best for demonstrating the need of forward declarations. Say, we need the following instead:
function foo($n) {
echo 'Foo';
if($n>0) bar($n-1);
}
function bar($n) {
echo 'Bar';
if($n>0) foo($n-1);
}
foo(200);
The code above works perfectly in PHP despite of "undefined" function bar inside foo. It appears that PHP checks function definition when it is called.
So the answer is:
PHP doesn't have forward declarations.
The function doesn't have to
be defined before it appears in the text, but it must be defined
before it is called.
Would it not just be...
$x = foo();
function foo() {
return 5;
}
echo $x; //echos "5"
?
PHP does not do forward function declarations (or "function prototyping*). The closest thing we have is Object Interfaces and Abstract Methods. These are called "method prototypes" or "method declarations" (declaration as opposed to definition, which carries a c-style semantic)
Interface MyWidgetInterface {
function calculateThings(SomeClass $foo);
}
Abstract Class MyAbsClass {
public abstract function sayHello();
}
Class MyObj Extends MyAbsClass Implements MyWidgetInterface {
public function calculateThings(SomeClass $foo) {
}
public function sayHello() {
echo "Hi!\n";
}
}
$thing = new MyObj();
$thing->sayHello();
One of the reasons we don't have/need forward declared functions is that php parses your script before it compiles it, every time. It finds your functions before it starts executing the file, so it knows they are there. In fact, I can't remember how far back you'd have to go to even have to have defined the function before calling it. I've been doing PHP for 9 years and it's never needed that :-)
If you want that a function to return a certain type value in PHP, you can use something like this.
function foo($param) {
// code
return (int) $param; // or (string), (float)
}
Or, when you access the function:
$x = (int) foo($param);
Referring to the default argument you can do like this
function foo( $param1="value1" , $param2="value2" ){
echo $param1." ".$param2;
}
foo();
foo("not default","not default");
foo(NULL,"not default");

PHP create_function Instance variable - Unable to call anonymous function: Follow up

This is somewhat a follow up to a previous question - but I've distilled the question down and have the "works" vs. "doesn't work" cases narrowed down much more precisely.
My Goal:
I have a class MyClass that has an instance variable myFunction. Upon creating a MyClass object (instantiating), the constructor assigns the instance variable myFunction with the result of a call to create_function (where the code and args come from a db call).
Once this object of type MyClass is created (and stored as an instance variable of another class elsewhere) I want to be able to call myFunction (the instance variable anonymous function) from "anywhere" that I have the MyClass object.
Experimental Cases -- below is my highly simplified test code to illustrate what works vs. what doesn't (i.e. when the expected functionality breaks)
class MyClass extends AnotherClass {
public $myFunction;
function __construct() {
$functionCode = 'echo "NyanNyanNyan";';
$this->myFunction();
/*Now the following code works as expected if put in here for testing*/
$anonFunc = $this->myFunction;
$anonFunc(); //This call works just fine (echos to page)!
/*And if i make this call, it works too! */
self::TestCallAnon();
}
public function TestCallAnon() {
$anonFunc2 = $this->myFunction;
$anonFunc2();
}
}
However, if I do the following (in another file, it errors saying undefined function () in... within the Apache error log.
//I'm using Yii framework, and this is getting the user
//objects instance variable 'myClass'.
$object = Yii::app()->user->myClass;
$object->TestCallAnon(); // **FAILS**
or
$func = $object->myFunction;
$func(); // ** ALSO FAILS **
In addition, several variations of calls to call_user_func and call_user_func_array don't work.
If anyone is able to offer any insight or help that would be great :).
Thanks in advance!
You can't pass references to functions around in PHP like you can in for instance JavaScript.
call_user_func has limited functionality. You can use it like so:
class MyClass {
function func() {}
static function func() {}
}
function myfunc() {}
$i = new MyClass();
call_user_func("myfunc", $args);
call_user_func(array($i, "func"), $args);
call_user_func(array(MyClass, "staticFunc"), $args);
I ended up solving this issue via a workaround that ended up being a better choice anyways.
In the end I ended up having a static class that had a method to randomly return one of the possible identifiers, and then another method which accepted that identifier to build the anonymous function upon each class.
Slightly less elegant than I would like but it ends up working well.
Thanks to everyone for your efforts.

Categories