Reputation: 46433
Note: I have already read Function to set default value of associative array if the key is not present and Default values for Associative array in PHP.
Let's say:
$a = array('foo' => '123');
$b = $a['bar']; // PHP Notice: Undefined index: bar
I'd like to have an empty string by default ""
if the key is not present, instead of a PHP Notice.
I know the solutions would be to do:
$b = isset($a['bar']) ? $a['bar'] : "";
// or, since PHP 5.3:
$b = $a['bar'] ?: ""; // but this still produces a "PHP Notice"!
Is there a way to avoid the ?: ""
and directly have:
$b = $a['bar'];
get ""
with no Notice?
Note: this exists in Python with:
import collections
d = collections.defaultdict(str)
print(d['bar']) # empty string, no error
Upvotes: 1
Views: 2145
Reputation: 57388
(TL;DR the answer to the last line is "Yes, it's possible - see Scuzzy's answer")
No. PHP arrays don't work that way.
If you need defaults for known keys, then you can assign them:
$defaults = [
'foo' => 'foo',
'bar' => 'bar',
];
$a = [ 'bar' => 'baz' ];
$a = array_merge($defaults, $a);
Now $a['bar]
will be 'baz' (not the default 'bar'), but $a['foo']
will yield 'foo'.
I think the only way to achieve a similar lexical simplicity with not-yet-defined keys is use a class and have $a
return a default value of your choice using a magic getter. Different defaults for different keys, even.
Then you can write,
class FakeArray {
private array $values;
private array $defaults;
private $default = null;
public function __get($key) {
if (array_key_exists($key, $this->values)) {
return $this->values[$key];
}
if (array_key_exists($key, $this->defaults)) {
return $this->defaults[$key];
}
return $this->default;
}
public function __construct(array $values = [ ]) {
$this->values = $values;
}
public function setDefault($default) {
$this->default = $default;
}
public function setDefaults(array $default = []) {
$this->defaults = $defaults;
}
};
$a = new FakeArray([ 'foo' => '123' ]);
$a->setDefaults([ 'joe' => 'jim' ]);
$a->setDefault('baz');
$c = $a->foo; // $c is now '123'.
$b = $a->bar; // $b is now 'baz' (no error).
$d = $a->joe; // $d is now 'jim' (not 'baz').
I would have thought that extending ArrayObject
would have come very close to what you wanted, allowing to replace $a['key']
for $a->key
, but that is not the case:
class FakeArray extends ArrayObject {
...
public function __get($key) {
return $this->default;
}
}
but while $a['foo'] = 'bar'
does store the value, actually not just accessing a nonexistent index, but even accessing a nonexistent property (which would otherwise work in other classes) now triggers an Index notice:
$b = $a->baz;
PHP Notice: Undefined index: baz in ./test.php ...
So, the ArrayObject
actually behaves worse than a StdClass.
This might mean that there's some magic goodness in ArrayObject that could yet be accessed and exploited, but I don't know for sure how and if this is true, or possible.
Upvotes: 3
Reputation: 12332
I'd like to submit another solution using array ArrayObject
as stated above
This extends the class and slightly tweaks the offsetGet
behavior to always return an empty string
the parent::
statement here invokes the function of the extended class
class MyArrayObject extends ArrayObject
{
function offsetGet( $key )
{
return parent::offsetExists( $key ) ? parent::offsetGet( $key ) : '';
}
}
$myArray = new MyArrayObject( array( 'foo' => '123') );
var_dump( $myArray['foo'] ); // '123' provided string
var_dump( $myArray['bar'] ); // '' our new default
var_dump( isset( $myArray['foo'] ) ); // true
var_dump( isset( $myArray['bar'] ) ); // false
foreach( $myArray as $key )
{
var_dump( $key ); // only one iteration of '123'
}
var_dump( is_array( $myArray ) ); // false unfortunately
var_dump( is_iterable( $myArray ) ); // true however
var_dump( array_merge( array(), $myArray ) ); // will fail
var_dump( array_merge( array(), (array) $myArray ) ); // will work
and finally
$myArray['bar'] = '456'; // now if we set bar
var_dump( $myArray['bar'] ); // '456' new value
var_dump( isset( $myArray['bar'] ) ); // now true
as a suggestion from @miken32 to set a default value
class MyArrayObject extends ArrayObject
{
protected $default;
public function __construct($array = [], $default = null, $flags = 0, $iteratorClass = "ArrayIterator")
{
parent::__construct( $array, $flags, $iteratorClass );
$this->default = $default;
}
function offsetGet( $key )
{
return parent::offsetExists( $key ) ? parent::offsetGet( $key ) : $this->default;
}
}
you can set a default value via
$myArray = new MyArrayObject( array( 'foo' => '123'), 'mydefault' );
Upvotes: 1
Reputation: 59
1 step - add this function:
function getIfIsset(array $array, string $key)
{
return $array[$key] ?? '';
}
2 step - use this:
echo getIfIsset($mayArray, 'bar');
Upvotes: 2
Reputation: 12332
You'd have to pre-populate your array with your defaults or create a object class as stated to handle the default response.
$array = array('foo' => '123') + array('foo' => '', 'bar' => '');
var_dump( $array );
array(2) {
["foo"]=>string(3) "123"
["bar"]=> string(0) ""
}
Upvotes: 0
Reputation: 59
You can use this method @ before variable with key:
echo @$a['bar'];
Upvotes: -1