e.g:
$arr = array('k1'=>1,'k2'=>2,'k3'=>3);
If i want get $arr['k4'] (unexpect index),there is a notice:
Notice: undefined index......
so,can i set a dufalut value for array,like as ruby's hash:
h = {'k1'=>1,'k2'=>2,'k3'=>3}
h.default = 'default'
puts h['k4']
then,i'll get 'default';
Just do some sort of check to see if it exists:
isset($arr['k4'])?$arr['k4']:'default';
Or make a function for it:
function get_key($key, $arr){
return isset($arr[$key])?$arr[$key]:'default';
}
//to use it:
get_key('k4', $arr);
#Neal's answer is good for generic usage, but if you have a predefined set of keys that need to be defaulted, you can always merge the array with a default:
$arr = $arr + array('k1' => null, 'k2' => null, 'k3' => null, 'k4' => null);
that way, if $arr defines any of those keys, it will take precidence. But the default values will be there if not. This has the benefit of making option arrays easy since you can define different defaults for each key.
Edit Or if you want ruby like support, just extend arrayobject to do it for you:
class DefaultingArrayObject extends ArrayObject {
public $default = null;
public function __construct(array $array, $default = null) {
parent::__construct($array);
$this->default = $default;
}
public function offsetGet($key) {
if ($this->offsetExists($key)) {
return parent::offsetGet($key);
} else {
return $this->default;
}
}
}
Usage:
$array = new DefaultingArrayObject($array);
$array->default = 'default';
echo $array['k4']; // 'default'
Related
I have a bunch of optional settings and I'm sick of checking for isset and property_exists.
In Laravel, if I ask for a property that does not exist on a model or request, I get null and no complaints (errors). How can I do the same for my data structure.
If I try array, I can't do simple $settings['setting13'], I have to either pre-fill it all with nulls or do isset($settings['setting13']) ? $settings['setting13'] : '' or $settings['setting13'] ?? null. If I try an object (new \stdClass()), $settings->setting13 still gives me a warning of Undefined property.
How can I make a class such that it responds null or an empty string whenever it is asked for a property that it doesn't have?
Simply do what Laravel does, create a class that deals with your data structure which returns a value if key exists, and something else if it doesn't.
I'll illustrate with an example class (this class supports the "dot notation" of accessing array keys):
class MyConfigClass
{
protected $data;
public function __construct(array $data)
{
$this->data = $data;
}
public function get($path = '', $default = null)
{
if(!is_string($path))
{
return $default;
}
// There's a dot in the path, traverse the array
if(false !== strpos('.', $path))
{
// Find the segments delimited by dot
$segments = explode('.', $path);
$result = $this->data;
foreach($segments as $segment)
{
if(isset($result[$segment]))
{
// We have the segment
$result = $result[$segment];
}
else
{
// The segment isn't there, return default value
return $default;
}
}
return $result;
}
// The above didn't yield a result, check if the key exists in the array and if not - return default
return isset($this->data[$path]) ? $this->data[$path] : $default;
}
}
Use:
$my_structure = [
'url' => 'www.stackoverflow.com',
'questions' => [
'title' => 'this is test title'
]
];
$config = new MyConfigClass($my_structure);
echo $config->get('url'); // echoes www.stackoverflow.com
echo $config->get('questions.title'); // echoes this is test title
echo $config->get('bad key that is not there'); // returns null
There is also a possibility to create wrapper as Jon Stirling mentioned in a comments. This approach will allow to keep code clean and also add functionality via inheritance.
<?php
class myArray implements ArrayAccess {
private $container;
function __construct($myArray){
$this->container = $myArray;
}
public function offsetSet($offset, $value) {
if (is_null($offset)) {
$this->container[] = $value;
} else {
$this->container[$offset] = $value;
}
}
public function offsetExists($offset) {
return isset($this->container[$offset]);
}
public function offsetUnset($offset) {
unset($this->container[$offset]);
}
public function offsetGet($offset) {
return isset($this->container[$offset]) ? $this->container[$offset] : null;
}
}
$settings = array("setting1"=>1,"setting2"=>2,"setting3"=>3);
$arr = new myArray($settings);
echo $arr['setting1'];
echo "<br>";
echo $arr['setting3'];
echo "<br>";
echo $arr['setting2'];
echo "<br>";
echo "------";
echo "<br>";
echo $arr['setting4'] ?:"Value is null";
!empty($settings['setting13']) ? $settings['setting13'] : ''
can be replaced with
$settings['setting13'] ?: ''
as long as whatever you want to print and whatever you want to check exists is the same expression. It's not the cleanest thing ever - which would be to check the existence of anything - but it's reasonably clear and can be chained :
echo ($a ?: $b ?: $c ? $default ?: '');
However, you are not the first who are "sick of checking for isset and property_exists, it's just that we still have to do it, or else we get unexpected results when we expect it the least.
It's not about saving time typing code, it's about saving time not debugging.
EDIT : As pointed in the comments, I wrote the first line with isset() instead of !empty(). Since ?: returns the left operand if it's equal to true, it's of course uncompatible with unchecked variables, you have at least to check for existence beforehand. It's emptiness that can be tested.
The operator that returns its left operand if it exists and is different from NULL is ??, which can be chained the same way ?: does.
Admittedly not the best way to do this, but you can use the error suppressor in php like this:
$value = #$settings['setting13'];
This will quitely set$value to NULL if $settings['setting13'] is not set and not report the undefined variable notice.
As for objects, you should just calling for attributes that are not defined in class.
I've got some arrays like this
$something = array('foo' => 'bar');
Now how can I get the content of $something? I want to use this method to retrieve values from arrays but can't work out how to find an array with only it's name given as a string.
getArrayData($array,$key){
// $array == 'something';
// $key == 'foo';
// this should return 'bar'
}
EDIT:
I abstracted this too much maybe, so here is the full code:
class Config {
public static $site = array(
'ssl' => 'true',
'charset' => 'utf-8',
// ...
);
public static $menu = array(
'home' => '/home',
'/hub' => '/hub',
// ...
);
public static function get($from, $key){
return self::$from[$key];
}
public static function __callStatic($method, $key){
return self::get($method,$key);
}
}
In the end the configuration should be accessible from within the whole app by using Config::site('charset') to return 'utf-8'
You can use Variable-Variables
<?php
$something = array('foo' => 'bar');
$key="foo";
$arrayName="something";
echo getArrayData($$arrayName,$key); // Notice the use of $$
function getArrayData($array,$key){
return isset($array[$key])? $array[$key] : NULL ;
}
Fiddle
$array == 'something' doesn't mean much, you can easily check the array keys and return the value if the key exists:
function getArrayData($array,$key){
if(isset($array[$key])) return $array[$key];
else return "";
}
You should pass the array itself as parameter instead of the name. Then you can just return the value by the given key:
function getArrayData($array,$key){
return $array[$key];
}
Im having a lot of difficulty with arrays in PHP. They require me to write a lot of codes such as isset(), empty(), array_key_exist(); And I really dont want to deal with these. If the key doesnt exist just handle it as a null.
$arr = [
'location' => 'Paris'
]
$arr['country'] // boom crash. How to walkaround this?
Any suggestions?
EDIT
I dont want to use any if condition. No isset(), array_key_exist, exceptions, etc. I just want them to be null if the key doesn't exist? Is this possible in PHP? The application is very abstract and data may vary on each request.
function getValue(array $array, $key) {
return isset($array[$key]) ? $array[$key] : null;
}
echo getValue($mysteryArray, 'mysteryKey');
Or:
$array += array_fill_keys(array('foo', 'bar', 'baz'), null);
echo $array['foo'];
My own function inspired from deceze. Works perfectly.
/**
* Fill array with null on nonexistent keys
*
* #param array $arg
* #param array $possible_keys
*/
function fillNull(array $arg, array $possible_keys){
foreach($possible_keys as $key){
$result[$key] = empty( $arg[$key] ) ? null : $arg[$key];
}
return $result;
}
You can use ArrayIterator or some class that gives you the interface you desire.
<?php
class MyArrayIterator extends ArrayIterator {
public function __construct($array, $flags=0) {
parent::__construct($array, $flags);
}
public function offsetGet($index) {
if (!$this->offsetExists($index)) {
return null;
}
return parent::offsetGet($index);
}
}
$arr = [
'location' => 'Paris'
];
$arrIt = new MyArrayIterator($arr);
echo $arrIt['country'];
echo "Only this is echoed";
#$arr['country'] - suppress errors, bad pratice.
&$arr['country'] - use reference, could add additional elements to array, bad pratice.
Is there a way to instantiate a new PHP object in a similar manner to those in jQuery? I'm talking about assigning a variable number of arguments when creating the object. For example, I know I could do something like:
...
//in my Class
__contruct($name, $height, $eye_colour, $car, $password) {
...
}
$p1 = new person("bob", "5'9", "Blue", "toyota", "password");
But I'd like to set only some of them maybe. So something like:
$p1 = new person({
name: "bob",
eyes: "blue"});
Which is more along the lines of how it is done in jQuery and other frameworks. Is this built in to PHP? Is there a way to do it? Or a reason I should avoid it?
the best method to do this is using an array:
class Sample
{
private $first = "default";
private $second = "default";
private $third = "default";
function __construct($params = array())
{
foreach($params as $key => $value)
{
if(isset($this->$key))
{
$this->$key = $value; //Update
}
}
}
}
And then construct with an array
$data = array(
'first' => "hello"
//Etc
);
$Object = new Sample($data);
class foo {
function __construct($args) {
foreach($args as $k => $v) $this->$k = $v;
echo $this->name;
}
}
new foo(array(
'name' => 'John'
));
The closest I could think of.
If you want to be more fancy and just want to allow certain keys, you can use __set() (only on php 5)
var $allowedKeys = array('name', 'age', 'hobby');
public function __set($k, $v) {
if(in_array($k, $this->allowedKeys)) {
$this->$k = $v;
}
}
get args won't work as PHP will see only one argument being passed.
public __contruct($options) {
$options = json_decode( $options );
....
// list of properties with ternary operator to set default values if not in $options
....
}
have a looksee at json_decode()
The closest I can think of is to use array() and extract().
...
//in your Class
__contruct($options = array()) {
// default values
$password = 'password';
$name = 'Untitled 1';
$eyes = '#353433';
// extract the options
extract ($options);
// stuff
...
}
And when creating it.
$p1 = new person(array(
'name' => "bob",
'eyes' => "blue"
));
So I've got a class that I'd like to have it just set defaults if they're not passed in. For example, I can pass it an array called $options.
function new_score($options)
{
}
Then I'd like to have a different function that I can set a var to a default if a key with that var's name doesn't exist in the $options array;
The function definition could look like this:
function _set(&$key, $options, $default)
{
}
I know there's array_key_exists(), and I guess I'm sort of looking for a way to access the variables name.
For example:
$apple = 'orange';
How can I get the string 'apple', so I can look for that key? I know I could take the function _set() and have it look for $key, $var, $options, and $default, but I'd rather abstract it further.
function method($options)
{
//First, set an array of defaults:
$defaults = array( "something" => "default value",
"something_else" => "another default");
//Second, merge the defaults with the $options received:
$options = array_merge($defaults, $options);
//Now you have an array with the received values or defaults if value not received.
echo($options["something"]);
//If you wish, you can import variables into local scope with "extract()"
//but it's better not to do this...
extract($options);
echo($something);
}
References:
http://ar.php.net/manual/en/function.array-merge.php
http://ar.php.net/manual/en/function.extract.php
there's two ways of doing this:
One at a time with the ternary operator:
$key = isset($array['foo']) ? $array['foo'] : 'default';
Or, as an array as a whole:
$defaults = array('foo' => 'bar', 'other' => 'default value');
$array = $array + $defaults;
How about this:
class Configurable
{
private static $defaults = array (
'propertyOne'=>'defaultOne',
'propertyTwo'=>'defaultTwo'
);
private $options;
public function __construct ($options)
{
$this->options = array_merge (self::$defaults, $options);
}
}
From the documentation for array_merge:
If the input arrays have the same
string keys, then the later value for
that key will overwrite the previous
one.