How to access class members from an array of class variables? - php

I want to use PHP's reflection features to retrieve a list of parameter names from a method. I have a class like this:
class TestClass {
public function method($id, $person, $someotherparam) {
return;
}
}
I can get the list using code like this:
$r = new ReflectionClass('TestClass');
$methods = $r->getMethods();
foreach($methods as $method) {
$params = $method->getParameters();
$p = $params[0]; // how can I combine this and the next line?
echo $p->name;
I want to know how to access the class members from the array, so I don't have to do an assignment. Is this possible? I tried something like echo ($params[0])->name but I get an error.

you can replace these two lines :
$p = $params[0]; // how can I combine this and the next line?
echo $p->name;
by that single one :
echo $params[0]->name;
i.e. no need for any kind of parenthesis here.
But you cannot use this kind of syntax :
($params[0])->name
It'll give you a
Parse error: syntax error, unexpected T_OBJECT_OPERATOR

Related

Parse error: syntax error, unexpected 'new' (T_NEW) in .../test6_2.php on line 20

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().

error when using variable class name and static method

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();

dynamically retrieve object method

I try to dynamically retrieve a method of a class but php throws an exception which says Undefined property: stdClass ...
and How i try to get the values
private function getExactValue($row, $name)
{
$tempRow = clone $row;
foreach( explode('->', $name) as $key => $value)
{
$temp = $tempRow->{$value};
unset($tempRow);
$tempRow = $temp;
}
return $tempRow;
}
$row is an instance of an Object (not Std one)
$name is what i need in the Object to traverse , for example when i need $row->student->gifts->totalPoint() just pass the student->gifts->totalPoint() to the method for $name parameter
can you tell me what my mistake is?
I see what you are trying to do here. My first word of advice is that you are going about what you are trying to achieve in a very hackish way. If you wanted a better way to be able to execute arbitrary methods on an unknown object, I would suggest you look into PHP's reflection capabilities.
That being said, the problem with your code would appear to be that you are trying to execute a method via string, where what you need to do is utilize the method's name. What I would suggest is that within your loop where you explode the string on ->, you try to detect if it is a method or not, and then act accordingly. That could look like this:
foreach( explode('->', $name) as $value)
{
$value_trimmed = rtrim($value, '()');
if ($value === $value_trimmed) {
// this is a property
$tempRow = $tempRow->{$value};
} else {
// this is a method
$tempRow = $tempRow->{$value_trimmed}();
}
}
You should probably also do some validation on the input as well to make sure you have valid property/method names for each segment, as well as add validation that the entire string is indeed properly formed (i.e. you don't have things like foo->->bar(())). Of course this make no mention of how to handle array like foo[0]->bar() which you might also need to accommodate.

PHP Fatal Error: "Can't use method return value in write context in.... "

Trying to use a class that expects something like:
$client->firstname = 'bob';
$client->lastname = 'jones';
So I want to pass this data to the script in an array... where the keys and values are set elsewhere. I want to step through the array passing the key and value to the class. Trying to use this:
while($Val = current($CreateClientData)){
$client->key($CreateClientData) = $Val;
next($CreateClientData);
}
getting this:
Fatal error: Can't use method return value in write context in
blahblahpath on line 40.
Line 40 being: $client->key($CreateClientData) = $Val;
How can I do this?
If $client is already an instance of some class, and $CreateClientData is an array, then you probably wan to do something like this:
foreach($CreateClientData as $k => $v) {
$client->{$k} = $v;
}
This assumes of course that every key in the array is a valid member of the $client instance. If not, then you will have to do some additional checking before assigning the value, or you will have to wrap the assignment in a try / catch.
EDIT
The answer as to why your code doesn't work is because PHP doesn't allow for assignment of class properties to certain functions that return values. In your case, key($CreateClientData) returns a key. So you could alter your code and just add
$key = key($CreateClientData);
$client->$key = $Val;
But, the foreach loop is a lot cleaner anyway.
Why don't you use a foreach loop?
foreach($CreateClientData as $key => $val) {
$client->$key = $val;
}

PHP: Is code like this possible?

I'm trying to have a user-defined list of game-maps. Because I don't know how many maps will be in the array at design time, I'm trying to dynamically create new variables to contain them. Is this even possible? Here's my failed attempt:
<?php
$maplist=array("map1.aamap.xml","map2.aamap.xml"); //edit this list with your maps
$rounds = 3; //times to play each map
/*======No need to edit below========*/
global $last; //store the last played map
class Map
{
public $difficulty;
public $played; //amount of times played
}
foreach($maplist as $i => $element)
{
$element = $map[$i];
$map[$i] = new Map();
}
//snipped other code here
$map[$i]->$played = $x++; //increment the times played counter <-- FAILS HERE
?>
Parser says: Fatal error: Cannot access empty property
Is something like this even feasible in this manner?
There are some errors in your code:
<?php
$maplist=array("map1.aamap.xml","map2.aamap.xml"); //edit this list with your maps
$rounds = 3; //times to play each map
/*======No need to edit below========*/
global $last; //store the last played map
Since you are on the global scope here, not inside a function, there is no need for global.
class Map
{
public $difficulty;
public $played; //amount of times played
}
foreach($maplist as $i => $element)
{
$element = $map[$i];
Is some code missing here? You are not using $element within the loop, so this assignment is not needed.
$map[$i] = new Map();
}
//snipped other code here
$map[$i]->$played = $x++; //increment the times played counter <-- FAILS HERE
The syntax to access a member variable is $object->variable, not $object->$variable. The latter one will evaluate $variable and use the value as variable name (E.g., if $variable = "foo", this will try to access $object->foo).
Use $map[$i]->played = $x++; instead.
When accessing the properties of a class, you don't want to use the $ in front of the property name itself.
Replace $map[$i]->$played = $x++; with $map[$i]->played = $x++; to solve the Fatal error: Cannot access empty property error.
You could override the magic methods to provide dynamic properties if you wish:
public function __get($name)
{
...
}
public function __set($name, $value)
{
...
}
http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.members
Within each of these functions you could store the data in some internal array structure.
You don't have to use the $ when accessing properties of an instance. Simple use $map[$i]->played. Have a look on the OOP basics.

Categories