5

Take this example:

$data = array();
$data['a']['one'] = 'test';

This will throw a notice because $data['a'] doesn't exist. So instead, I always do this:

$data = array();
$data['a'] = array();
$data['a']['one'] = 'test';

Or if I'm in a loop, something like this:

$data = array();
foreach ($items as $item) {
    if (!isset($data['a'])) {
        $data['a'] = array();
    }
    $data['a']['one'] = $item->getId();
}

This gets really reptitive in the code and messy. I know that I could write some kind of array_push alternative function to handle this, but I'm wondering if there is a way to do this with existing PHP methods.

4
  • you can always use add @ before $data['a']['one'] = 'test'; but it's stupid and can cause many problems in future, @ will ignore errors/warning/notices... etc Commented Mar 18, 2015 at 21:22
  • You could use a custom error handler that discards those errors. Commented Mar 18, 2015 at 21:56
  • 1
    Im not sure PHP does give a warning, Ive set it E_ALL and only get warnings when reading and not writing, using PHP 5.5 Commented Mar 18, 2015 at 22:18
  • @kmlnvm You suggest something but then argue with yourself against it :D - IMO Don't advise something you feel shouldn't be used. One should never use @ to suppress warnings, just fix the reason why there is a warning. It's like everyone sees warnings and notices as PHP saying "Hey I noticed this but don't worry about it". Warnings don't crash the code because they are not critical, that doesn't mean they should be ignored. Commented Mar 18, 2015 at 22:49

7 Answers 7

2

Initialising the entire array (all keys, sub arrays etc) somewhere first is not practical.

This means remembering and maintaining it - when you have new data not previously accounted for, you have to also add it to the array initialisation.
(Urgh)

I would least delcare the var as an array ($data = array();) then you don't need is_array() - which is an annoying single line of code before you even do anything useful (two lines including the closing brace..).

However, your checking is not needed.
Your code checks if the array's sub array has been set, and if not you set it as an array and then set the data onto it.

This is not necessary, as you can set data in an array even if some of the sub keys/arrays had not previously been set.

For example this code (this is the entire file and all code ran) won't throw an error, warning, or notice:

$data['a']['one']['blah']['foo'] = 'test';

print_r($data);

echo $data['a']['one']['blah']['foo'];

The above outputs:

Array ([a] => Array ( [one] => Array ( [blah] => Array ( [foo] => test ) ) ) )

test

The above code will not return any warning/notice/errors.
Also notice I didn't even have $data = array().
(although you want to, as you likely use foreach and that initialisation negates the need for using is_array).

That was with error_reporting(-1);

TL;DR; - The Answer

So to answer your question, in your code you could do this (and receive no errors/notices/warnings):

$data = array();

// more data setting the array up  

foreach ($items as $item) {
    $data['a']['one'] = $item->getId();
}
Sign up to request clarification or add additional context in comments.

4 Comments

Interesting. I know that the example in your TL;DR; would have thrown a notice once upon a time. I'll try and find if I'm just wrong about that, or if PHP changed this at some point.
Post the exact notice you get, and post the line of code it happens on and I'll test. Also, what PHP version you use. I've just been testing trying to recreate the notice and just can't, using E_ALL setting, -1 (which is everything PHP can throw back) and others.
I should clarify that I wasn't seeing this Notice today. It's just something that I've taught myself to avoid because I've gotten it historically. On PHP 5.4.24 I am not getting it. I'm still trying to find if this was an issue in earlier versions of PHP, or if I'm just crazy.
Do a bit of testing, changing the code you use to approach it in ways you might now or in the future. If you get no warnings then all good. Note, this is not the preferred way to create an array, which is why using $data = array() first is advised (plus negates is_array() which is a faffy and otherwise pointless line of code)
1

You might wish to look into ArrayObject class, the following runs without errors or warnings

<?php

error_reporting(E_ALL| E_NOTICE);
ini_set('display_errors', 1);

$ar = new ArrayObject();

$ar['foo']['bar'] = 1;
assert($ar['foo']['bar'] === 1);

Checkout the ideone

4 Comments

