Why are objects not allowed as keys in associative arrays? - php

The PHP documentation states:
Arrays and objects can not be used as keys. Doing so will result in a warning: Illegal offset type.
AFAIK, PHP arrays are ordered hash-maps. So, why is it per se forbidden to use objects as keys, is there a reason for this limitation? Why is there no possibility to implement a hash function in a class in order to use it as a key?
On a related note, is there a PHP implementation of a hash-map which solves this issue?

Keys need to be immutable in order for them to work. If your objects are mutable, then they can't be keys. That's true in every language that implements them: Java, C#, etc.

See #duffymo for the answer.
Note that there is a "workaround" of sorts, by using spl_object_hash as your key. This returns a string, which is immutable, that can be used as a key and will be the same for any object which occupies that memory address. (Read: spl_object_hash will return the same value for the same instance regardless of where it's called or if the object has changed)

Related

Custom iteration for SplObjectStorage

I want to modify the way to iterate an SPLObjectStorage object, such as sorting it first by the data (info).
So, in a loop, it goes numerically from a to z (using sort() function)
But, in SPLObjectStorage, there is no access to the array, right ?
Is it possible to do it since we don't have the access to the array of objects ??
No, it's not possible. Internally SplobjectStorage use the same data structure as an array (the HashTable), but it's not an "array-array" as we know from the PHP userland: we only add values and not keys, as keys are actually generated from the values by hashing them (you can even overwrite this by overwriting the getHash method). Another difference is that you can additionally add information to the object.
In short, SplObjectStorage should not be used as an array, but as either a set or a map, there lies its strength.

Best practice - REST API response decoded as array or object on client side

I have the following issue:
I make a call to a rest api. It returns a json with data. Now I need on client to process that data and do something with it (doesn't really matter what).
I can either decode the json as an object, or as an associative array. Are there any good practices saying that I should go one way or another (with solid reasons behind them)?
Personally I'm inclined towards object, but in some cases this may not be the best choice (for example when there is a numerical indexed array encoded in json, it will be decoded as array inside the object, so I'm ending up with two types of data - is not a big problem, but is a bit inconvenient).
JSON/JavascriptECMAScript clearly delineates between objects and arrays (as do many other languages, which call them lists and dictionaries, or hashes, or whatever). Objects are unordered key-value pairs, while arrays are ordered numerically indexed containers.
PHP doesn't make that distinction in its arrays, PHP's arrays are ordered key-value pairs also allowing numeric keys. But PHP also happens to have a concept of objects. json_decode simply offers you which way you want to map those ambiguous data types. It's entirely up to you.
There's not a lot you can do with stdClass objects, while arrays are very flexible data structures with tons of manipulation functions. Take your pick. It largely doesn't matter.

Why does the PHP function "json_decode" return an object?

The PHP function json_decode (by default) returns an object. Switching the second argument will return an array.
Maybe I just don't understand objects, but I thought objects have properties and methods (maybe events too). Arrays only have properties.
Given that json_decode will only ever return properties and never methods, shouldn't it always return an array?
It returns an object because JSON defines an object structure. This is what the 'O' stands for in 'JSON'.
This is where the differences between languages starts to become more obvious.
Javascript uses objects where PHP might use an array with named keys. JS can't have named keys in an array, only in an object. Other languages have other limitations to how they structure their variables.
Using an object means that PHP is as consistent with other language implementations of JSON as possible. Since JSON is designed for cross-language communication, being consistent is important.
But as you say, in PHP it is sometimes easier to work with an array, so this is why PHP offers the option of converting it directly to an array.
But be aware that PHP arrays are not the same as JSON arrays and objects. PHP allows you to mix named and numbered array keys. This does not map well to JSON, so if you're using PHP arrays to work with JSON you have to be careful of it. If you're using PHP objects for your JSON work, then you won't have this mismatch in functionality.
Okay, so it seems you already knew this:
By default, json_decode will return a StdClass object. If you want an array, use:
json_decode($jsondata, true);
See: http://php.net/manual/en/function.json-decode.php
So, to answer "Why":
JSON is a format used to store hierachical datasets, much like how XML might have been used in the past. Because however Javascript is optimized for accessing object properties, no additional libraries need be present to work with JSON structures - they are actual objects in Javascript.
It is easier to parse JSON than XML, and relatively easy to translate into objects and/or arrays in back-end languages. In many languages outside of PHP, there is something called a Dictionary, or Hashtable, which is usually an object with key/value pairs.
PHP does not differentiate arrays and "associative arrays" other than contextually, so for a PHP developer it's natural to expect the result to be an associative array, and that option exists, but most likely for flexibility (and maybe because it decodes more naturally to the object) the object format exists.
I hope that explains. I also strongly recommend reading further on what JSON is (and is not) here:
http://json.org
json_decode returns by default an object from the stdClass class. This is the basic (top-level) generic class for objects. This class has no method nor attributes first.
But then you can add some "on the fly", what's called Dynamic Properties. More here:
Sometimes all that is necessary is a property bag to throw key value pairs into. One way is to use array, but this requires quoting all keys. Another way is to use dynamic properties on an instance of StdClass.
Hope it helps.
It returns the object of stdClass.
If an object is converted to an object, it is not modified. If a value of any other type is converted to an object, a new instance of the stdClass built-in class is created. If the value was NULL, the new instance will be empty. Arrays convert to an object with properties named by keys, and corresponding values. For any other value, a member variable named scalar will contain the value.

In php, how similar to an array can I make an object act? And how would I do that?

I know that by implementing iterable you can make an object able to be foreached over. I'd like to take it further and make an object react like an array would in as many places as possible where an array is called for.
(The reason for this is because I'm selecting data from a database, and the statement object that results by default is very good on memory, whereas the full dataset in array form tends to throw the memory usage into orbit. I'd love to have the best of both worlds, array type usage with the lower memory usage up until the moment that an array type of behavior is called for.)
You can make your object Countable so that it works with count
You can implement ArrayAccess, so that syntax like $obj['index'] works.
Like you've done, you can implement Iterator or IteratorAggregate.
What you can't do:
You can't make it work with the array functions, except these, which kind of work, but rely on converting the object to an array, which is done by fetching its properties:
end, prev, next, reset, current, key
array_walk, array_walk_recursive, array_key_exists.
Have a look at the ArrayAccess and Countable interfaces. The former allows accessing your object using $obj[...], the latter allows count($obj);
Don't know if this is what you need, but you can:
// $your_object
foreach(get_object_vars($your_object) as $property=>$value) /* do something */ ;
If memory serves me right, you can (interchangeably) use typecasting wherever you need.
Perhaps it's not considered OOP candy, but it's imperative stuff that works.

SPL vs. Array: When should we use SPL and when should we use Array in PHP?

In java and C++ when we don't know the size - array not used like in PHP, instead used linkedList etc.
In PHP exist SPL, but most of the times programmers use array, why (because people don't know about SPL )?
When we should use Array in PHP and whenSPL and what is the difference in this case between PHP and Java/C++?
Every PHP request must initialize all variables and after request they are freed. Because of that not often comes situations where special data structures (like maxheap, linkedlist or queue) are more efficient than array.
Also arrays are much simpler to understand and use for beginner.
Difference from C++ in PHP is that arrays length is dynamic. You can add elements whenever you want.
$arr=array();
$arr[]=5; //add integer to array
echo count($arr); //1
$arr[]=7;
echo count($arr); //2
you can dynamically create and add array to another array
$arr[]=array();
$arr[2][]=5;
echo count($arr); //3
echo count($arr[2]); //1
This will create new array, add element with value 5 and add it as element to array $arr.
$arr[][]=5;
In PHP arrays are hash tables, so you can have not only integer keys but also strings:
$arr['somekey']='somevalue';
If array element is integer then each element requires a value structure (zval) which takes 16 bytes. Also requires a hash bucket - which takes 36 bytes. That gives 52 bytes per value. Memory allocation headers take another 8 bytes*2 - which gives 68 bytes.
About arrays in PHP: http://oreilly.com/catalog/progphp/chapter/ch05.html
You're asking us to compare two massively different things, almost the only similarity being that they're both (arrays and the SPL) available in PHP.
To that end, it would be essentially nonsensical to compare directly, or prescribe, when one should be used over the other for times when both might be used to accomplish a task. On that note, both might be used intertwined: for example, using the ArrayIterator to iterate over an array, or the ArrayObject to make use of array-style syntax when working with objects.
You also seem to be confused, or just unclear, about what the SPL is; it certainly is not restricted to tools used to iterate over collections of things. Did you mean to ask about specific parts of the library, or are you perhaps just unclear what is available in it?
Use standard arrays, it is faster than ArrayObject.
Use ArrayObject only to implement your own specified arrays with your custom methods.
Not necessarilly a confusion maybe, because people can decide to use "SplStack" instead of vanilla array associated with array_push/pop functions. Or use arrays in classical way,
and then there exist SplDoublyLinkedList, SplQueue, SplHeap. plus ArrayObject.
So the question is valid. And the answer is: you do the same in a more javaish way, and it is slower.
SPL generally speaking is a tentative to mimic standard & "off-the-shelf" classes & API, like there exist in C++ & Java.
IMHO it came too late.

Categories