Spl, ArrayObject, ArrayObject::STD_PROP_LIST - php

I'm trying to understand STD_PROP_LIST constant in the documentation but so far i didn´t understand it, and didn´t found any explanation :(
The documentation has the following example:
$a = new ArrayObject(array(), ArrayObject::STD_PROP_LIST);
$a['arr'] = 'array data';
$a->prop = 'prop data';
$b = new ArrayObject();
$b['arr'] = 'array data';
$b->prop = 'prop data';
// ArrayObject Object
// (
// [prop] => prop data
// )
print_r($a);
// ArrayObject Object
// (
// [arr] => array data
// )
print_r($b);
Both prints give me the same exact result:
ArrayObject Object ( [prop] => prop data [storage:ArrayObject:private] => Array ( [arr] => array data ) )
ArrayObject Object ( [prop] => prop data [storage:ArrayObject:private] => Array ( [arr] => array data ) )
Anyone could help me understanding what is the difference between using this constant or not?
Thanks in advance!

The ArrayObject and ArrayIterator are 2 classes that are really similar. They actually both share lot of code internally inside the php core. These two classes have a internal array to store the elements you set to those classes.
The STD_PROP_LIST tells us how to read, and ARRAY_AS_PROPS tells us how we to write those elements. First of all,setting elements through the standard array ([]) notation will always work the same way, regardless of these settings.
When setting ARRAY_AS_PROPS flags, it means that when you set properties (through the ->), will not be set on the object like you would expect with regular objects, but will be stored as internal elements. If this flag is NOT set, it will store the property onto the actual array-object or array-iterator, which is what you see in the code output from your example: the "prop => propdata" is not inside the storage:ArrayObject:private, which would have been the case if the ARRAY_AS_PROPS flag would have been set:
$a = new ArrayObject();
$a['arr'] = 'array data';
$a->prop = 'prop data';
$b = new ArrayObject(array(), ArrayObject::ARRAY_AS_PROPS);
$b['arr'] = 'array data';
$b->prop = 'prop data';
print_r($a);
print_r($b);
// Output:
ArrayObject Object
(
[prop] => prop data
[storage:ArrayObject:private] => Array
(
[arr] => array data
)
)
ArrayObject Object
(
[storage:ArrayObject:private] => Array
(
[arr] => array data
[prop] => prop data
)
)
The STD_PROP_LIST decides on what to return on certain conditions, most notably at var_dump(). Though there will be other cases, i haven't found them myself. If the STD_PROP_LIST is set, it will return the properties that have been set onto your ArrayObject, or ArrayIterator class. If it's NOT set, then var_dump() will return a list of the internal elements that have been stored.
The actual documentation is not 100% correct on STD_PROP_LIST. This flag affects var_dump(), but not foreach(). When using foreach(), it will always iterate the internal elements, and never the actual properties, even when STD_PROP_LIST has been set.
These two flags are not mutually exclusive: you can set both flags, but it wouldn't make much sense doing so: it means that properties are always added as internal elements (ARRAY_AS_PROPS), and we want to return the standard properties through var_dump (STD_PROP_LIST). Since properties cannot have been set, it will always return an empty list in that case.

A great answer by #JayTaph but print_r is more like a debug function. To actually use the arrays in for instance a foreach it becomes clear that the both differ significantly:
$a = new ArrayObject();
$a['arr'] = 'array data';
$a->prop = 'prop data';
$b = new ArrayObject(array(), ArrayObject::ARRAY_AS_PROPS);
$b['arr'] = 'array data';
$b->prop = 'prop data';
echo "\$a:<br>\n";
foreach( $a as $key=> $value) {
printf( "[%s] : %s<br>\n", $key, $value);
}
echo "\$b:<br>\n";
foreach ($b as $key => $value) {
printf("[%s] : %s<br>\n", $key, $value);
}
will output:
$a:
[arr] : array data
$b:
[arr] : array data
[prop] : prop data

Related

Move array element by associative key to the beginning of an array

