I was wondering if there is any possibility in PHP to do following;
<?php
class boo {
static public $myVariable;
public function __construct ($variable) {
self::$myVariable = $variable;
}
}
class foo {
public $firstVar;
public $secondVar;
public $anotherClass;
public function __construct($configArray) {
$this->firstVar = $configArray['firstVal'];
$this->secondVar= $configArray['secondVar'];
$this->anotherClass= new boo($configArray['thirdVal']);
}
}
$classFoo = new foo (array('firstVal'=>'1st Value', 'secondVar'=>'2nd Value', 'thirdVal'=>'Hello World',));
echo $classFoo->anotherClass::$myVariable;
?>
Expected OUTPUT : Hello World
I am getting following error; Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM
I Googled and it is related to colon (double dots) in $classFoo->anotherClass::$myVariable
I wouldn't like to go all the trouble to change my other classes. Is there anyway around this problem?
Thank you for your help in advance.
P.S. I just didn't want to lose few hours on this to find a way around. I already spent yesterday 2.5 hours to change almost whole Jquery because customer wanted a change and today in the morning I was asked to take the changes back because they didn't want to use it (they changed their mind). I am just trying to avoid big changes right now.
You need to do:
$anotherClass = $classFoo->anotherClass;
echo $anotherClass::$myVariable;
Expanding expressions to class names/objects for static calls/constants is not supported (but expanding variables, as shown above, is).
If you do not care about memory and execution speed, this is correct.
It seems that reference would be better:
$classRef = &$classFoo->anotherClass;
echo $classRef;
Works for me.
Related
I found some strange PHP behaviour, I'm interested if someone could explain me why some parts of this code works, while others don't.
PHP can create new classes dynamically when class names are stored in variables. And it works fine since I'm using a modern version of PHP (5.5.28). But I found some strange behaviour that I don't really understand.
The problem occurs when the class name is stored in a property of some object. In this case, static functions cannot be called on the dynamic class:
$this->dynClass::SomeFunction() fails and ($this->dynClass)::SomeFunction() fails as well. However $instance = new $this->dynClass works. So if I need to call a static method on $this->dynClass, I have to create a local variable storing the same string: $tmp = $this->dynClass. And then, I can call $tmp::SomeFunction()
I really don't understand this. Could this be a bug? Please someone explain me.
Here's my example code:
<?php
class MyClass {
static function SomeFunction($name){
echo "Hello $name\n";
}
}
MyClass::SomeFunction("World"); //Works fine as it should, prints Hello World
$firstInstance = new MyClass;
$firstInstance::SomeFunction("First"); //prints hello first, no problem
//here comes the interesting part
$dynClass = "MyClass";
$dynClass::SomeFunction("Dynamic"); //Yeah, it works as well
$secondInstance = new $dynClass;
$secondInstance::SomeFunction("Second"); //Hello Second. Fine.
//And here comes the part that I don't understand
class OtherClass {
private $dynClass = "MyClass";
public function test(){
$thirdInstance = new $this->dynClass; //WORKS!
$thirdInstance::SomeFunction('Third'); //Hello Third
//BUT
$this->dynClass::SomeFunction("This"); //PHP Parse error: syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM)
//OK, but then this one should work:
($this->dynClass)::SomeFunction("This"); //same error. WHY??
//The only solution is creating a local variable:
$tmp = $this->dynClass;
$tmp::SomeFunction("Local"); //Hello Local
}
}
$otherInstance = new OtherClass;
$otherInstance->test();
?>
Before the Uniform Variable Syntax, php's variable parsing was basically a big lump of corner cases.
In particular, certain operations, like ::, where not supported on (...) expressions.
The two errors you encountered are examples of this loosely defined and inconsistent variable parser.
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.
I'm making a plugin system. I have a class extensionmanager that takes the name of a plugin as a constructor parameter. Long story short, this is the code I'm trying to run:
$this->parsedata = function($data) {
$this->extension::parsedata($data);
};
$this-extension is a string with the name of the plugin. I have run static functions in the exact way shown in this example before. Now I'm getting the error unexpected T_PAAMAYIM_NEKUDOTAYIM on that second line (I've heard it roughly translates to "unexpected double colon")
Could anyone help me understand why?
Before the above example I tried to run something like this
$this->parsedata = &$this->extension::parsedata;
Hence the question title. The top example I thought was closer to working so I changed it.
call_user_func may give you a solution. Somewhere in the examples you have this code :
<?php
namespace Foobar;
class Foo {
static public function test() {
print "Hello world!\n";
}
}
call_user_func(__NAMESPACE__ .'\Foo::test'); // As of PHP 5.3.0
call_user_func(array(__NAMESPACE__ .'\Foo', 'test')); // As of PHP 5.3.0
?>
I think you can easily adapt this to call your static function. For example something like :
call_user_func(array($this->extension, 'parseData'), $data);
Do that:
$self = $this;
$this->parsedata = function($data) use ($self) {
{$self->extension}::parsedata($data);
};
Yet, I would suggest to avoid static functions. After all, whoever is going to use your extension manager will need to conform to some interface. Why not take advantage of abstract methods or interfaces to make the user conform to your interface?
function do_something()
{
static first_time = true;
if (first_time) {
// Execute this code only the first time the function is
➥called
...
}
// Execute the function's main logic every time the function is
➥called
...
}
it's bring up this error
Parse error: parse error, expecting `T_VARIABLE' in C:\wamp\www\functions.php on line 3
This is not valid PHP. You need to define variables preceded with a $ character.
Frankly, when I saw your code, initially I thought it may be JavaScript, but then I saw the static keyword... What language could he be using now? Java? No function keyword there.... That was when I saw the tag php....
function do_something() {
static $first_time = true;
if ($first_time) {
//...
}
}
That will work.
(A bit of advice: look over your code at least a couple of times before posting here, this was quite an elementary issue)
I have a class Logger which, among other things has a method Log.
As Log is the most common use of the Logger instance, I have wired __invoke to call Log
Another class, "Site" contains a member "Log", an instance of Logger.
Why would this work:
$Log = $this->Log;
$Log("Message");
But not this:
$this->Log("Message");
The former fails with "PHP Fatal error: Call to undefined method Site::Log()"
Is this a limitation of the callable object implementation, or am I misunderstanding something?
Unfortunately, this is (still) a limitation of PHP, but it makes sense when you think about it, as a class can contain properties and methods that share names. For example:
<?php
class Test {
public $log;
public function __construct() {
$this->log = function() {
echo 'In Test::log property';
};
}
public function log() {
echo 'In Test::log() method';
}
}
$test = new Test;
$test->log(); // In Test::log() method
call_user_func($test->log); // In Test::log property
?>
If PHP were to allow the syntax you desire, which function would be invoked? Unfortunately, that only leaves us with call_user_func[_array]() (or copying $this->log to another variable and invoking that).
However, it would be nice if the following syntax was acceptable:
<?php
{$test->log}();
?>
But alas, it is not.
Same reasons you can't do this:
$value = $this->getArray()["key"];
or even this
$value = getArray()["key"];
Because PHP syntax doesn't do short hand very well.
This may work:
${this->Log}("Message");
But perhaps it's just easier and better to use the full call? There doesn't seem to be a way to get what you want to work on the one line.
The error in your question indicates it is looking for a function defined on the class which doesn't exist. An invokable object isn't a function, and it seems it can't be treated as one in this case.
as of php7.4 the following code works for me
($this->Log)("Message");