The PHP manual says
Like static members, constant values can not be accessed from an instance of the object.
which explains why you can't do this
$this->inst = new Classname();
echo $this->inst::someconstant;
but then why does this work?
$this->inst = new Classname();
$inst = $this->inst;
echo $inst::someconstant;
From the PHP interactive shell:
php > class Foo { const A = 'a!'; }
php > class Bar { public $foo; }
php > $f = new Foo;
php > $b = new Bar;
php > $b->foo = $f;
php > echo $b->foo::A;
PHP Parse error: syntax error, unexpected T_PAAMAYIM_NEKUDOTAYIM, expecting ',' or ';' in php shell code on line 1
The reason that the former syntax fails is that the PHP parser doesn't know how to resolve the double-colon after the property reference. Whether or not this is intentional is unknown.
The latter syntax works because it's not going through the property directly, but through a local variable, which the parser accepts as something it can work with:
php > $inst = $b->foo;
php > echo $inst::A;
a!
(Incidentally, this same restriction is in place for anonymous functions as properties. You can't call them directly using parens, you have to first assign them to another variable and then call them from there. This has been fixed in PHP's trunk, but I don't know if they also fixed the double colon syntax.)
If you are within the class, you can access the constant like this:
self::MY_CONSTANT;
For example:
class MyClass {
const MY_CONSTANT = 'constant value';
public function showConstant() {
echo self::MY_CONSTANT;
}
}
http://php.net/manual/en/language.oop5.constants.php
To quote the manual:
As of PHP 5.3.0, it's possible to reference the class using a variable. The variable's value can not be a keyword (e.g. self, parent and static).
It goes on to use this example:
$class = new MyClass();
echo $class::constant."\n"; // As of PHP 5.3.0
So $inst::someconstant is supposed to work.
As to why $this->inst::someconstant gives a parsing error, I don't know. PHP is funny about some things.
php supports accessing class constants from an object instance. Code below is working (checked in phpv5.5.5):
<?php
class superheroes{
const kal_el = 'Superman';
}
$instance = new superheroes;
echo $instance::kal_el;
Source: http://dwellupper.io/post/48/defining-class-constants-in-php
Related
Just trying to save and fix sources from PHPBench.com
and hit this error (the site is down and the author didn't respond to questions). This is the source:
<?php
// Initial Configuration
class SomeClass {
function f() {
}
}
$i = 0; //fix for Notice: Undefined variable i error
// Test Source
function Test6_2() {
//global $aHash; //we don't need that in this test
global $i; //fix for Notice: Undefined variable i error
/* The Test */
$t = microtime(true);
while($i < 1000) {
$obj =& new SomeClass();
++$i;
}
usleep(100); //sleep or you'll return 0 microseconds at every run!!!
return (microtime(true) - $t);
}
?>
Is it a valid syntax or not? Correct me if I'm wrong but think it creates a reference to SomeClass, so we can call new $obj() ... Thanks in advance for the help
Objects are always stored by reference anyway. You don't need =& and as Charlotte commented, it's deprecated syntax.
Correct me if I'm wrong but think it creates a reference to SomeClass, so we can call new $obj() .
No, this is not correct. The new operator always creates an instance of the class, not a reference to the class as a type.
You can create a variable object instantiation simply by creating a string variable with the name of the class, and using that.
$class = "MyClass";
$obj = new $class();
Functions like get_class() or ReflectionClass::getName() return the class name as a string. There is no "reference to the class" concept in PHP like there is in Java.
The closest thing you're thinking of is ReflectionClass::newInstance() but this is an unnecessary way of creating an object dynamically. In almost every case, it's better to just use new $class().
Running PHP 5.4, so I wasn't expecting this, but I'm encountering the following error:
Parse error: syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM)
Assume you have a variable of stdClass setup as follows:
$this->variable = new stdClass();
$this->variable->other = array('class' => 'helloworld');
Now, assume you want to access a static method of class helloworld:
// Standard call
$x = helloworld::my_static_method();
// Call with variable class name
$x = $this->variable->other['class']::my_static_method();
When calling the above using the variable class name, I receive the parsing error. What's odd, is that if I do the following, no error is presented:
$class = $this->variable->other['class'];
$x = $class::my_static_method();
To me this seems very odd, can anyone think of a reason why the class name isn't resolving correctly when using the first example versus the second?
can anyone think of a reason why the class name isn't resolving correctly when using the first example versus the second?
The PHP parser does not support such a syntax, and that's merely all. This is because the parser has grown historically. I can't give more reason than that.
It will be that with PHP 7 you can see some changes on these syntax details working more into your expected direction Uniform Variable Syntax:
($variable->other['class'])::my_static_method();
But until then, you can go around that with the help of call_user_func:
call_user_func([$variable->other['class'], 'my_static_method']);
call_user_func($variable->other['class'] . '::my_static_method');
Or as you wrote your own, by creating a variable:
$class = $variable->other['class'];
$class::my_static_method();
Or even a variable that looks like something different:
${(int)!${0}=$variable->other['class']}::my_static_method();
Related Material:
Interpolation (double quoted string) of Associative Arrays in PHP
This doesn't work ($this->variable->other['class']::my_static_method()) as it's essentially using a string as the class name directly. It works when you assign it to a variable first, as it's then being evaluated out as the class name instead.
You can also look into using ReflectionMethod invocation in order to call the method, in which case you wouldn't have to store the class name in a variable before using it. Here's the docs on that: http://php.net/manual/en/class.reflectionmethod.php and on the invoke method (you pass in NULL to indicate a static method) http://php.net/manual/en/reflectionmethod.invoke.php
Here are a couple examples of ways to invoke your function:
class helloworld{
public static function my_static_method($i = 0){
echo "Here: ".$i;
}
}
class Foo{
private $variable;
public function __construct(){
//Create a new class
$this->variable = new stdClass();
//Create a new property of the class, storing an array
$this->variable->other = array('class' => 'helloworld');
//Call function statically
$x = helloworld::my_static_method(1); //Outputs: "Here: 1"
//Store class name in a variable before use
$class = $this->variable->other['class'];
$y = $class::my_static_method(2); //Outputs: "Here: 2"
//Using a ReflectionMethod, you can call the function this way, too
$z = new ReflectionMethod($this->variable->other['class'], 'my_static_method');
$z->invoke(null, 3); //Outputs: "Here: 3"
}
}
//Instantiate new Foo class
new Foo();
The following code uses the string "rand" stored in the property $prop to call rand() as a variable function, by using $function as a temporary local variable.
class C
{
private $prop = "rand";
public function execute()
{
$function = $this->prop;
echo $function();
}
}
$c = new C();
$c->execute();
This works, but I need to call the variable function stored in $this->prop using only one statement and avoiding the temporary variable.
I had no luck with
echo $this->prop();
because it actually calls the method prop() which does not exist and in any case it is not what I want to do.
As $this->prop is actually a string, I tried the following, but it produces a syntax error:
echo ($this->prop)();
I also tried
echo call_user_func($this->prop);
Although it does the work, it is not an option for me because it is not a variable function.
It seems like variable functions only work using local variables as function name.
Does anybody know a way to call directly a variable function using a class property as function name, avoiding the local temporary variable and the usage of call_user_func()?
Edit:
I understand your perplexity, therefore I'm going to explain what's wrong with using call_user_func.
I'm just exploring the opportunities offered by variable functions, which seems to be less then those offered by variable variables.
Let's try using variable variables feature it its simplest form.
Suppose we have a function f() which returns the string "something"
function f() {
return "something";
}
then a class property containing the string "something"
$this->prop = "something";
$something is a local variable
$something = "I am a local variable";
Then all the following statements will work:
$r = ${"something"};
$r = ${$this->prop};
$r = ${f()};
My personal conclusion: No matter how the string "something" has been obtained; just surround it with braces {} and prepend a dollar symbol $ to consider it a variable.
Pretty flessibe.
Let's try the same for variable functions
Now we have a function f() which returns the string "rand"
function f() {
return "rand";
}
then a class property containing the string "rand"
$this->prop = "rand";
Variable functions on the other hand, does not allow a string followed by parenthesis () to be considered a function call.
$r = "rand"(); // Produces a syntax error, unexpected '()' after a string
$r = $this->prop(); // Calls the 'prop()' method, which does not exist
$r = f()(); // Again a syntax error, unexpected '()' after the function f()
I have to conclude that variable functions always require a local variable to be run :(
You need to implement a magic __call method, like this:
class C
{
private $prop = "execute";
public function __call($method, $args)
{
if($method == "prop") // just for this prop name
{
if(method_exists($this, $this->prop))
return call_user_func_array([$this, $this->prop], $args);
}
}
public function execute ($s){
echo '>>'.$s.'<<';
}
}
$c = new C;
$c->prop(123);
It certainly does feel like a glaring omission in PHP's syntax. (Although taken literally I guess they are variable functions, not property functions!?) I would have perhaps expected the following "curly brace" syntax to work, but it doesn't, Parse error: syntax error, unexpected '{' in ....
echo {$this->prop}();
However, there are significant benefits to using variable function syntax over other methods. Variable functions are quicker than call_user_func() / call_user_func_array() and natively support pass-by-reference, rather than the "special-case" call-time pass-by-reference with call_user_func_array() (which is deprecated in all other cases).
An alternative to the __call magic method (above), which is going to be relatively slow, is to simply use a wrapper method, to which you pass the function/method name and use variable functions inside that wrapper method.
In its most simplest form:
function callUserFunc($callable) {
return $callable();
}
Because of the performance benefit (over using call_user_func_array()) several frameworks implement a similar "helper" method, allowing for a variable number of arguments. This other question/answer goes into more depth and covers some performance benchmarks: Calling a function with explicit parameters vs. call_user_func_array()
In case anyone is wondering, since PHP 7 we get immedietally invoked function expressions.
While this particular case is undocumented it actually works in the following example:
class Test {
private $func = "strtolower";
public function testFunc() {
return ($this->func)("ALPHABET");
}
}
$t = new Test();
echo $t->testFunc(); //echoes alphabet in PHP 7+ error in anything below
This can be seen in https://3v4l.org/JiuIF
<?php
$ar = (object) array('a'=>function(){
echo 'TEST';
});
$ar->a();
?>
I get this error Call to undefined method
Update:
If you are using PHP 5.3 or greater, take a look at other answers please :)
I don't think that's correct syntax, it would give you:
Parse error: syntax error, unexpected T_FUNCTION in....
You need to create a class, add method to it, use new keyword to instantiate it and then you will be able to do:
$ar->a();
class myclass
{
public function a()
{
echo 'TEST';
}
}
$ar = new myclass;
$ar->a(); // TEST
See Classes and Objects for more information.
Anonymous or not, you have a callback function, thus you need to handle it as such. E.g.:
<?php
$ar = (object) array(
'a' => function(){
echo 'TEST';
}
);
call_user_func($ar->a);
?>
For some reason it doesn't seem possibly to run the closure the way you do.
If you modify your code and set another variable to the function, it can be called:
$ar = (object) array('a'=>function(){
echo 'TEST';
});
$a = $ar->a;
$a();
This is no solution. But from what I can see, this seems like a bug or limitation in PHP 5.3.
I am using 5.3.5 when trying this.
There is no function a() but the property a, so you should call it by $ar->a.
Anyway I don't think it's going to work the way you expect it to.
EDIT:
As suggested by Álvaro G. Vicario you should use call_user_func, not echo to call the function and it will work correctly.
Or, just for the fun of it, you can do something like this -
<?php
$ar = new stdClass;
$ar->a = function($to_echo){ echo $to_echo; };
$temp = $ar->a;
//[Edit] - $ar->a("hello"); // doesn't work! php tries to match an instance method called "func" that is not defined in the original class' signature
$temp("Hey there");
call_user_func($ar->a("You still there?"));
?>
Working a lot with JS I have come to love closures, so I was pleased to learn that there are closures in PHP also. However I just can't get this stuff to work, what's wrong with this piece of code?
class Foo {
public $Bar;
public function Foo() {
$this->Bar = function() { echo "Hello World"; };
}
};
$F = new Foo();
$F->Bar();
I keep getting PHP Fatal error: Call to undefined method Foo::Bar() errors.
This has been discussed a lot on SO already (see e.g. this answer). This should do the trick:
$b = $f->Bar;
$b();
Yes, it is that stupid. You could use call_user_func() to put in in one line (see jlb's answer to this question), but the ugliness remains.
If you want a one-line solution to replace
$F->Bar()
try this:
call_user_func($F->Bar);
PHP has separation between methods and fields. In fact, you can have a method and a field of the same name at the same time:
class Foo {
public $Bar;
function Bar() { echo "hello\n"; }
};
$F = new Foo();
$F->Bar = 42;
$F->Bar(); // echoes "hello"
So you can see that, to avoid ambiguity, there must be a separate syntax between calling a method with that name, and accessing a field with that name and then calling that as a function.
If PHP had better syntax, they would support ($F->Bar)(), i.e. function call operator on any expression, but currently only variables can be "called".
PHP isn't liking the $F->Bar notation for accessing the closure.
If you change this slightly to
$t = $F->Bar();
$t();
then it works.