So far all my research has shown that this cannot be achieved without writing lengthy functions such as the solution here
Surely there is a simpler way of achieving this using the predefined PHP functions?
Just to be clear, I am trying to do the following:
$test = array(
'bla' => 123,
'bla2' => 1234,
'bla3' => 12345
);
// Call some cool function here and return the array where the
// the element with key 'bla2' has been shifted to the beginning like so
print_r($test);
// Prints bla2=1234, bla=>123 etc...
I have looked at using the following functions but have so far have not been able to write a solution myself.
array_unshift
array_merge
To Summarize
I would like to:
Move an element to the beginning of an array
... whilst maintaining the associative array keys
This seems, funny, to me. But here ya go:
$test = array(
'bla' => 123,
'bla2' => 1234,
'bla3' => 12345
);
//store value of key we want to move
$tmp = $test['bla2'];
//now remove this from the original array
unset($test['bla2']);
//then create a new array with the requested index at the beginning
$new = array_merge(array('bla2' => $tmp), $test);
print_r($new);
Output looks like:
Array
(
[bla2] => 1234
[bla] => 123
[bla3] => 12345
)
You could turn this into a simple function that takes-in a key and an array, then outputs the newly sorted array.
UPDATE
I'm not sure why I didn't default to using uksort, but you can do this a bit cleaner:
$test = array(
'bla' => 123,
'bla2' => 1234,
'bla3' => 12345
);
//create a function to handle sorting by keys
function sortStuff($a, $b) {
if ($a === 'bla2') {
return -1;
}
return 1;
}
//sort by keys using user-defined function
uksort($test, 'sortStuff');
print_r($test);
This returns the same output as the code above.
This isn't strictly the answer to Ben's question (is that bad?) - but this is optimised for bringing a list of items to the top of the list.
/**
* Moves any values that exist in the crumb array to the top of values
* #param $values array of options with id as key
* #param $crumbs array of crumbs with id as key
* #return array
* #fixme - need to move to crumb Class
*/
public static function crumbsToTop($values, $crumbs) {
$top = array();
foreach ($crumbs AS $key => $crumb) {
if (isset($values[$key])) {
$top[$key] = $values[$key];
unset($values[$key]);
}
}
return $top + $values;
}

