<?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?"));
?>
Related
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();
i got some trouble to understand scope in OOP. What i want is that $foo->test_item() prints "teststring"...Now it just fails with:
Warning: Missing argument 1 for testing::test_item()
Thanks a lot!
<?php
class testing {
public $vari = "teststring";
function test_item($vari){ //$this->vari doesn't work either
print $vari;
}
}
$foo = new testing();
$foo->test_item();
?>
test_item() should be:
function test_item() {
print $this->vari;
}
There is no need to pass $vari as a parameter.
Well, you've declared a method which expects an argument, which is missing. You should do:
$foo->test_item("Something");
As for the $this->, that goes inside of the class methods.
function test_item(){
print $this->vari;
}
function parameters can not be as "$this->var",
change your class like
class testing {
public $vari = "teststring";
function test_item(){ //$this->vari doesn't work either
print $this->vari;
}
}
$foo = new testing();
$foo->test_item();
And read this Object-Oriented PHP for Beginners
What's happening there is that $foo->test_item() is expecting something passed as an argument, so for example
$foo->test_item("Hello");
Would be correct in this case. This would print Hello
But, you may be wondering why it doesn't print teststring. This is because by calling
print $vari;
you are only printing the variable that has been passed to $foo->test_item()
However, if instead you do
function test_item(){ //notice I've removed the argument passed to test_item here...
print $this->vari;
}
You will instead be printing the value of the class property $vari. Use $this->... to call functions or variables within the scope of the class. If you try it without $this-> then PHP will look for that variable within the function's local scope
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.
i'm new to php and am wondering - is it possible to initialize a class with parameters?
like $obj = new myClass('myID');
i've tried but it gave me an error.
maybe someone can point me to some good tutorials.
thanks
Yes it is, you need to pass the variables through the constructor:
class SomeClass
{
function __construct($some_var)
{
}
}
Please note that in older versions of php the constructor needs to have the name of the class, it´s __construct() since php 5.
Yes, you need to use a class constructor.
Example:
<?php
class ClassWithArgs
{
function __construct($argument1, $argument2)
{
echo "arg 1 = $argument1\n";
echo "arg 2 = $argument2\n";
}
}
$object = new ClassWithArgs('one', 'two');
?>
Example Output
arg 1 = one
arg 2 = two
I suggest you also take a look at the PHP5 OOP documentation, it includes simple examples to get you going: http://php.net/manual/en/language.oop5.php
I have this:
one string variable which holds the class name ($classname)
one string variable with holds the property name ($propertyname)
I want to get that property from that class, the problem is, the property is static and I don't know how to do that.
If the property weren't static, it would have been:
$classname->$propertyname;
if the property were a method, I could have used call_user_function
call_user_func(array($classname, $propertyname));
But in my case, am I just lost. I am however hoping that it is possible. With the thousands of functions that PHP has, he'd better have something for this as well. Maybe I'm missing something?
Thanks!
Edit:
for those with eval() solutions: thanks, but it is out of the question
for those with get _class _vars() solutions: thanks, but it seems it returns "the default properties of the given class" (php.net), and yes, I would like that value to be changable (even though it does help me in some of the cases)
If you are using PHP 5.3.0 or greater, you can use the following:
$classname::$$propertyname;
Unfortunately, if you are using a version lower than 5.3.0, you are stuck using eval() (get_class_vars() will not work if the value is dynamic).
$value = eval($classname.'::$'.$propertyname.';');
EDIT: I've just said get_class_vars() wouldn't work if the value is dynamic, but apparently, variable static members are part of "the default properties of a class". You could use the following wrapper:
function get_user_prop($className, $property) {
if(!class_exists($className)) return null;
if(!property_exists($className, $property)) return null;
$vars = get_class_vars($className);
return $vars[$property];
}
class Foo { static $bar = 'Fizz'; }
echo get_user_prop('Foo', 'bar'); // echoes Fizz
Foo::$bar = 'Buzz';
echo get_user_prop('Foo', 'bar'); // echoes Buzz
Unfortunately, if you want to set the value of the variable, you will still need to use eval(), but with some validation in place, it's not so evil.
function set_user_prop($className, $property,$value) {
if(!class_exists($className)) return false;
if(!property_exists($className, $property)) return false;
/* Since I cannot trust the value of $value
* I am putting it in single quotes (I don't
* want its value to be evaled. Now it will
* just be parsed as a variable reference).
*/
eval($className.'::$'.$property.'=$value;');
return true;
}
class Foo { static $bar = 'Fizz'; }
echo get_user_prop('Foo', 'bar'); // echoes Fizz
set_user_prop('Foo', 'bar', 'Buzz');
echo get_user_prop('Foo', 'bar'); // echoes Buzz
set_user_prop() with this validation should be secure. If people start putting random things as $className and $property, it will exit out of the function as it won't be an existing class or property. As of $value, it is never actually parsed as code so whatever they put in there won't affect the script.
I think this is the simplest:
$foo = new ReflectionProperty('myClassName', 'myPropertyName');
print $foo->getValue();
To return a variable value that is set by a Static Variable you need to call:
$static_value = constant($classname.'::'.$propertyname);
Check out the documentation :: PHP Constant Documentation
You should be able to do something like:
eval("echo $classname::$propertyname;");
I just did a quick test and got this to work for me. Not sure if there's a better way or not, but I wasn't able to find one.
'eval' looks so close to 'evil', and I hate using it and/or seeing it in code. With a few ideas from other answers, here's a way to avoid it even if your php isn't 5.3 or higher.
Changed to reflect testing based on a comment.
class A {
static $foo = 'bar';
}
A::$foo = 'baz';
$a = new A;
$class = get_class($a);
$vars = get_class_vars($class);
echo $vars['foo'];
Outputs 'baz'.
One thing I noticed is that you can't set variables which are protected in static classes as the eval() command runs in a scope outside the class. The only thing to get around this would be to implement a static method inside the/every class which runs the eval(). This method could be protected as the call_user_func() [to call the setter method] also runs from inside the class.
Potentially relevant: discussion on late static binding in PHP - When would you need to use late static binding?.
get_class_vars is not same as get_object_vars.
I think get_clas_vars should return the original property values.
Even if for you said eval is out of the question, prior PHP 5.3 the easiest solution is still by using eval:
eval("\$propertyval = $classname::\$propertyname;");
echo $propertyval;
Getting and setting both static and non static properties without using Reflection
Using Reflection works but it is costly
Here is what I use for this purpose,
It works for PHP 5 >= 5.1.0 because I'm using property_exist
function getObjectProperty($object, $property)
{
if (property_exists(get_class($object), $property)) {
return array_key_exists($property, get_object_vars($object))
? $object->{$property}
: $object::$$property;
}
}
function setObjectProperty($object, $property, $value)
{
if (property_exists(get_class($object), $property)) {
array_key_exists($property, get_object_vars($object))
? $object->{$property} = $value
: $object::$$property = $value;
}
}
You can use ReflectionClass:
class foo
{
private static $bar = "something";
}
$class = "foo";
$reflector = new ReflectionClass($class);
$static_vars = $reflector->getStaticProperties();
var_dump($static_vars["bar"]);