Initialize Objects like arrays in PHP? - php

In PHP, you can initialize arrays with values quickly using the following notation:
$array = array("name" => "member 1", array("name" => "member 1.1") ) ....
is there any way to do this for STDClass objects?
I don't know any shorter way than the dreary
$object = new STDClass();
$object->member1 = "hello, I'm 1";
$object->member1->member1 = "hello, I'm 1.1";
$object->member2 = "hello, I'm 2";

You can use type casting:
$object = (object) array("name" => "member 1", array("name" => "member 1.1") );

I also up-voted Gumbo as the preferred solution but what he suggested is not exactly what was asked, which may lead to some confusion as to why member1o looks more like a member1a.
To ensure this is clear now, the two ways (now 3 ways since 5.4) to produce the same stdClass in php.
As per the question's long or manual approach:
$object = new stdClass;
$object->member1 = "hello, I'm 1";
$object->member1o = new stdClass;
$object->member1o->member1 = "hello, I'm 1o.1";
$object->member2 = "hello, I'm 2";
The shorter or single line version (expanded here for clarity) to cast an object from an array, ala Gumbo's suggestion.
$object = (object)array(
'member1' => "hello, I'm 1",
'member1o' => (object)array(
'member1' => "hello, I'm 1o.1",
),
'member2' => "hello, I'm 2",
);
PHP 5.4+ Shortened array declaration style
$object = (object)[
'member1' => "hello, I'm 1",
'member1o' => (object)['member1' => "hello, I'm 1o.1"],
'member2' => "hello, I'm 2",
];
Will both produce exactly the same result:
stdClass Object
(
[member1] => hello, I'm 1
[member1o] => stdClass Object
(
[member1] => hello, I'm 1o.1
)
[member2] => hello, I'm 2
)
nJoy!

From a (post) showing both type casting and using a recursive function to convert single and multi-dimensional arrays to a standard object:
<?php
function arrayToObject($array) {
if (!is_array($array)) {
return $array;
}
$object = new stdClass();
if (is_array($array) && count($array) > 0) {
foreach ($array as $name=>$value) {
$name = strtolower(trim($name));
if (!empty($name)) {
$object->$name = arrayToObject($value);
}
}
return $object;
}
else {
return FALSE;
}
}
Essentially you construct a function that accepts an $array and iterates over all its keys and values. It assigns the values to class properties using the keys.
If a value is an array, you call the function again (recursively), and assign its output as the value.
The example function above does exactly that; however, the logic is probably ordered a bit differently than you'd naturally think about the process.

You can use :
$object = (object)[]; // shorter version of (object)array();
$object->foo = 'bar';

I use a class I name Dict:
class Dict {
public function __construct($values = array()) {
foreach($values as $k => $v) {
$this->{$k} = $v;
}
}
}
It also has functions for merging with other objects and arrays, but that's kinda out of the scope of this question.

You could try:
function initStdClass($thing) {
if (is_array($thing)) {
return (object) array_map(__FUNCTION__, $thing);
}
return $thing;
}

from this answer to a similar question:
As of PHP7, we have Anonymous Classes which would allow you to extend a class at runtime, including setting of additional properties:
$a = new class() extends MyObject {
public $property1 = 1;
public $property2 = 2;
};
echo $a->property1; // prints 1
It's not as succinct as the initializer for array. Not sure if I'd use it. But it is another option you can consider.

Another option for deep conversion is to use json_encode + json_decode (it decodes to stdClass by default). This way you won't have to repeat (object) cast in each nested object.
$object = json_decode(json_encode(array(
'member1' => "hello, I'm 1",
'member1o' => array(
'member1' => "hello, I'm 1o.1",
),
'member2' => "hello, I'm 2",
)));
output:
php > print_r($object);
stdClass Object
(
[member1] => hello, I'm 1
[member1o] => stdClass Object
(
[member1] => hello, I'm 1o.1
)
[member2] => hello, I'm 2
)

Related

PHP object loaded as reference in foreach loop

