PHP function to validate array elements for n level - php

I have tried out with the google and tried myself to get done for the below functionality. I need a function that will validate each array element whether it is scalar or not. So i wrote a simple function that will iterate each element of the array and checks for scalar or not.
But the real requirement, the array could be a multi dimentional array. So i have modified the array and called the function recursively as below, But it will not go-through all elements in the array.
function validate_scalar($params)
{
foreach ($params as $key => $arg)
{
if (is_array($arg))
{
validate_scalar($arg);
}
else
{
if (!is_scalar($arg))
{
// throwing an exception here if not scalar.
}
}
}
return true;
}
Is there any method to achieve this functionality? Please help me on this.

array_walk_recursive
You could use something like this:
<?php
$array = array(
'kalle' => 'asdf',
'anka' => array(
123,
54324,
new stdClass()
)
);
array_walk_recursive($array, function ($item, $key) {
if (!is_scalar($item)) {
echo $key . " => : Is not scalar\n";
return false;
}
echo $key . " => : Is scalar\n";
return true;
});
array_walk_recursive ignores values that are arrays
output:
kalle => : Is scalar
0 => : Is scalar
1 => : Is scalar
2 => : Is not scalar

Related

Laravel Collection, replace where method with filter method

I have a collection on which I use the where method in order to get only the element that match like this:
myCollection->where('akey', $value);
When I try to transform this with the filter method, it fails:
myCollection->filter(function($value, $key){
if($key === 'akey' && $value === $aValue)
return true;
});
I try to use filter because I want to select items in the collection if theirs values are equals to multiple value. (where or Where or Where or Where basically).
I assume that $aValue is defined outside of the filter function, you should pass it to the callback function like this:
myCollection->filter(function($value, $key) use ($aValue) {
if($key === 'akey' && $value === $aValue)
return true;
});
-- EDIT --
Based on your example using where I think this should work.
myCollection->filter(function($item) use ($aValue) {
return $item->aKey === $aValue;
});
I write a simple PHP script to describe your problem, Please check out the inline comments for details.
<?php
require __DIR__ . '/vendor/autoload.php';
use Illuminate\Support\Collection;
$data = [
[
'akey' => 'the answer',
'avalue' => 'vote up',
],
];
$filterKey = 'the answer';
$c = new Collection($data);
$c = $c->filter(function($val, $key) use ($filterKey) {
var_dump($key); // $key is indexed number, It will output "int(0)"
// return $key == $filterKey; // XXX Here is problem, Try to comment out to see the different.
return $val['akey'] == $filterKey; // Get value from $val, which is associative array.
});
print_r($c->all());
Output:
/Users/gasolwu/Code/laravel/demo.php:18:
int(0)
Array
(
[0] => Array
(
[akey] => the answer
[avalue] => vote up
)
)

Check if child of array is object or array

I have a class which allows to retrieve an array according to the syntax "key.key2.key3".
For now, no problem. Problems occur when one of the keys is an object.
Because I have to check that the key is an array or an object
My script bug when I try to determine if type of key[key2] == array or if type of key->key2 == object. One of the two conditions may be false. (If script tests that key[key2] == array, and that key2 is an object, for example).
Is there a way to verify that key2 is an array or an object without doing key[key2] or key->key2 ?
Thanks.
You need to perform the test on the parent, before accessing the key.
Here is an example:
function findValue($a, $s) {
$keys = explode(".", $s);
foreach ($keys as $key) {
if (is_object($a)) {
$a = $a->$key;
} else if (is_array($a)) {
$a = $a[$key];
} else { // unexpected
return null;
}
}
return $a;
}
// Sample data: mix of object and array:
$arr = [
"key1" => (object) [
"key2" => [
"key3" => 42
]
]
];
echo findValue($arr, "key1.key2.key3"); // 42
What about is_array()?
Docs here

PHP: array search when array doesn't start on zero

