2

When dealing with arrays, it's quite trivial to use array_keys() to grab the keys of your array. When dealing with objects, we have other functions like get_object_vars() to handle those.

So if we have two simple variables, one array and one object:

+--------------------+---------------------------+
|       Array        |          Object           |
+--------------------+---------------------------+
| $array = array(    | $object = new stdClass(); |
|   'foo'  => 'bar', |                           |
|   'john' => 'doe', | $object->foo  = 'bar';    |
|   'beep' => 'bop'  | $object->john = 'doe';    |
| );                 | $object->beep = 'bop';    |
+--------------------+---------------------------+

If we take the array_keys() function and pass it the array, it does what we all expect and gives us an array with foo, john, and beep:

Return: array(3) {
  [0]=> string(3) "foo"
  [1]=> string(4) "john"
  [2]=> string(4) "beep"
}

And of course, as expected, if we instead pass the object to it, the function explodes and doesn't know what to do with it (if we really needed to, we could convert or even just typecast it to an array):

Return: NULL
WARNING array_keys() expects parameter 1 to be array, object given

But if we're dealing with a single key at a time, it seems to get a little bit more interesting. Using PHP's key() function, we can extract whatever key we want.

key($array); //returns: string(3) "foo"
key($object); //returns: string(3) "foo"

// If we move the internal pointer
end( $array ); // key($array) returns: string(4) "beep"
end( $object ); // key($object) returns: string(4) "beep"

Looking at the documentation for the key() function, should this not throw up a warning if an object is used? I ask because I'm curious and was recently downvoted and told not to use key() on objects. Generally I use other methods, but have used key() in some instances without warnings (or errors) - and so I decided to look and nowhere does the documentation say anything about allowing an object, just array &$array. I suppose a similar thing could be said the the array pointer functions like end().

Xhynk
  • 13,513
  • 8
  • 32
  • 69
  • Where does it say that it takes mixed arguments? It says `key ( array $array )` – Barmar Feb 12 '20 at 22:11
  • Actually both `end` and `key` only take arrays as parameters, so `end($object)` and `key($object)` should both cause an error... – Nick Feb 12 '20 at 22:12
  • 1
    Many functions that require a specific type of parameter automatically convert the argument when it's not the required type. – Barmar Feb 12 '20 at 22:12
  • The return value may be mixed. `key ( array $array ) : mixed` The parameter is `array`. Compare to `array_multisort ( array &$array1 [, mixed $array1_sort_order = SORT_ASC [, mixed $array1_sort_flags = SORT_REGULAR [, mixed $... ]]] ) : bool` where the return value is a boolean. – mickmackusa Feb 12 '20 at 22:12
  • https://www.php.net/manual/en/function.key.php - it shows `key ( array $array ) : mixed` in the "description" – Xhynk Feb 12 '20 at 22:12
  • @Xhynk That's the return type. – Barmar Feb 12 '20 at 22:13
  • @Xhynk the output can be `mixed` because there is no guarantee of what might be in an arrays values – Nick Feb 12 '20 at 22:13
  • Oh my apologies, I misinterpreted that - but doesn't that give more credence to the fact that it should be throwing warnings if an object is passed to it? – Xhynk Feb 12 '20 at 22:14
  • As @Barmar says, PHP must be type juggling the object to an array. If you `vardump($object)` you can see it would be easy: `object(stdClass)#1 (3) { ["foo"]=> string(3) "bar" ["john"]=> string(3) "doe" ["beep"]=> string(3) "bop" }` – Nick Feb 12 '20 at 22:15
  • Just because php allows you to write code a certain way without generating Notices/Warning/Errors, doesn't mean that you _should_ use a particular technique. Part of our job is to write clean, clear, intuitive, maintainable code. Handling types with their intended functions is integral to that. _I ask because I'm curious and was recently downvoted and told not to use key() on objects._ **Opinion-based** – mickmackusa Feb 12 '20 at 22:20
  • @Nick - that seems a little scary to type juggle in this instance when a more complicated class could have been based to it `$class = new class { public $foo = 'bar'; public function myFunc(){} };` – Xhynk Feb 12 '20 at 22:24
  • @mickmackusa - I agree, that's why I asked the question in the first place. As I mentioned, my standard use for objects is different, but on the few occassions I have used it, I not once realized that PHP is most likely type juggling objects to arrays as Nick and Barmar alluded to. A warning would have helped illustrate that. – Xhynk Feb 12 '20 at 22:26
  • Well, in PHP5, throwing any var into a `count()` would not error either (and mostly work), until they decided to enforce array(countable) in php7. So, I'm guessing at some point arrays will get enforced in `key() and end()` as well, right? – IncredibleHat Feb 12 '20 at 22:28
  • I had never tried but added to this answer https://stackoverflow.com/questions/60196726/php-get-inner-key-from-standard-class/60197102#60197102 that was not long before this question. – AbraCadaver Feb 12 '20 at 22:35
  • The downvote I referenced was actually in response to that question! After that I reached out to another longtime PHP dev who said not to use `key()` but couldn't explain _why_, other than I suppose the docs not saying it's a supported type `¯\_(ツ)_/¯`. Hence the question! – Xhynk Feb 12 '20 at 22:38
  • I just saw your deleted answer there. It's a good one, somebody didn't understand probably. Undelete it I'll upvote it. – AbraCadaver Feb 12 '20 at 22:59

1 Answers1

1

From: https://www.php.net/manual/en/language.types.array.php

If an object is converted to an array, the result is an array whose elements are the object's properties. The keys are the member variable names, with a few notable exceptions: integer properties are unaccessible; private variables have the class name prepended to the variable name; protected variables have a '*' prepended to the variable name. These prepended values have null bytes on either side. This can result in some unexpected behaviour

For this reason, it should be considered unreliable in certain scenarios to rely on the keys not being mutated in the conversion.


Furthermore, depending on if a given property is public/protected/private, then you might not get the return you expect.

https://www.php.net/manual/en/function.get-object-vars.php#47075

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
  • That's a really interesting read, especially with the potential for null bytes being added to the variable name. Of course type juggling can omit certain pieces of the data, but it's interesting to what kind of nuances go into it when it's between an `array` and an `object`. – Xhynk Feb 12 '20 at 22:41