Converting to object an indexed array [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Casting an Array with Numeric Keys as an Object
I was wondering about (object) type casting.
It's possible to do a lot of useful things, like converting an associative array to an object, and some not so useful and a bit funny (IMHO) things, like converting a scalar value to object.
But how can I access the result of casting of an indexed array?
// Converting to object an indexed array
$obj = (object) array( 'apple', 'fruit' );
How about accessing a specific value?
print $obj[0]; // Fatal error & doesn't have and any sense
print $obj->scalar[0]; // Any sense
print $obj->0; // Syntax error
print $obj->${'0'}; // Fatal error: empty property.
print_r( get_object_vars( $obj ) ); // Returns Array()
print_r( $obj ); /* Returns
stdClass Object
(
[0] => apple
[1] => fruit
)
*/
The following works because stdClass implements dynamically Countable and ArrayAccess:
foreach( $obj as $k => $v ) {
print $k . ' => ' . $v . PHP_EOL;
}
This is actually a reported bug.
It has been deemed as "too expensive to fix" and the resolution has
been "updated the documentation to describe this useless quirk, so it
is now officially correct behavior" [1].
However, there are some workarounds.
As get_object_vars gives you nothing, only thing you can do is:
You can iterate on the stdClass using foreach
You can cast it back as array.
You can change cast it to object using json_decode+json_encode (this is dirty trick)
Example 1.:
$obj = (object) array( 'apple', 'fruit' );
foreach($obj as $key => $value) { ...
Example 2.:
$obj = (object) array( 'apple', 'fruit' );
$array = (array) $obj;
echo $array[0];
Example 3.:
$obj = (object) array( 'apple', 'fruit' );
$obj = json_decode(json_encode($obj));
echo $obj->{'0'};
var_dump(get_object_vars($obj)); // array(2) {[0]=>string(5) "apple"[1]=>string(5)"fruit"}
This is why you shouldn't cast non-associative array as object :)
But if you want to, do it in this way:
// PHP 5.3.0 and higher
$obj = json_decode(json_encode(array('apple', 'fruit'), JSON_FORCE_OBJECT));
// PHP 5 >= 5.2.0
$obj = json_decode(json_encode((Object) array('apple', 'fruit')));
instead of
$obj = (Object) array('apple','fruit');

how to convert multidimensional array to object in php?

i have a multidimensional array:
$image_path = array('sm'=>$sm,'lg'=>$lg,'secondary'=>$sec_image);
witch looks like this:
[_media_path:protected] => Array
(
[main_thumb] => http://example.com/e4150.jpg
[main_large] => http://example.com/e4150.jpg
[secondary] => Array
(
[0] => http://example.com/e4150.jpg
[1] => http://example.com/e4150.jpg
[2] => http://example.com/e9243.jpg
[3] => http://example.com/e9244.jpg
)
)
and i would like to convert it into an object and retain the key names.
Any ideas?
Thanks
edit: $obj = (object)$image_path; doesn't seem to work. i need a different way of looping through the array and creating a object
A quick way to do this is:
$obj = json_decode(json_encode($array));
Explanation
json_encode($array) will convert the entire multi-dimensional array to a JSON string. (php.net/json_encode)
json_decode($string) will convert the JSON string to a stdClass object. If you pass in TRUE as a second argument to json_decode, you'll get an associative array back. (php.net/json_decode)
I don't think the performance here vs recursively going through the array and converting everything is very noticeable, although I'd like to see some benchmarks of this. It works, and it's not going to go away.
The best way would be to manage your data structure as an object from the start if you have the ability:
$a = (object) array( ... ); $a->prop = $value; //and so on
But the quickest way would be the approach supplied by #CharlieS, using json_decode(json_encode($a)).
You could also run the array through a recursive function to accomplish the same. I have not benchmarked this against the json approach but:
function convert_array_to_obj_recursive($a) {
if (is_array($a) ) {
foreach($a as $k => $v) {
if (is_integer($k)) {
// only need this if you want to keep the array indexes separate
// from the object notation: eg. $o->{1}
$a['index'][$k] = convert_array_to_obj_recursive($v);
}
else {
$a[$k] = convert_array_to_obj_recursive($v);
}
}
return (object) $a;
}
// else maintain the type of $a
return $a;
}
Hope that helps.
EDIT: json_encode + json_decode will create an object as desired. But, if the array was numerical or mixed indexes (eg. array('a', 'b', 'foo'=>'bar') ), you will not be able to reference the numerical indexes with object notation (eg. $o->1 or $o[1]). the above function places all the numerical indexes into the 'index' property, which is itself a numerical array. so, you would then be able to do $o->index[1]. This keeps the distinction of a converted array from a created object and leaves the option to merge objects that may have numerical properties.

Unable to recreate object from var_exported data (in PHP)

A script running on on our live server sends out data from the following line:
$log_output .= '<br>'.__LINE__.'<br>recordings_data='.var_export($recordings_data,TRUE);
Which looks like this:
recordings_data=stdClass::__set_state(array( 'RecordingLongResponse'
=> array ( 0 => stdClass::__set_state(...), 1 => stdClass::__set_state(), 2 => stdClass::__set_state(), 3 =>
stdClass::__set_state(array( 'roomStartDate' => '1321977120000',
'roomEndDate' => '1321977120000', 'recordingURL' => 'serverURL1',
'secureSignOn' => false, 'recordingId' => '1287268130290',
'creationDate' => '1321977120000', 'recordingSize' => '6765975',
'roomName' => 'Stakeholder Analysis', 'sessionId' => '1287268130229',
)), ...), ))
I'm not sure how to 'recreate' the object. I tried unserializing it:
$recording_data_ser= file_get_contents('elm-ser-data.txt'); // where I've saved everything after the '='
$recording_data = unserialize($recording_data_ser);
serialize() and unserialize() are the generally accepted methods for dumping/loading PHP objects. You can also do it with json_encode() and json_decode(). Is there a reason you want to use var_export()?
Edit: you can only unserialize() the result of serialize() - var_dump() is in a completely different format and isn't designed for importing unless you use eval().
For example:
$arr = array('foo' => 'bar');
var_export($arr);
#=> array (
#=> 'foo' => 'bar',
#=> )
echo serialize($arr);
#=> a:1:{s:3:"foo";s:3:"bar";}
echo json_encode($arr);
#=> {"foo":"bar"}
Once you have the serialized data (via serialize() or json_encode()), you can use the opposite method (unserialize() or json_decode(), respectively) to recreate the object again.
var_export() is intended to dump a data structure to a file. You then have to eval() or include() or require() that file. the serialize() format is completely different from var_export.
var_export produces valid PHP code to define a data structure, as if you'd written out the array/object definition yourself. serialize/unserialize write out in a completely different format, and they're not interchangeable.
If you call var_export() on an instance of stdClass, it attempts to export it using ::__set_state(), which, for some reason, is not implemented in stdClass.
However, casting an associative array to an object usually produces the same effect (at least, it does in my case). So I wrote an improved_var_export() function to convert instances of stdClass to (object) array () calls. If you choose to export objects of any other class, I'd advise you to implement ::__set_state() in those classes.
<?php
/**
* An implementation of var_export() that is compatible with instances
* of stdClass.
* #param mixed $variable The variable you want to export
* #param bool $return If used and set to true, improved_var_export()
* will return the variable representation instead of outputting it.
* #return mixed|null Returns the variable representation when the
* return parameter is used and evaluates to TRUE. Otherwise, this
* function will return NULL.
*/
function improved_var_export ($variable, $return = false) {
if ($variable instanceof stdClass) {
$result = '(object) '.improved_var_export(get_object_vars($variable), true);
} else if (is_array($variable)) {
$array = array ();
foreach ($variable as $key => $value) {
$array[] = var_export($key, true).' => '.improved_var_export($value, true);
}
$result = 'array ('.implode(', ', $array).')';
} else {
$result = var_export($variable, true);
}
if (!$return) {
print $result;
return null;
} else {
return $result;
}
}
// Example usage:
$obj = new stdClass;
$obj->test = 'abc';
$obj->other = 6.2;
$obj->arr = array (1, 2, 3);
improved_var_export((object) array (
'prop1' => true,
'prop2' => $obj,
'assocArray' => array (
'apple' => 'good',
'orange' => 'great'
)
));
/* Output:
(object) array ('prop1' => true, 'prop2' => (object) array ('test' => 'abc', 'other' => 6.2, 'arr' => array (0 => 1, 1 => 2, 2 => 3)), 'assocArray' => array ('apple' => 'good', 'orange' => 'great'))
*/
// Example implementation in context of OP
$export = improved_var_export($data, true);
file_put_contents(dirname(__FILE__).'/data.php', '<'.'?php return '.$export.'; ?'.'>');
// "Unserialization" (evaluation)
$import = include dirname(__FILE__).'/data.php';
?>

Javascript-like objects in PHP?

It's pretty handy in JS to create objects like this:
test = { foo : { bar : "hello world" }, bar2 : "hello world 2" }
and then use them like:
test.foo.bar
test.bar2
Is there anything like this in PHP without declaring classes?
It's called associative arrays.
Example (note: the indentation is for layout purposes):
$test = array(
'foo' => array(
'bar' => 'hello world'
),
'bar2' => 'hello world 2'
);
$test['foo']['bar'];
$test['bar2'];
This is equivalent to the following Javascript code:
var test = {
'foo': {
'bar': 'hello world',
},
'bar2': 'hello world 2'
};
As an alternative, you can use the pre-declared StdClass.
$test = new StdClass;
$test->foo = new StdClass;
$test->foo->bar = 'hello world';
$test->bar2 = 'hello world 2';
which would be written in JavaScript as:
var test = new Object;
test.foo = new Object;
test.foo.bar = 'hello world';
test.bar2 = 'hello world 2';
(note: new Object is the same as {} in Javascript)
stdClass allows you to create (essentially) typeless objects. For example:
$object = (object) array(
'name' => 'Trevor',
'age' => 42
);
As shown here, the fastest way to create a stdClass object is to cast an associative array. For multiple levels, you just do the same thing again inside like this:
$object = (object) array(
'name' => 'Trevor',
'age' => '42',
'car' => (object) array(
'make' => 'Mini Cooper',
'model' => 'S',
'year' => 2010
)
);
Another method is to convert the associative array to an object afterwards with a recursive function. Here's an example.
function toObject(array $array) {
$array = (object) $array;
foreach ($array as &$value)
if (is_array($value))
$value = toObject($value);
return $array;
}
// usage:
$array = // some big hierarchical associative array...
$array = toObject($array);
This is useful when you're not the one making the associative array.
Unfortunately, even though PHP 5.3 supports anonymous methods, you cannot put an anonymous method into a stdClass (though you can put one into an associative array). But this isn't too bad anyway; if you want functionality in it, you really should create a class instead.
You can use a StdClass object or an ArrayObject which are included in php (though the latter requires that you have SPL installed). Though unless you need to access the values specifically with the -> operator its more efficient to just use an associative array instead.
I think what you are looking for is an Associative Array
$test["foo"]["bar"]
http://www.google.com/search?sourceid=chrome&ie=UTF-8&q=keyed+arrays
The closest thing would be arrays.
$test = array(
'foo' => array('bar' => 'hello world'),
'bar2' => 'hello world 2',
);
echo $test['foo']['bar'];
Technically, no. However if you are creating a data object (ie no methods), you could technically write a JSON string and use
$obj = json_decode($obj_string);
I wouldn't recommend it however. I assume there would be significant speed loss.
EDIT
Though it goes without mentioning, associative arrays should be used for this instead of flat data objects.
The only reason to do that is if you wish to pass data back to a JavaScript function with JSON. In that case, use json_encode on the array. Otherwise, just keep it as an array, as there's not reason to encode it and then decode it just so it looks like JavaScript.
Try this way: https://github.com/ptrofimov/jslikeobject
Author implemented JS-like objects, you can even access properties from functions via $this pointer.
But perhaps it is not so good to use such objects instead of usual ones.
$a = array(
'a'=> 123,
'b'=> 334,
'c'=> 7853
);
echo json_encode($a);
This will be the result: {"a":123,"b":334,"c":7853}

Categories