I'm trying to find a key in an array that doesn't start with zero.
This is my not so elegant solution:
private $imagetypes = [
1 => [
'name' => 'banner_big',
'path' => 'campaigns/big/'
],
2 => [
'name' => 'banner_small',
'path' => 'campaigns/small/'
],
// ...
If i use $key = array_search('banner_big', array_column($this->imagetypes, 'name')); the result is 0
I came up with this solution but I feel like I needlessly complicated the code:
/**
* #param string $name
* #return int
*/
public function getImagetypeFromName($name)
{
$keys = array_keys($this->imagetypes);
$key = array_search($name, array_column($this->imagetypes, 'name'));
if ($key !== false && array_key_exists($key, $keys)) {
return $keys[$key];
}
return -1;
}
Is there a better solution then this.
I can't change the keys in.
Just save indexes
$key = array_search('banner_big',
array_combine(array_keys($imagetypes),
array_column($imagetypes, 'name')));
demo on eval.in
The problem is array_column will return a new array (without the existing indexes)
So in your example.
$key = array_search('banner_big', array_column($this->imagetypes, 'name'));
var_dump($key);
//$key is 0 as 0 is the key for the first element in the array returned by array_column.
You can mitigate against this by creating a new array with the existing keys.
That's because array_column() generates another array (starting at
index zero), as you may have imagined. An idea to solve this would be to
transform the array with array_map(), reducing it to key and image
name (which is what you're searching for). The keys will be the same,
and this can be achieved with a simple callback:
function($e) {
return $e['name'];
}
So, a full implementation for your case:
public function
getImagetypeFromName($name)
{
$key = array_search($name, array_map(function($e) {
return $e['name'];
}, $this->imagetypes));
return $key ?: -1;
}

return boolean if any item in the array is empty/not empty

I have an array of objects. I need to loop over these objects (preferably without foreach(), and if a certain key in the objects is not empty, then return true, otherwise return false.
For example,
$items = array(
'0' => stdClass {
name => Ryan
suppliers => array()
}
'1' => stdClass {
name => Dave
suppliers => array(
'0' => stdClass {}
)
}
)
Essentially, I need to go through the array and check the "supplier" key of the object, and if any of them are not empty, return true for the entire thing, otherwise return false.
What's wrong with foreach?
$check = function($arr) {
foreach($arr as $o) {
if (!empty($o->suppliers)) return true;
}
return false;
};
If you want to use it only in one place, use anonymous function
I don't understand why you don't want to use foreach because thing is - foreach is only right way because you leave loop as soon as you find value
One other option, reduce the array to a boolean.
array_reduce($items, function($hasSupplier, $item) {
return !empty($item->suppliers) || $hasSupplier;
});
Still, I prefer the foreach solution since it won't continue to iterate unnecessarily.
You can filter and check for a result:
if(array_filter($items, function($v) { return !empty($v->suppliers); })) {
//at least one not empty
} else {
//all are empty
}
If you really want a boolean:
$result = (bool)array_filter($items, function($v) { return !empty($v->suppliers); })

strip null values of json object

All my AJAX requests are in json format which are being parsed in javascript.
How can i prevent null values being displayed in an HTML page without needing to write an if-statement in javascript for each json value?
Or should i write a custom PHP function to encode an array to json instead of using json_encode() so it doesn't display 'null' ?
In server side with PHP,
You can use array_filter before json_encode.
array_filter without second argument removes null elements of entry array, example :
$object= array(
0 => 'foo',
1 => false,
2 => -1,
3 => null,
4 => ''
);
$object = (object) array_filter((array) $object);
$result = json_encode($object);
The $result contains:
{"0":"foo","2":-1}
As you see, the null elements are removed.
I'm going to add to the accepted answer because that will only work if you have a 1 dimensional object or array. If there is any array or object nesting then in order to get the accepted solution to work, you must create some sort of recursive array filter. Not ideal.
The best solution my colleague and I came up with was to actually perform a regular expression on the JSON string before it was returned from the server.
$json = json_encode($complexObject);
echo preg_replace('/,\s*"[^"]+":null|"[^"]+":null,?/', '', $json);
The regular expression will remove all places in the string of the form ,"key":null including any whitespace between the leading comma and the start of the key. It will also match "key":null, afterwards to make sure that no null values were found at the beginning of a JSON object.
This isn't an ideal solution but it's far better than creating a recursive array filter given an object could be several dimensions deep. A better solution would be if json_encode had a flag that let you specify if you wanted null entries to remain in the output string.
To remove only NULL, but keep FALSE, '', and 0:
function is_not_null($var)
{
return !is_null($var);
}
echo json_encode(array_filter((array) $object, 'is_not_null'));
public function __toString() {
$obj = clone $this;
$keys = get_object_vars($obj);
foreach ($keys as $key => $value) {
if (!$value) {
unset($obj->{$key});
}
}
return json_encode($obj);
}
What about using the native JSON.stringify method on the javascript side?
You can set, a second parameter, a function to remove keys with a null value.
If you return undefined, the property is not included in the output JSON string (check the documentation for "the replacer parameter" at https://developer.mozilla.org/en-US/docs/Using_native_JSON#The_replacer_parameter).
function removeNulls(obj) {
var str = JSON.stringify(obj, function(key, val) {
if (val == null) return undefined;
return val;
});
return JSON.parse(str);
}
Then you can have a "normalized" JSON object by calling:
var obj = removeNulls(obj);
echo json_encode(array_filter((array) $object, function($val) {
return !empty($val);
}));
class Foo implements JsonSerializable
{
public $param1;
public $param2;
public function jsonSerialize()
{
return array_filter((array) $this, function ($var) {
return !is_null($var);
});
}
}
public function testJsonSerialization()
{
$expectedJson = '{"param1":true}';
$foo = new Foo();
$foo->param1 = true;
$foo->param2 = null;
$this->assertEquals(
$expectedJson,
json_encode($foo)
);
}`
of course you can create Abstract class with custom jsonSerialize method and extend all your DTOs from this
A version that works with multi-dimensional arrays.
$withoutNull = function($a) use (&$withoutNull) {
return array_filter(
array_map(
fn($p) => is_array($p) ? $withoutNull($p) : $p, $a
)
);
};
Example:
$a = [
"name" => "nathan",
"data" => [
"age" => 27,
"something" => null
],
"another" => null
];
$b = $withoutNull($a);
print_r($b);
Output:
Array
(
[name] => nathan
[data] => Array
(
[age] => 27
)
)

Categories