Thanks! I'll look into this. I've seen objects implementing the Iterator, but I haven't seen this before.
@Victory why do we not see these used more often? They seem pretty good to me (or maybe I've just not seen them often..?)
@James - its not terribly uncommon, but also a lot of times you have to do other initializing with the if isset so its not as universal as it might first seem.
Ah fair enough. Will have a closer look at it, weight up the pros and cons. Cheers
0

Create the array during assignment:

$data=[];
$data['a'] = ['one' => 'test'];

Or create the whole structure in one go

$data = ['a'=>['one'=>'test']];

4 Comments

A nice approach, but it won't work if I need to support creating $data['a'] and appending to $data['a'] with one line of code.
@TylerV. Sorry, i dont follow. In what scenario does this not work for you?
@Steve i guess if you're in a loop, $data['a'] will keep getting overwritten with the latest array.. ['one'=>'test'] ['two'=>'test'] etc.. instead of appending it
Right. It's the situation where I'm in a loop and I need to append to $data['a'] but I'm not sure yet if $data['a'] is an existing array yet. Like I said, the if (!isset($data['a'])) method words great to avoid the Notice, but I was hoping there was a trick I wasn't aware of.
0

I dont believe there are any built in methods that suit your needs: PHP array functions

Maybe creating your own function would be the neatest way to achieve this. Or, depending on your use case you could create your array of data to add to key a separately like below:

$data = array();
$array_data = array();
foreach ($items as $key => $item) {
    $array_data[$key] = $item->getId(); // presuming your 'one' is a dynamic key  
}
$data['a'] = $array_data;

Whether or not this a better than your approach is a matter of opinion I suppose.

Comments

0

You can bypass notices by adding @. Also you can disable notices which I don't recommend at all.

I think there are better ways to write such codes:

$a['one'] = 'test';
$a['two'] = 'test';
$data['a'] = $a;

or:

$data['a'] = ['one'=>'test', 'two'=>'test']

or:

$data = ['a'=>['one'=>'test', 'two'=>'test']];

5 Comments

"I don't recommend at all" - please explain. @ is extremely useful when used with care. For example, $var = NULL; @$var['a']['b'] = 'c' will never lead me wrong. Conversely, function($var){ $var['a']['b'] = 'c';} is not necessarily reliable and may throw a fatal error.
@Jakar I don't recommend was for disabling notices :)
@Jakar You should never use @ for disabling notices - simply never. If you expect a warning or notice, just fix it. Sheesh...
@James, haha. Sheesh. I get what you're saying, but from php docs for the example $arr[key] = value, they say "If $arr doesn't exist yet, it will be created, so this is also an alternative way to create an array." They do proceed to say it's discouraged because of what I already mentioned above, but @ remains a viable option in the correct situation IMO.
@Jakar As a developer, I would never not want to know when there is an issue, of any level, or any kind. If a code returns a warning or notice, I fix the reason why it's doing that, even if just to keep PHP happy. A warning or notice might be the reason you get an error further down the code.
0

The methods that multiple people have suggested to simply create the array as a multidimensional array from the beginning is typically not an option when dealing with dynamic data. Example:

$orderItems = array();
foreach ($items as $item) {
    $oId = $order->getId();
    if (!isset($orderItems[$oId])) {
        $orderItems[$oId] = array();
    }

    $pId = $item->getPackageNumber();
    if (!isset($orderItems[$oId][$pId])) {
        $orderItems[$oId][$pId] = array('packages'=>array());
    }

    $orderItems[$oId][$pId][] = $item;
}

It sounds like I need to create a function to do this for me. I created this recursive function which seems to do the job:

function array_md_push(&$array, $new) {
    foreach ($new as $k => $v) {
        if (!isset($array[$k])) {
            $array[$k] = array();
        }

        if (!is_array($v)) {
            array_push($array[$k], $v);
        } else {
            array_md_push($array[$k], $v);
        }
    }
}

$test = array();
$this->array_md_push($test, array('a' => array('one' => 'test')));
$this->array_md_push($test, array('a' => array('one' => 'test two')));
$this->array_md_push($test, array('a' => array('two' => 'test three')));
$this->array_md_push($test, array('b' => array('one' => 'test four')));

Which gives me this:

array(2) {
  ["a"] => array(2) {
    ["one"] => array(2) {
      [0] => string(4) "test"
      [1] => string(8) "test two"
    }
    ["two"] => array(1) {
      [0] => string(10) "test three"
    }
  }
  ["b"] => array(1) {
    ["one"] => array(1) {
      [0] => string(9) "test four"
    }
  }
}

Comments

-1

This works. You do not need to set as an empty array

$data['a']['one'] = 'test';

1 Comment

With error reporting set to E_ALL this will throw a notice.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.