I am looping through an object and i try to duplicate one of the items while changing one of it's variables.
But when i copy the original and then change the title in the new one, the old one changes along with it. Which it shouldn't, since i did not initialised it as a reference.
$calendar = array(
(object)[
'id' => 1,
'title' => 'original 1',
],
(object)[
'id' => 2,
'title' => 'original 2',
],
(object)[
'id' => 3,
'title' => 'original 3',
],
);
foreach ($calendar AS $key => $item){
if($item->id == 2){
$item->title = 'new 2';
array_splice($calendar, $key, 0, [1]);
$calendar[$key] = $item;
}
}
echo "<pre>";
print_r($calendar);
die();
I would expect the output of this to keep original 2 intact. But it changes it along with it.
(
[0] => stdClass Object
(
[id] => 1
[title] => original 1
)
[1] => stdClass Object
(
[id] => 2
[title] => new 2
)
[2] => stdClass Object
(
[id] => 2
[title] => new 2
)
[3] => stdClass Object
(
[id] => 3
[title] => original 3
)
)
Even if i make a new object and use that one to make the changes, it still changes the orignial.
foreach ($calendar AS $key => $item){
if($item->id == 2){
$new_item = $item;
$new_item->title = 'new 2';
array_splice($calendar, $key, 0, [1]);
$calendar[$key] = $new_item;
}
}
Now i could probably fix this by just making a new object from scratch and copy the values one by one in it. But where's the fun in that?
So my question is...Why does this happen? Even though i didn't cast $item as &$item
Assignment or clone ?
Because, you're using objects, the problem is that $new_item = $item; doesn't create a new object, it creates a new reference of $item, named $new_item.
In the following example, $a and $b are the same object:
$a = new stdclass;
$b = $a;
var_dump($a, $b);
Output is:
object(stdClass)#1 (0) {...} // same object #1
object(stdClass)#1 (0) {...} // same object #1
Clone
You could use the keyword clone to create a new instance:
$a = new stdclass;
$b = clone $a; // Clone the object
var_dump($a, $b);
Output:
object(stdClass)#1 (0) {...} // object #1
object(stdClass)#2 (0) {...} // new object #2
So, in your case, you could use:
if ($item->id == 2) {
$clone = clone $item; // << Create a COPY of $item
$clone->title = 'new 2'; // Update the copy, not the reference
$calendar[$key] = $clone; // Add this copy to final array
// ...
}
A note about parameters
When you're using objects as parameters for some functions, objects are reference, so, the given object can be updated in that function. Here is a simple example (demo):
function updateObject(object $object): void {
$object->newProperty = true;
}
$obj = new stdClass;
var_dump($obj);
updateObject($obj);
var_dump($obj);
The code above gives the following (condensed) output:
object(stdClass)#1 (0) { }
object(stdClass)#1 (1) { ["newProperty"]=> bool(true) }
Further reading : Objects and references
As simple PHP Object assignment does not create a new object. It simply creates a new pointer to the same object.
I think you want to use the clone keyword:
foreach ($calendar AS $key => $item){
if($item->id == 2){
$new_item = clone $item;
$new_item->title = 'new 2';
array_splice($calendar, $key, 0, [1]);
$calendar[$key] = $new_item;
}
}

PHP: Updating an associative array though a class function?

I want to be able to update an associative array within an object based on function input, but I'm at a loss for how to do this. Here's my problem. Let's say there's this data container in my object:
private $vars = Array
(
['user_info'] = Array
(
['name'] => 'John Doe'
['id'] => 46338945
['email'] => 'johndoe#example.com'
['age'] => 35
)
['session_info'] = Array
(
['name'] => 'session_name'
['id'] => 'mGh44Jf0nfNNFmm'
)
)
and I have a public function update to change these values:
public function update($keys, $changeValueTo) {
if (!is_array($keys)) {
$keys = array($keys);
}
nowWhat();
}
Ultimately, I just want to be able to convert something like this
array('user_info', 'name')
into this:
$this->vars['user_info']['name']
so I can set it equal to the $equalTo parameter.
This usually wouldn't be a problem, but in this scenario, I don't know the schema of the $vars array so I can't write a foreach statement based on a fixed number of keys. I also can't just make $vars public, because the function needs to do something within the object every time something is changed.
I'm worried that this is a recursive scenario that will involve resorting to eval(). What would you recommend?
It is not hard to do it. You need passing variable by reference and a loop to achieve. No need eval().
$var = array(
"user_info" => array(
"name" => "Visal"
)
);
function update(&$var, $key, $value) {
// assuming the $key is an array
$t = &$var;
foreach ($key as $v) {
$t = &$t[$v];
}
$t = $value;
}
update($var, array("user_info", "name"), "Hello World");
var_dump($var);

