9

Update: My original intention for this question was to determine if PHP actually has this feature. This has been lost in the answers' focus on the scalar issue. Please see this new question instead: "Does PHP have autovivification?" This question is left here for reference.

According to Wikipedia, PHP doesn't have autovivification, yet this code works:

$test['a']['b'] = 1;
$test['a']['c'] = 1;
$test['b']['b'] = 1;
$test['b']['c'] = 1;

var_dump($test);

Output:

array
  'a' => 
    array
      'b' => int 1
      'c' => int 1
  'b' => 
    array
      'b' => int 1
      'c' => int 1

I found that this code works too:

$test['a'][4] = 1;
$test['b'][4]['f'] = 3;

But adding this line causes an warning ("Warning: Cannot use a scalar value as an array")

$test['a'][4]['f'] = 3;

What's going on here? Why does it fail when I add the associative element after the index? Is this 'true' Perl-like autovivification, or some variation of it, or something else?

Edit: oh, I see the error with the scalar now, oops! These work as expected:

$test['a'][4]['a'] = 1;
$test['a'][4]['b'] = 2;
$test['a'][5]['c'] = 3;
$test['a'][8]['d'] = 4;

So, php does have autovivification? Searching Google for "php autovivification" doesn't bring up a canonical answer or example of it.

Community
  • 1
  • 1
Ollie Glass
  • 19,455
  • 21
  • 76
  • 107
  • PHP does have its version of what Perl developers know as `autovifify`, but PHP has a design history that is ... different from Perl ... and there are some design artifacts and anomalies that are present because of it. This means some design aspects are not clearly identified according to a systematic nomenclature, as is the case with Perl, Java, Python and other mainstream programming languages. See also: https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/ – dreftymac Sep 06 '16 at 18:51

3 Answers3

7

From the PHP manual on the square bracket syntax:

$arr[] = value;

If $arr doesn't exist yet, it will be created, so this is also an alternative way to create an array

With your example:

$test['a'][4] = 1;

Since $test and $test['a'] don't currently exist; they are both created as arrays.

$test['b'][4]['f'] = 3;

$test['b'] and $test['b'][4] don't currently exist; they are both created as arrays.

$test['a'][4]['f'] = 3;

$test['a'][4] does exist, but it is an integer (1). This is the "scalar value" that cannot be used as an array. You can't use the square bracket [] syntax on number values; it doesn't convert an existing value to an array.

Community
  • 1
  • 1
lonesomeday
  • 233,373
  • 50
  • 316
  • 318
3

According to the results, PHP has autovivification. The error comes from the way it works.

When you say: $a[1][2] = 55, PHP wants to insert the 55 into $a[1] as [2]=>55. Since the $a[1] is non-existent, PHP is creating automatically an empty node, cca. $a[1] = Array(). But when the node already exists, PHP does not create $a[1], just performs the [2]=>55, which is an error, if $a[1] is not array-like (array, object).

The last language I've seen, where nodes may have value and children too, is MUMPS. There were also a function, called $DATA(), which told wheter a node has any child (10), value (1) or both (11), or it's non-existent (0). I think, that's the correct handling of associative arrays.

(Anyway, I like this behavior of PHP.)

ern0
  • 3,074
  • 25
  • 40
  • I do too, but I'm surprised that a Google search for "php autovivification" doesn't bring up a canonical statement that it exists or details of how it works. – Ollie Glass May 11 '11 at 10:10
  • 1
    Yep, and I think, it's a very important feature. That makes script languages easier-to-use than compiled ones, even they have nice container classes, like map, hash and so on. My pain is that JavaScript has no autovivification. Creating a "deep" node is one line in PHP, ** line in JavaScript, and * x 2 + 2* in C++ or Java (cca.). – ern0 May 11 '11 at 10:30
1

With:

$test['b'][4]['f'] = 3;

You're not adding an element to

$test['a'][4]

bacause it's not initialized as an array.

If you'd write:

$test['a'][4] = array(1);

Then it would work.

With:

$test['a']['b'] = 1;
$test['a']['c'] = 1;
$test['b']['b'] = 1;
$test['b']['c'] = 1;

You're implicitly initializing $test['a'] and $test['b'] as an array. But $test['a']['b'] (and so on) as an int

Yoshi
  • 54,081
  • 14
  • 89
  • 103