I have trouble dynamically declaring variables inside a class/object in PHP.
I have a class called Column and it receives an associative array of (names => values) of an unknown length.
I need the class variables to have the exact same name as in the array (and their values to match obviously).
Since Variable Variables method is a bit confusing, when you add on top of it the class/object declaration syntax, I feel I lost myself in it a bit.
I tried something like this:
function __construct($array)
{
foreach ($array as $key => $value)
{
$this->$key;
$this->key=$value;
}
}
i would usually not do this
$this->$key;
I thought $this->key would fit the syntax,but apparently I was wrong. If someone could help correct me it would very helpful.
Just use the {} syntax:
function __construct($array)
{
foreach ($array as $key => $value)
{
$this->{$key} = $value;
}
}
Instead of
$this->$key;
$this->key=$value;
It should be
$this->$key=$value;
What's the difference?
The variable property $this->$key; as single statement accesses the property with the name in $key but does not do anything with it. But it will trigger a notice Undefined property if the property has not been declared or dynamically assigned before.
$this->key accesses the literal key property, that is public $key; if it has been declared explicitly.
$this->$key accesses the property with the name stored in $key. So if $key === 'foo' it is the same as $this->foo.
Assigning properties dynamically that have not been declared before is independent of using variable properties. So if the property $foo does not exist, $this->foo = 1 is the same as $this->$key = 1 with $key === 'foo'. Both create a public property $foo on the current object.
Special cases
If $key is not a string, it will be casted to string. If it is an object or resource that cannot be casted to string, you will get a could not be converted to string error.
If $key converts to an empty string, you will get a Cannot access empty property error.
If $key starts with a number or contains special characters that are usually not allowed in variable names (like $), the property will be created anyway. Accessing properties with names like this is always possible if you use {} to use arbitrary expressions as property names. Try this:
$o = new stdclass;
$o->{'!"§$%'} = 'it works';
echo $o->{'!"§$%'};
Related
Is it possible to access enumerations properties dynamically?
Here is what I tried and the error I got.
Access to undeclared static property ExampleEnum::$id
enum ExampleEnum
{
case _1;
case _2;
public function getIt(): string
{
return match ($this) {
ExampleEnum::_1 => 'foo',
ExampleEnum::_2 => 'bar',
};
}
}
$id = "_1";
ExampleEnum::$id->getIt();
It's important to distinguish between three different things here:
A class property would be declared in a class as static $foo (with optional visibility, type, and default value), and accessed as Example::$foo. Dynamically, you could access that with "variable-variable" syntax, e.g. $name = 'foo'; echo Example::$$name;.
A class constant would be declared as const foo = 'value' (with optional visibility), and accessed as Example::foo. There is no direct syntax for accessing it directly, but you can use the constant function, as in $name = 'foo'; echo constant("Example::$name");
An enum case is declared as case foo (with a value if using a "backed enum"), and it is accessed using the same syntax as a class constant.
In fact, it is treated like a constant in many ways, and a test shows that the constant function can actually be used to look one up, so this will work:
enum ExampleEnum
{
case _1;
case _2;
public function getIt(): string
{
return match ($this) {
ExampleEnum::_1 => 'foo',
ExampleEnum::_2 => 'bar',
};
}
}
$id = "_1";
echo constant("ExampleEnum::$id")->getIt();
Note that if you use a "backed enumeration", you can associate an arbitrary integer or string with each case, separate from its name, and use the from method to look up a case based on that value.
class User{
protected $dates =[
'created'
];
public function __construct(){
foreach( $this->dates as $date){
$property = $this->{$date};
$this->{$date} = new DateTime($property);
}
}
}
1) Is using "this" with "date" variable in the foreach loop inside a class specific to php or a general oops concept?
2) why do we need curly braces with "this" can't we simply write $this->date ?
$this->{$date} is a variable variable. It uses the value of $date as the name of a property to access. So when $date = "created" (as it is when iterating through the $this->dates property), it's equivalent to $this->created.
You don't need the curly braces if the expression is just a variable name, you can write $this->$date; but if it's a more complex expresion you need the braces, e.g. $this->{$date . "_field"} would be equivalent to$this->created_field. But many programmers use the braces consistently, just to make the code clearer and cause a warning if they forget the$`.
You need the $ to make it use a variable as the property name. If you just write $this->date it looks for the date property, not the created property.
Using dynamic property names like this is available in many scripting languages; for instance, you can do it in Javascript with this[date]. It's not generally available in statically-typed languages like C++.
$this->{$date} , assuming your date is '2018-08-13', for example, you're trying to acess $this->2018-08-13.
I think what you want is
foreach($this->dates as $date){
//DO SOMETHING LIKE INITIATE THE OBJ
$obj->date = date("Y-m-d H:i:s"); //If you want current time
// OR
$obj->date = $date; //For the value on $date
}
Class properties may also be accessed using variable property names. The variable property name will be resolved within the scope from which the call is made. For instance, if you have an expression such as $foo->$bar, then the local scope will be examined for $bar and its value will be used as the name of the property of $foo.
For Example:
<?php
class SimpleClass
{
// property declaration
public $var = 'a default value';
// method declaration
public function displayVar() {
echo $this->var;
}
}
?>
$this->var is used when you have actual property declared in class ($var above)
whereas $this->$date in your case will be used when you are not declaring property in the class and would like to still use it has a class property...
In order to use $this->dates you will need to declare a class variable like
class {
public $dates;
public function __construct($d){
$this->dates = $d;
}
}
$this->{$date} will be interpreted as $this->created
class RouteCollection implements \IteratorAggregate, \Countable
{
/**
* #var Route[]
*/
private $routes = array();
public function add($name, Route $route)
{
unset($this->routes[$name]);
$this->routes[$name] = $route;
}
public function remove($name)
{
foreach ((array) $name as $n) {
unset($this->routes[$n]);
}
}
}
This is a piece of code from the class Symfony\Component\Routing\RouteCollection. Does unset before the assignment matter?
Why is it done?
Second question: Why in remove method simple string is parsed to array?
Why I can't use simply:
unset($this->routes[$name]);
Same as in add method?
Does unset before the assignment matter?
It can. If $this->routes[$name] is a PHP reference and you don't use unset, all symbols pointing to the underlying value will point to the new value. If you use unset before, the assignment will only affect the symbol used.
Second question: Why in remove method simple string is parsed to array?
This is just a small trick that allows you to use the remove method with both strings and array. When you cast a string (e.g. 'abc') to an array, PHP will return an array that contains the string as its only value (array(0 => 'abc')). For strings the method works as you suggested, and for arrays it will unset all names in the array.
How do I know if an arbitrary object has any properties in PHP?
I need it for a recursive search on JSON objects as a break condition
i.e break search when the object has no more sub-objects.
I thought of property_exists but it checks a particular property, while I want to know if any property exists.
You can use a foreach loop:
foreach (new object as $prop => $value) {
echo "property \$$prop is $value\n";
}
Also You can do it conveniently with get_object_vars:
$propertyName = key(get_object_vars($object));
The function get_object_vars() will return a list of all accessible properties on an object.
You can try to use this function:
http://php.net/manual/en/function.get-object-vars.php
From the docs:
Returns an associative array of defined object accessible non-static properties for the specified object in scope. If a property has not been assigned a value, it will be returned with a NULL value.
You can also use the ReflectionClass to get the object properties like this:
$obj = new YourObjectClass;
$reflect = new ReflectionClass($obj);
$props = $reflect->getProperties();
foreach ($props as $prop) {
print $prop->getName() . "\n";
Casting the object to an array and performing a count on the resulting array will tell you if an object has properties.
$foo = new Bah();
$propertiesAsArray = (array) $foo;
if(count($propertiesAsArray)) {
//this object has properties
} else {
//this object does not have properties
}
You could use :
if(isset($yourobject)){
//YourCode
}
in a loop to see if the object have anything already set.
I have a class with several variables like:
class ABC
{
$var1=0;
$var2=0;
...
}
Instead of setting variables one by one like;
$ABC=new ABC();
$ABC->var1=1;
$ABC->var2=1;
...
How to loop through all class' (instance) variables and dynamically set them all to some value.
You could use get_object_vars to get the non static properties of the object, and then loop through that.
$object_vars = get_object_vars($ABC);
foreach ($object_vars as $name => $value) {
$ABC->{$name} = $newVal;
}
See more information here: http://php.net/manual/en/function.get-object-vars.php