Using an array as a default parameter in a PHP function

Is it possible to use an array as a default parameter in a PHP function?
I would like to do the following:
$arr = array(1,2,3,4);
function sample($var1, $var2, $var3 = $arr){
echo $var1.$var2;
print_r($var3);
}
sample('a','b');
// Should still work without the third parameter and default to $arr
No, this is not possible, the right hand expression of the default value must be a constant or array literal, i.e.
function sample($var1, $var2, $var3 = array(1, 2, 3, 4))
{
}
If you want this behaviour, you could use a closure:
$arr = array(1, 2, 3, 4);
$sample = function ($var1, $var2, array $var3 = null) use ($arr) {
if (is_null($var3)) {
$var3 = $arr;
}
// your code
}
$sample('a', 'b');
You could also express it with a class:
class Foo
{
private static $arr = array(1, 2, 3, 4);
public static function bar($var1, $var2, array $var3 = null)
{
if (is_null($var3)) {
$var3 = self::$arr;
}
// your code here
}
}
Foo::bar('a', 'b');
You can't pass $arr into the function definition, you'll have to do:
function sample($var1, $var2, $var3 = array('test')){
echo $var1.$var2;
echo print_r($var3);
}
sample('a','b'); // output: abArray ( [0] => test ) 1
or, if you want to be really dirty (I wouldn't recommend it..):
$arr = array('test');
function sample($var1, $var2, $var3 = null){
if($var3 == null){
global $arr;
$var3 = $arr;
}
echo $var1.$var2;
echo print_r($var3);
}
sample('a','b');
(It might not be a complete answer, but it covers some useful cases.)
If you want to get one or more options using an array as an argument in a function (or a method), setting a default set of options might not help. Instead, you can use array_replace().
For example, let's consider a sample $options argument which gets an array with two keys, count and title. Setting a default value for that argument leads overriding it when using the function with any custom $option value passed. In the example, if we set $options to have only one count key, then the title key will be removed. One of the right solutions is the following:
function someCoolFunc($options = []) {
$options = array_replace([
"count" => 144,
"title" => "test"
], $options);
// ...
}
In the example above, you will be ensured that count and title indexes are present, even if the user supplies an empty array (keep in mind, the order of the arguments in array_replace() function is important).
Note: In the explained case, using a class (or interface) is also an option, but one reason to choose arrays over it might be simplicity (or even performance).
I tried the last example above. Here was my comparable test:
function someFunc($options = [])
{
$options = array_replace([
"<br>", "<b>", "<i>", "<u>", "<hr>", "<span>"
], $options);
print_r($options);
}
here is the result:
>>> somefunc()
Array
(
[0] => <br>
[1] => <b>
[2] => <i>
[3] => <u>
[4] => <hr>
[5] => <span>
)
=> null
Yet looks what happens when you try to add a tag. Notice what happens to the original values. Element [0] is changed. The array is not added to:
>>> someFunc(["<div>"])
Array
(
[0] => <div>
[1] => <b>
[2] => <i>
[3] => <u>
[4] => <hr>
[5] => <span>
)
=> null
This would allow you to add an element to default option:
function someFunc($options = array())
{
array_push($options, "<br>", "<b>", "<i>", "<u>", "<hr>", "<span>");
return $options;
}
Here is what results:
>>> someFunc()
=> [
"<br>",
"<b>",
"<i>",
"<u>",
"<hr>",
"<span>",
]
---
someFunc(["<div>","<table>"]);
=> [
"<div>",
"<table>",
"<br>",
"<b>",
"<i>",
"<u>",
"<hr>",
"<span>",
]
this way, the default values get added to.

Removing object from array; how to avoid nulls

I have an array that is a object which I carry in session lifeFleetSelectedTrucksList
I also have objects of class fleetUnit
class fleetUnit {
public $idgps_unit = null;
public $serial = null;
}
class lifeFleetSelectedTrucksList {
public $arrayList = array();
}
$listOfTrucks = new lifeFleetSelectedTrucksList(); //this is the array that I carry in session
if (!isset($_SESSION['lifeFleetSelectedTrucksList'])) {
$_SESSION['lifeFleetSelectedTrucksList'] == null; //null the session and add new list to it.
} else {
$listOfTrucks = $_SESSION['lifeFleetSelectedTrucksList'];
}
I use this to remove element from array:
$listOfTrucks = removeElement($listOfTrucks, $serial);
And this is my function that removes the element and returns the array without the element:
function removeElement($listOfTrucks, $remove) {
for ($i = 0; $i < count($listOfTrucks->arrayList); $i++) {
$unit = new fleetUnit();
$unit = $listOfTrucks->arrayList[$i];
if ($unit->serial == $remove) {
unset($listOfTrucks->arrayList[$i]);
break;
} elseif ($unit->serial == '') {
unset($listOfTrucks->arrayList[$i]);
}
}
return $listOfTrucks;
}
Well, it works- element gets removed, but I have array that has bunch of null vaues instead. How do I return the array that contains no null elements? Seems that I am not suing something right.
I think what you mean is that the array keys are not continuous anymore. An array does not have "null values" in PHP, unless you set a value to null.
$array = array('foo', 'bar', 'baz');
// array(0 => 'foo', 1 => 'bar', 2 => 'baz');
unset($array[1]);
// array(0 => 'foo', 2 => 'baz');
Two approaches to this:
Loop over the array using foreach, not a "manual" for loop, then it won't matter what the keys are.
Reset the keys with array_values.
Also, removing trucks from the list should really be a method of $listOfTrucks, like $listOfTrucks->remove($remove). You're already using objects, use them to their full potential!
You can use array_filter
<?php
$entry = array(
0 => 'foo',
1 => false,
2 => -1,
3 => null,
4 => ''
);
print_r(array_filter($entry));
?>
output:
Array
(
[0] => foo
[2] => -1
)

Extended addslashes function in PHP

Hi can somebody help me with building an extended addslashes function, which will work with mixed combination of objects and arrays. For example i have this Object:
$object = new stdClass;
$object2 = new stdClass;
$object2->one = "st'r2";
$object3 = new stdClass;
$object3->one = "st'r3";
$object->one = "s'tr";
$object->two = array($object2);
$object->obj = $object3;
And i would like to get this object back escaped and with the same structure.
I have started some experiments and i get something like this:
function addslashes_extended($arr_r){
if(is_array($arr_r)){
foreach ($arr_r as $key => $val){
is_array($val) ? addslashes_extended($val):$arr_r[$key]=addslashes($val);
}
unset($val);
}else if(is_object($arr_r)){
$objectProperties = get_object_vars($arr_r);
foreach($objectProperties as $key => $value){
is_object($value) ? addslashes_extended($value):$arr_r->{$key}=addslashes($value);
}
}
return $arr_r;
}
But this is not going to work, i have to work with passing by reference i think, but i have no clue how, other solutions would be nice to have too, thanks in advance!
Try this (using array_walk):
error_reporting(E_ALL ^ E_STRICT);
ini_set('display_errors', 'on');
$data = array(
"fo'o",
'bar' => "foo'bar",
'foobar' => array(
1, 2, 'someObj' => json_decode('{"prop1": "a", "prop2": "b\'c"}')
)
);
class Util
{
public static function addslashes_extended(&$mixed) {
if (is_array($mixed) || is_object($mixed)) {
array_walk($mixed, 'Util::addslashes_extended');
}
elseif (is_string($mixed)) {
$mixed = addslashes($mixed);
}
}
}
Util::addslashes_extended($data);
print_r($data);
Output ( http://codepad.org/nUUYKWrn ):
Array
(
[0] => fo\'o
[bar] => foo\'bar
[foobar] => Array
(
[0] => 1
[1] => 2
[someObj] => stdClass Object
(
[prop1] => a
[prop2] => b\'c
)
)
)
To pass by reference, you use & before the variable name, quick example:
function inc(&$var) {
$var++;
}
$x = 5;
inc($x);
echo $x; //Prints: 6

Categories