Array to Object and Object to Array in PHP - Interesting Behaviour

Array to Object and Object to Array in PHP - interesting behaviour

The array key contains a marker that this should be a private property of the class test.

Compare your scripts output with the following:

$array = array(
"xpublic" => "x1",
# this will become a private member:
"\x00test\x00xprivate" => "x2",
# this will become a protected member:
"\x00*\x00xprotected" => "x3"
);

var_dump($array);

$obj = (object) $array;

var_dump($obj);

When serialized, the same string is used to describe the private members.

Output:


array(3) {
["xpublic"]=>
string(2) "x1"
["testxprivate"]=>
string(2) "x2"
["*xprotected"]=>
string(2) "x3"
}

object(stdClass)#1 (3) {
["xpublic"]=>
string(2) "x1"
["xprivate":"test":private]=>
string(2) "x2"
["xprotected":protected]=>
string(2) "x3"
}

In the output of var_dump(), the null bytes are not visible.

(Update: Added protected class member)

Cast object to array - strange behaviour

When casting an object to an array, certain properties (private, protected and parent properties) are assigned to the array, with keys that look like:

*protected
ClassNamePrivate
ParentNameProperty

But they really look like this:

"\0*\0protected"
"\0ClassName\0Private"
"\0ParentName\0Property"

That's what's causing your problems here.

Replace:

echo $new['EPPContactemail'];

with

echo $new["\0EPPContact\0email"];

And take it from there.

Note that you'll have to use double quotes as string delemiters, because '\0' !== "\0", just as '\n' !== "\n"

This behaviour is documented on php.net, though it's rather well hidden

(array) type cast strange behaviour object to array conversion

A few findings I have here:

Quoted from:

  1. A numeric string as array key in PHP
  2. http://www.php.net/manual/en/language.types.array.php

They state that:

Strings containing valid integers will be cast to the integer type. E.g. the key "8" will actually be stored under 8. On the other hand "08" will not be cast, as it isn't a valid decimal integer.

What's interesting is (slightly modifying your test script):

<?php
$json = '{"1455260079":"Tracking : #34567808765098767 USPS","1455260723":"Delivered","1455261541":"Received Back"}';

$json_obj = json_decode($json);
$json_array = (array) $json_obj;
var_dump($json_array);
print_r($json_array);

$newerArray = array();

echo "json_array contents: \n";
foreach($json_array as $k => $v){
echo "k: $k " . gettype($k) . ", v: $v " . gettype($v) . "\n";
$newerArray[$k] = $v;
}

echo "\n";

echo "newerArray contents: \n";
foreach($newerArray as $k => $v){
echo "k: $k " . gettype($k) . ", v: $v " . gettype($v) . "\n";
}

echo $json_array["1455260079"]."\n";
echo $newerArray["1455260079"]."\n";

The output is:

array(3) {
["1455260079"]=>
string(34) "Tracking : #34567808765098767 USPS"
["1455260723"]=>
string(9) "Delivered"
["1455261541"]=>
string(13) "Received Back"
}
Array
(
[1455260079] => Tracking : #34567808765098767 USPS
[1455260723] => Delivered
[1455261541] => Received Back
)
json_array contents:
k: 1455260079 string, v: Tracking : #34567808765098767 USPS string
k: 1455260723 string, v: Delivered string
k: 1455261541 string, v: Received Back string

newerArray contents:
k: 1455260079 integer, v: Tracking : #34567808765098767 USPS string
k: 1455260723 integer, v: Delivered string
k: 1455261541 integer, v: Received Back string

Notice: Undefined offset: 1455260079 in /in/Eq1OI on line 24

Tracking : #34567808765098767 USPS

Notice the type of the key in of two arrays - the casted array have (numeric) string keys, while the reassigned array have integer keys.

When you cast the object to an array, the key is somehow still a string. This is not expected by the PHP definition of an array, according to the quote above.

So when you try to access the array with a "numeric string", PHP still treats the string as an integer, but internally, the keys are still strings, resulting in a undefined array.

This also implies that for associative arrays, key comparisons are actually strict but practically loose.

PHP prepend object in array of objects

You should be able to "simply" merge the two arrays:

$post_types = array_merge($prepend, $post_types);

PHP: convert object to array gives me index of array field's name with namespace?

Instead of converting it to array (which will do things you don't expect), have your MyObject implement the JsonSerializable interface.

namespace backoffice\controller;

class MyObject implements \JsonSerializable
{
private $id;
private $name;

public function jsonSerialize() {
return get_object_vars($this);
}

// setters
}

Then you can use json_encode on it directly and get the desired result:

$obj = new MyObject;
$obj->setId(1);
$obj->setName('foo');
echo json_encode($obj); // {"id":1,"name":"foo"}

How do I convert an object to an array?

You should look at get_object_vars , as your properties are declared private you should call this inside the class and return its results.

Be careful, for primitive data types like strings it will work great, but I don't know how it behaves with nested objects.

in your case you have to do something like;

<?php
print_r(get_object_vars($response->response->docs));
?>

PHP - Array to object - Issue when getting object variable by index

This is PHP brokenness. Curly-brace syntax for object property access does not work for all-digit keys.

get_object_vars() vs. cast to array

This is not exactly true.

get_object_vars is scope-sensitive and will return all visible properties excepting static properties regardless of their visbility. If you call it from outside your class, you'll only get the public members; from a derived class, you'll get the protected and public members; and from the class itself, you'll get all the members. The array keys represent the property names, and are not mangled.

The (array) cast returns, at least on PHP 5.3.0, all the object properties, public and otherwise. The name of the properties are mangled according to their protection level:

  • public: not mangled, identical to property names
  • protected: key name for property starts with a *
  • private: key name for property starts with the name of the class

See casting to an array for more informations.

I hope you'll be able to better understand which one is the most appropriate for your situation.

Strange behavior adding this object to this static array

That's because your object (i.e. $this in internal context) will be copied by reference, not by value. To do copy by value, you'll need to do:

    public function add($type, $message) 
{
$this->type = $type;
$this->message = $message;
self::$_alerts[] = clone $this;
}

As an alternative, you'll need to instantiate (that is, for example, constructions like new self - but clone seems to be more flexible here) your object as many times as you'll wish to copy.

By the way, there's easy way to realize what's going on. Use var_dump() instead of print_r() - then you'll see that objects are actually same. Sample for your code (i.e. where copying is not fixed yet):


array(2) {
[0]=>
object(Alert)#1 (2) {
["type":"Alert":private]=>
string(5) "error"
["message":"Alert":private]=>
string(6) "test 2"
}
[1]=>
object(Alert)#1 (2) {
["type":"Alert":private]=>
string(5) "error"
["message":"Alert":private]=>
string(6) "test 2"
}
}

-as you can see, objects are same there.

Casting an array to an object allows invalid property names?

That's done by the cast. And technically spoken, those names are not invalid.

You need to differ how you can write (define) these names. If you write:

$1

That's an invalid label. But if you write

${1}

That label is not invalid.

This question might be interesting for you as well: Array to Object and Object to Array in PHP - interesting behaviour.



Related Topics



Leave a reply



Submit