5

Fast code (100ms):

// Mixed could theoretically be an object or an array. 
// In this example it's an array.
$mixed = array();
for($i = 0; $i < 10000; $i++) {
  if (is_array($mixed)) {
    $mixed[getRandomStr(15)] = 'abcd';
  } else {
    // Do something else which we don't care about here
  }
}

Terribly slow code (4000ms): (note that $mixed is passed by reference)

function put(&$mixed, $key, $value) {
  if (is_array($mixed)) {
    $mixed[$key] = $value;
  } else {
    // Do something else which we don't care about here
  }
}

$mixed = array();
for($i = 0; $i < 10000; $i++) {
  put($mixed, getRandomStr(15), 'abcd');
}

Now it's fast again: (note that the is_array check has been dropped here)

function put(&$mixed, $key, $value) {
  $mixed[$key] = $value;
}

$mixed = array();
for($i = 0; $i < 10000; $i++) {
  put($mixed, getRandomStr(15), 'abcd');
}

Now we wrap the array inside an object and reintroduce the is_array check ... and it's still fast:

function put($objWrap, $key, $value) {
  if (is_array($objWrap->mixed)) {
    $objWrap->mixed[$key] = $value;
  } else {
    // Do something else which we don't care about here
  }
}

$objWrap = new stdClass;
$objWrap->mixed = array();

for($i = 0; $i < 10000; $i++) {
  put($objWrap, getRandomStr(15), 'abcd');
}

This happens with PHP 5.3 and 5.4.

Does anyone know why? (and/or how to work around this problem)

My guess: passing a reference to the array to is_array() causes the whole array to be copied, slowing the process down.

Note: you can replace is_array() with !is_object() or even with gettype() === 'array'. It does not change a bit.

Sergio
  • 1,139
  • 13
  • 24
  • 1
    Yeah, it happens with any function if you pass the referenced array to it, not just `is_array` or `get_type` – nice ass May 12 '13 at 14:40
  • Passing a reference does NOT copy, that's the whole point of references. But your first example doesn't have anything like the `put()` function, so you're comparing apples and oranges. – Barmar May 12 '13 at 15:08
  • [related](http://stackoverflow.com/questions/3117604/why-is-calling-a-function-such-as-strlen-count-etc-on-a-referenced-value-so-s). @Barmar, that's not (always) true, and that's not the whole point of references at all – nice ass May 12 '13 at 15:16
  • Of course it's the point. You get a reference to the original object, not a copy, so that changes you make will be reflected in the original. – Barmar May 12 '13 at 15:19
  • @OneTrickPony That related question seems to be exactly the same problem, no? – Barmar May 12 '13 at 15:21
  • @Barmar: that doesn't mean that PHP won't copy the object internally – nice ass May 12 '13 at 15:21
  • Just to clarify: the point here is about why calling is_array inside a method where the array is passed by reference so slow as compared to other code that basically does the same thing. This seems to be a PHP bug to me, or at the very least an unexpected/unwanted behavior, but I may be missing something and this is why I'm asking. – Sergio May 12 '13 at 15:37
  • @Barmar if this bothers you, please ignore my first example and just consider the other ones which share a `put()` method. I believe my doubt/question still remains valid. – Sergio May 12 '13 at 15:41
  • @Sergio: it's not a bug, it's just how PHP works. Take a look at this [bug report](https://bugs.php.net/bug.php?id=34540) and the PHP dev reply: *In case you pass it by reference to the function, and then use the same variable as parameter to a function that doesn't accept by reference, then PHP needs to make a copy of the array. If you are just passing by reference to ensure PHP doesn't create a copy, then you're doing things wrong. You should only pass by reference when you are actually modifying the array inside the function* – nice ass May 12 '13 at 15:44
  • @One Trick Pony that seems to answer my question. If you write that down as an answer rather than a comment, I'll gladly accept it :) – Sergio May 12 '13 at 15:50
  • You should probably close it because it's dupe. Or ask *why does PHP need to make a copy?*, if you're curious about that (I am :). Maybe someone who knows PHP internals can answer us – nice ass May 12 '13 at 15:52
  • @One Trick Pony good point, I'll close this one as dupe and open a new more specific one – Sergio May 12 '13 at 15:56
  • @Sergio Hi! Interesting question! Thinking about this since yesterday. Have you read [this article](http://derickrethans.nl/talks/phparch-php-variables-article.pdf) ? Look at the examples 5 and 6. They explain your situation. (As far as I understand). But I really don't know *why* this happens!! .. For experiments you should know about `debug_zval_dump()`.. It will give you the ref count – hek2mgl May 13 '13 at 09:30

0 Answers0