PHP ReflectionMethod does not get default boolean value of param - php

When I try to get the value of a boolean param, with ReflectionMethod, that have a default value set, I got empty result.
With this code:
public function GetOrderBook($symbol = null, $limit = 100, $async = false)
{
if ($symbol !== null) {
$params = [];
$ref = new \ReflectionMethod($this, 'GetOrderBook');
foreach ($ref->getParameters() as $param) {
$name = $param->name;
$params[$name] = $$name;
}
print_r($params);
}
}
I get this:
Array (
[symbol] => ETHBTC
[limit] => 100
[async] =>
)
Is there a way to get the default value of a param with reflection?

print_r function outputs string representation of values. String representation of false is empty string. To see real values that you have in an array, use var_dump:
var_dump($params);
After that you will see that:
["async"]=>bool(false)

Related

PHP - How to check for multiple array keys in $_POST variable [duplicate]

I have a variety of arrays that will either contain
story & message
or just
story
How would I check to see if an array contains both story and message? array_key_exists() only looks for that single key in the array.
Is there a way to do this?
Here is a solution that's scalable, even if you want to check for a large number of keys:
<?php
// The values in this arrays contains the names of the indexes (keys)
// that should exist in the data array
$required = array('key1', 'key2', 'key3');
$data = array(
'key1' => 10,
'key2' => 20,
'key3' => 30,
'key4' => 40,
);
if (count(array_intersect_key(array_flip($required), $data)) === count($required)) {
// All required keys exist!
}
If you only have 2 keys to check (like in the original question), it's probably easy enough to just call array_key_exists() twice to check if the keys exists.
if (array_key_exists("story", $arr) && array_key_exists("message", $arr)) {
// Both keys exist.
}
However this obviously doesn't scale up well to many keys. In that situation a custom function would help.
function array_keys_exists(array $keys, array $arr) {
return !array_diff_key(array_flip($keys), $arr);
}
Surprisingly array_keys_exist doesn't exist?! In the interim that leaves some space to figure out a single line expression for this common task. I'm thinking of a shell script or another small program.
Note: each of the following solutions use concise […] array declaration syntax available in php 5.4+
array_diff + array_keys
if (0 === count(array_diff(['story', 'message', '…'], array_keys($source)))) {
// all keys found
} else {
// not all
}
(hat tip to Kim Stacks)
This approach is the most brief I've found. array_diff() returns an array of items present in argument 1 not present in argument2. Therefore an empty array indicates all keys were found. In php 5.5 you could simplify 0 === count(…) to be simply empty(…).
array_reduce + unset
if (0 === count(array_reduce(array_keys($source),
function($in, $key){ unset($in[array_search($key, $in)]); return $in; },
['story', 'message', '…'])))
{
// all keys found
} else {
// not all
}
Harder to read, easy to change. array_reduce() uses a callback to iterate over an array to arrive at a value. By feeding the keys we're interested in the $initial value of $in and then removing keys found in source we can expect to end with 0 elements if all keys were found.
The construction is easy to modify since the keys we're interested in fit nicely on the bottom line.
array_filter & in_array
if (2 === count(array_filter(array_keys($source), function($key) {
return in_array($key, ['story', 'message']); }
)))
{
// all keys found
} else {
// not all
}
Simpler to write than the array_reduce solution but slightly tricker to edit. array_filter is also an iterative callback that allows you to create a filtered array by returning true (copy item to new array) or false (don't copy) in the callback. The gotchya is that you must change 2 to the number of items you expect.
This can be made more durable but verge's on preposterous readability:
$find = ['story', 'message'];
if (count($find) === count(array_filter(array_keys($source), function($key) use ($find) { return in_array($key, $find); })))
{
// all keys found
} else {
// not all
}
One more possible solution:
if (!array_diff(['story', 'message'], array_keys($array))) {
// OK: all the keys are in $array
} else {
// FAIL: some keys are not
}
It seems to me, that the easiest method by far would be this:
$required = array('a','b','c','d');
$values = array(
'a' => '1',
'b' => '2'
);
$missing = array_diff_key(array_flip($required), $values);
Prints:
Array(
[c] => 2
[d] => 3
)
This also allows to check which keys are missing exactly. This might be useful for error handling.
The above solutions are clever, but unnecessarily slow. A simple foreach loop over a few keys is much faster.
function array_keys_exist($keys, $array){
foreach($keys as $key){
if(!array_key_exists($key, $array)) {
return false;
}
}
return true;
}
If you have something like this:
$stuff = array();
$stuff[0] = array('story' => 'A story', 'message' => 'in a bottle');
$stuff[1] = array('story' => 'Foo');
You could simply count():
foreach ($stuff as $value) {
if (count($value) == 2) {
// story and message
} else {
// only story
}
}
This only works if you know for sure that you ONLY have these array keys, and nothing else.
Using array_key_exists() only supports checking one key at a time, so you will need to check both seperately:
foreach ($stuff as $value) {
if (array_key_exists('story', $value) && array_key_exists('message', $value) {
// story and message
} else {
// either one or both keys missing
}
}
array_key_exists() returns true if the key is present in the array, but it is a real function and a lot to type. The language construct isset() will almost do the same, except if the tested value is NULL:
foreach ($stuff as $value) {
if (isset($value['story']) && isset($value['message']) {
// story and message
} else {
// either one or both keys missing
}
}
Additionally isset allows to check multiple variables at once:
foreach ($stuff as $value) {
if (isset($value['story'], $value['message']) {
// story and message
} else {
// either one or both keys missing
}
}
Now, to optimize the test for stuff that is set, you'd better use this "if":
foreach ($stuff as $value) {
if (isset($value['story']) {
if (isset($value['message']) {
// story and message
} else {
// only story
}
} else {
// No story - but message not checked
}
}
What about this:
isset($arr['key1'], $arr['key2'])
only return true if both are not null
if is null, key is not in array
I use something like this quite often
$wantedKeys = ['story', 'message'];
$hasWantedKeys = count(array_intersect(array_keys($source), $wantedKeys)) > 0
or to find the values for the wanted keys
$wantedValues = array_intersect_key($source, array_fill_keys($wantedKeys, 1))
try this
$required=['a','b'];$data=['a'=>1,'b'=>2];
if(count(array_intersect($required,array_keys($data))>0){
//a key or all keys in required exist in data
}else{
//no keys found
}
This is the function I wrote for myself to use within a class.
<?php
/**
* Check the keys of an array against a list of values. Returns true if all values in the list
is not in the array as a key. Returns false otherwise.
*
* #param $array Associative array with keys and values
* #param $mustHaveKeys Array whose values contain the keys that MUST exist in $array
* #param &$missingKeys Array. Pass by reference. An array of the missing keys in $array as string values.
* #return Boolean. Return true only if all the values in $mustHaveKeys appear in $array as keys.
*/
function checkIfKeysExist($array, $mustHaveKeys, &$missingKeys = array()) {
// extract the keys of $array as an array
$keys = array_keys($array);
// ensure the keys we look for are unique
$mustHaveKeys = array_unique($mustHaveKeys);
// $missingKeys = $mustHaveKeys - $keys
// we expect $missingKeys to be empty if all goes well
$missingKeys = array_diff($mustHaveKeys, $keys);
return empty($missingKeys);
}
$arrayHasStoryAsKey = array('story' => 'some value', 'some other key' => 'some other value');
$arrayHasMessageAsKey = array('message' => 'some value', 'some other key' => 'some other value');
$arrayHasStoryMessageAsKey = array('story' => 'some value', 'message' => 'some value','some other key' => 'some other value');
$arrayHasNone = array('xxx' => 'some value', 'some other key' => 'some other value');
$keys = array('story', 'message');
if (checkIfKeysExist($arrayHasStoryAsKey, $keys)) { // return false
echo "arrayHasStoryAsKey has all the keys<br />";
} else {
echo "arrayHasStoryAsKey does NOT have all the keys<br />";
}
if (checkIfKeysExist($arrayHasMessageAsKey, $keys)) { // return false
echo "arrayHasMessageAsKey has all the keys<br />";
} else {
echo "arrayHasMessageAsKey does NOT have all the keys<br />";
}
if (checkIfKeysExist($arrayHasStoryMessageAsKey, $keys)) { // return false
echo "arrayHasStoryMessageAsKey has all the keys<br />";
} else {
echo "arrayHasStoryMessageAsKey does NOT have all the keys<br />";
}
if (checkIfKeysExist($arrayHasNone, $keys)) { // return false
echo "arrayHasNone has all the keys<br />";
} else {
echo "arrayHasNone does NOT have all the keys<br />";
}
I am assuming you need to check for multiple keys ALL EXIST in an array. If you are looking for a match of at least one key, let me know so I can provide another function.
Codepad here http://codepad.viper-7.com/AKVPCH
Hope this helps:
function array_keys_exist($searchForKeys = array(), $inArray = array()) {
$inArrayKeys = array_keys($inArray);
return count(array_intersect($searchForKeys, $inArrayKeys)) == count($searchForKeys);
}
This is old and will probably get buried, but this is my attempt.
I had an issue similar to #Ryan. In some cases, I needed to only check if at least 1 key was in an array, and in some cases, all needed to be present.
So I wrote this function:
/**
* A key check of an array of keys
* #param array $keys_to_check An array of keys to check
* #param array $array_to_check The array to check against
* #param bool $strict Checks that all $keys_to_check are in $array_to_check | Default: false
* #return bool
*/
function array_keys_exist(array $keys_to_check, array $array_to_check, $strict = false) {
// Results to pass back //
$results = false;
// If all keys are expected //
if ($strict) {
// Strict check //
// Keys to check count //
$ktc = count($keys_to_check);
// Array to check count //
$atc = count(array_intersect($keys_to_check, array_keys($array_to_check)));
// Compare all //
if ($ktc === $atc) {
$results = true;
}
} else {
// Loose check - to see if some keys exist //
// Loop through all keys to check //
foreach ($keys_to_check as $ktc) {
// Check if key exists in array to check //
if (array_key_exists($ktc, $array_to_check)) {
$results = true;
// We found at least one, break loop //
break;
}
}
}
return $results;
}
This was a lot easier than having to write multiple || and && blocks.
$colsRequired = ["apple", "orange", "banana", "grapes"];
$data = ["apple"=>"some text", "orange"=>"some text"];
$presentInBoth = array_intersect($colsRequired,array_keys($data));
if( count($presentInBoth) != count($colsRequired))
echo "Missing keys :" . join(",",array_diff($colsRequired,$presentInBoth));
else
echo "All Required cols are present";
Does this not work?
array_key_exists('story', $myarray) && array_key_exists('message', $myarray)
<?php
function check_keys_exists($keys_str = "", $arr = array()){
$return = false;
if($keys_str != "" and !empty($arr)){
$keys = explode(',', $keys_str);
if(!empty($keys)){
foreach($keys as $key){
$return = array_key_exists($key, $arr);
if($return == false){
break;
}
}
}
}
return $return;
}
//run demo
$key = 'a,b,c';
$array = array('a'=>'aaaa','b'=>'ccc','c'=>'eeeee');
var_dump( check_keys_exists($key, $array));
I am not sure, if it is bad idea but I use very simple foreach loop to check multiple array key.
// get post attachment source url
$image = wp_get_attachment_image_src(get_post_thumbnail_id($post_id), 'single-post-thumbnail');
// read exif data
$tech_info = exif_read_data($image[0]);
// set require keys
$keys = array('Make', 'Model');
// run loop to add post metas foreach key
foreach ($keys as $key => $value)
{
if (array_key_exists($value, $tech_info))
{
// add/update post meta
update_post_meta($post_id, MPC_PREFIX . $value, $tech_info[$value]);
}
}
$myArray = array('key1' => '', 'key2' => '');
$keys = array('key1', 'key2', 'key3');
$keyExists = count(array_intersect($keys, array_keys($myArray)));
Will return true, because there are keys from $keys array in $myArray
Something as this could be used
//Say given this array
$array_in_use2 = ['hay' => 'come', 'message' => 'no', 'story' => 'yes'];
//This gives either true or false if story and message is there
count(array_intersect(['story', 'message'], array_keys($array_in_use2))) === 2;
Note the check against 2, if the values you want to search is different you can change.
This solution may not be efficient, but it works!
Updates
In one fat function:
/**
* Like php array_key_exists, this instead search if (one or more) keys exists in the array
* #param array $needles - keys to look for in the array
* #param array $haystack - the <b>Associative</b> array to search
* #param bool $all - [Optional] if false then checks if some keys are found
* #return bool true if the needles are found else false. <br>
* Note: if hastack is multidimentional only the first layer is checked<br>,
* the needles should <b>not be<b> an associative array else it returns false<br>
* The array to search must be associative array too else false may be returned
*/
function array_keys_exists($needles, $haystack, $all = true)
{
$size = count($needles);
if($all) return count(array_intersect($needles, array_keys($haystack))) === $size;
return !empty(array_intersect($needles, array_keys($haystack)));
}
So for example with this:
$array_in_use2 = ['hay' => 'come', 'message' => 'no', 'story' => 'yes'];
//One of them exists --> true
$one_or_more_exists = array_keys_exists(['story', 'message'], $array_in_use2, false);
//all of them exists --> true
$all_exists = array_keys_exists(['story', 'message'], $array_in_use2);
Hope this helps :)
I usually use a function to validate my post and it is an answer for this question too so let me post it.
to call my function I will use the 2 array like this
validatePost(['username', 'password', 'any other field'], $_POST))
then my function will look like this
function validatePost($requiredFields, $post)
{
$validation = [];
foreach($requiredFields as $required => $key)
{
if(!array_key_exists($key, $post))
{
$validation['required'][] = $key;
}
}
return $validation;
}
this will output this
"required": [
"username",
"password",
"any other field"
]
so what this function does is validate and return all the missing fields of the post request.
// sample data
$requiredKeys = ['key1', 'key2', 'key3'];
$arrayToValidate = ['key1' => 1, 'key2' => 2, 'key3' => 3];
function keysExist(array $requiredKeys, array $arrayToValidate) {
if ($requiredKeys === array_keys($arrayToValidate)) {
return true;
}
return false;
}

PHP 8.x get variable reference info (call time pass reference)

Call time pass by reference was removed in PHP 5.4. But I have a special case where it seems to be still available in PHP 8 (tried it here: www.w3schools.com):
$myVar = "original";
testFunc([$myVar]);
echo "Variable value: $myVar<br>"; // Output is: "Variable value: original"
testFunc([&$myVar]);
echo "Variable value: $myVar<br>"; // Output is: "Variable value: changed"
testFunc([&$undefinedVar]);
echo "Variable value: $undefinedVar<br>"; // Output is: "Variable value: changed"
testFunc([$undefinedVar_2]);
echo "Variable value: $undefinedVar_2<br>"; // Output is: "Variable value: "
function testFunc( array $arr ) : void
{
if ( !is_array($arr)
|| count($arr) == 0 )
return;
$arr[0] = 'changed';
}
Additionally, this way I can get a C# like parameter out functionality.
Maybe I am misunderstanding something.
Question:
How could I identify within "testFunc" if $arr[0] was passed by reference or normally?
Alternative question (for people who are searching this topic):
Check if variable was passed by reference.
The code by #Foobar pointed me to the right direction. I am using the output of var_dump to analyze it and create a data structure out of it:
class ReferenceInfo
{
public string $Type;
public bool $IsReference;
/** int, float, double, bool are always initialized with default value */
public bool $IsInitialized;
/** #var ?ReferenceInfo[] */
public ?array $SubItems;
public static function FromVariable( mixed $arr ) : ?ReferenceInfo
{
/** #var ReferenceInfo $rootRefInfo */
$rootRefInfo = NULL;
$varInfoStr = self::varDumpToString($arr);
$varInfoStrArray = preg_split("/\r\n|\n|\r/", $varInfoStr);
$refInfoObjectStack = [];
$curKey = NULL;
foreach ( $varInfoStrArray as $line ) {
$lineTrimmed = trim($line);
$lineTrimmedLen = strlen($lineTrimmed);
if ( $lineTrimmedLen == 0 )
continue;
if ( $lineTrimmed == '}' ) {
array_pop($refInfoObjectStack);
$curKey = NULL;
continue;
}
if ( $lineTrimmed[0] == '[' ) {
// Found array key
$bracketEndPos = strpos($lineTrimmed, ']');
if ( $bracketEndPos === false )
return NULL;
$keyName = self::convertToRealType(substr($lineTrimmed, 1, $bracketEndPos - 1));
$curKey = $keyName;
continue;
}
$parenPos = strpos($lineTrimmed, '(');
if ( $parenPos === false ) {
// Must be a NULL type
$parenPos = $lineTrimmedLen;
}
$type = substr($lineTrimmed, 0, $parenPos);
$isInitialized = true;
if ( $type == 'uninitialized' ) {
$parenEndPos = strpos($lineTrimmed, ')', $parenPos);
if ( $parenEndPos === false )
return NULL;
$type = substr($lineTrimmed, $parenPos + 1, $parenEndPos - $parenPos - 1);
$isInitialized = false;
}
$refInfoObj = new ReferenceInfo();
$refInfoObj->IsReference = str_starts_with($type, '&');
$refInfoObj->IsInitialized = $isInitialized;
$refInfoObj->Type = substr($type, $refInfoObj->IsReference ? 1 : 0);
if ( $rootRefInfo == NULL ) {
$rootRefInfo = $refInfoObj;
} else {
$refInfoObjectStack[count($refInfoObjectStack) - 1]->SubItems[$curKey] = $refInfoObj;
}
if ( $refInfoObj->Type == 'array'
|| $refInfoObj->Type == 'object' ) {
$refInfoObj->SubItems = [];
$refInfoObjectStack[] = $refInfoObj;
}
}
return $rootRefInfo;
}
private static function convertToRealType( string $keyName ) : float|int|string
{
if ( $keyName[0] == '"' ) {
$keyName = substr($keyName, 1, strlen($keyName) - 2);
} else if ( is_numeric($keyName) ) {
if ( str_contains($keyName, '.') )
$keyName = doubleval($keyName);
else
$keyName = intval($keyName);
}
return $keyName;
}
private static function varDumpToString( mixed $var ) : string
{
ob_start();
var_dump($var);
return ob_get_clean();
}
}
This is not call-time pass by reference. The parameter to the function is a PHP array, which is passed by value.
However, individual elements of PHP arrays can be references, and the new by-value array will copy over the reference, not the value it points to. As the PHP manual puts it:
In other words, the reference behavior of arrays is defined in an element-by-element basis; the reference behavior of individual elements is dissociated from the reference status of the array container.
To see more clearly, let's look at an example with no functions involved:
$myVar = 42;
// Make an array with a value and a reference
$array = [
'value' => $myVar,
'reference' => &$myVar
];
// Make a copy of the array
$newArray = $array;
// Assigning to the value in the new array works as normal
// - i.e. it doesn't affect the original array or variable
echo "Assign to 'value':\n";
$newArray['value'] = 101;
var_dump($myVar, $array, $newArray);
echo "\n\n";
// Assigning to the reference in the new array follows the reference
// - i.e. it changes the value shared between both arrays and the variable
echo "Assign to 'reference':\n";
$newArray['reference'] = 101;
var_dump($myVar, $array, $newArray);
Output:
Assign to 'value':
int(42)
array(2) {
["value"]=>
int(42)
["reference"]=>
&int(42)
}
array(2) {
["value"]=>
int(101)
["reference"]=>
&int(42)
}
Assign to 'reference':
int(101)
array(2) {
["value"]=>
int(42)
["reference"]=>
&int(101)
}
array(2) {
["value"]=>
int(101)
["reference"]=>
&int(101)
}
Additionally, this way I can get a C# like parameter out functionality.
You do not need any hacks to achieve an out parameter. Pass-by-reference is still fully supported, it's just the responsibility of the function to say that it uses it, not the code that calls the function.
function doSomething(&$output) {
$output = 'I did it!';
}
$output = null;
doSomething($output);
echo $output;
C# out parameters also need to be part of the function definition:
To use an out parameter, both the method definition and the calling method must explicitly use the out keyword.
The only difference is that PHP only has an equivalent for ref, not out and in:
[The out keyword] is like the ref keyword, except that ref requires that the variable be initialized before it is passed.

PHP - Looping through a mixed array

Let’s say I have two arrays, one is of keys I require, the other is an array I want to test against.
In the array of keys I require, each key might have a value which is itself an array of keys I require, and so on.
Here’s the function so far:
static function keys_exist_in_array(Array $required_keys, Array $values_array, &$error)
{
foreach($required_keys as $key)
{
// Check required key is set in the values array
//
if (! isset($values_array[$key]))
{
// Required key is not set in the values array, set error and return
//
$error = new Error();
return false;
}
// Check the value is an array and perform function on its elements
//
if (is_array($values_array[$key]))
{
Static::keys_exist_in_array($required_keys[$key], $values_array[$key], $error);
}
return true;
}
}
My problem is that the array I want to submit to $required_keys CAN look like this:
$required_keys = array(
‘key1’,
‘key2’,
‘key3’,
‘key4’ = array(
‘key1’,
‘key2’,
‘key3’ = array(
‘key1’
)
)
);
Obviously the problem here is that foreach only finds each key, e.g. ‘key4’, rather than the values without their own value, e.g. ‘key1’, ‘key2’, ‘key3’.
But if I loop through with a standard for loop, I only get the values, key1, key2, key3.
What’s a better way of doing this?
Thanks
Several problems:
$key is the element of the array, not a key, so you
You shouldn't return false as soon as you see a non-matching element, because there could be a matching element later in the array. Instead, you should return true as soon as you find a match. Once you find a match, you don't need to keep searching.
You need to do the isarray() test first, because you'll get an error if $key is an array and you try to use $values_array[$key]. And it should be isarray($key), not isarray($values_array[$key]).
You need to test the value of the recursive call. If it succeeded, you can return immediately.
You should only return false after you finish the loop and don't find anything.
static function keys_exist_in_array(Array $required_keys, Array $values_array, &$error)
{
foreach($required_keys as $key)
{
// Check the value is an array and perform function on its elements
//
if (is_array($key))
{
$result = Static::keys_exist_in_array($required_keys[$key], $values_array[$key], $error);
if ($result) {
return true;
}
}
// Check required key is set in the values array
//
elseif (isset($values_array[$key]))
{
return true;
}
}
$error = new Error();
return false;
}
Convert the array to a key => value array with an empty value for the "keys" that don't have a value.
$arr = [
'a',
'b' => ['foo' => 1, 'bar' => 'X'],
'c' => ['baz' => 'Z'],
'd'
];
$res = [];
$keys = array_keys($arr);
$vals = array_values($arr);
foreach ($vals as $i => $v) {
if (is_array($v)) {
$res[$keys[$i]] = $v;
} else {
$res[$v] = [];
}
}
print_r($res);
Result:
Array
(
[a] => Array
(
)
[b] => Array
(
[foo] => 1
[bar] => X
)
[c] => Array
(
[baz] => Z
)
[d] => Array
(
)
)
Returning false here is the correct action if you require that ALL the $required_keys exist, because you want it to stop looking as soon as it finds a missing key.
static function keys_exist_in_array(Array $required_keys, Array $values_array, &$error)
{
foreach($required_keys as $key=>$value)
{
//check if this value is an array
if (is_array($value))
{
if (!array_key_exists($key, $values_array)
|| !Static::keys_exist_in_array($value, $values_array[$key], $error);){
$error = new Error();
return false;
}
}
// Since this value is not an array, it actually represents a
// key we need in the values array, so check if it is set
// in the values array
elseif (!array_key_exists($value, $values_array))
{
// Required key is not set in the values array, set error and return
$error = new Error();
return false;
}
}
//All elements have been found, return true
return true;
}

if multiple variables are empTY

I am trying to check to see if any of the fields have been field out and if NONE have been field out return back to page with error. Even if I have a field filled it still returns acting like no fields are selected.
Controller
public function getServices() {
$user = User::find(Auth::user()->id);
$input = [
'rooms' => Input::get('rooms'),
'pr_deodorizer' => Input::get('pr_deodorizer'),
'pr_protectant' => Input::get('pr_protectant'),
'pr_sanitizer' => Input::get('pr_sanitizer'),
'fr_couch' => Input::get('fr_couch'),
'fr_chair' => Input::get('fr_chair'),
'pr_sectional' => Input::get('pr_sectional'),
'pr_ottoman' => Input::get('pr_ottoman'),
'pr_tile' => Input::get('pr_tile'),
'pr_hardwood' => Input::get('pr_hardwood')
];
$empty = 'No services were selected';
$var = $input['rooms']&& $input['pr_deodorizer']&&
$input['pr_protectant']&& $input['pr_sanitizer']&&
$input['fr_couch']&& $input['fr_chair']&&
$input['pr_sectional']&& $input['pr_ottoman']&&
$input['pr_tiles']&& $input['pr_hardwood'];
if(empty($var)){
return Redirect::to('book/services')->withErrors($empty)->withInput();
}
foreach($input as $services)
{
$service = new Service();
$service->userID = $user->id;
$service->services = $services;
$service->save();
}
return Redirect::to('book/schedule');
}
I have tried !isset() but I still cannot get it to work.
if you want to check if variable is empty, you should use empty() function not &&
when you using && string "0" is casted to false, this may be not what you expecting.
if you want to detect if any of keys in array is empty use this function:
function arrayEmpty($keys, $array) {
$keys = explode(" ", trim($keys));
foreach($keys as $key) {
if (!isset($array[$key]) || empty($array[$key])) return true; // isset prevents notice when $key not exists
}
return false;
}
use example:
$array = array( "foo" => "bar" );
arrayEmpty("foo", $array); // false
arrayEmpty("foo bar", $array); // $array["bar"] not exists, returns true

How to check if multiple array keys exists

I have a variety of arrays that will either contain
story & message
or just
story
How would I check to see if an array contains both story and message? array_key_exists() only looks for that single key in the array.
Is there a way to do this?
Here is a solution that's scalable, even if you want to check for a large number of keys:
<?php
// The values in this arrays contains the names of the indexes (keys)
// that should exist in the data array
$required = array('key1', 'key2', 'key3');
$data = array(
'key1' => 10,
'key2' => 20,
'key3' => 30,
'key4' => 40,
);
if (count(array_intersect_key(array_flip($required), $data)) === count($required)) {
// All required keys exist!
}
If you only have 2 keys to check (like in the original question), it's probably easy enough to just call array_key_exists() twice to check if the keys exists.
if (array_key_exists("story", $arr) && array_key_exists("message", $arr)) {
// Both keys exist.
}
However this obviously doesn't scale up well to many keys. In that situation a custom function would help.
function array_keys_exists(array $keys, array $arr) {
return !array_diff_key(array_flip($keys), $arr);
}
Surprisingly array_keys_exist doesn't exist?! In the interim that leaves some space to figure out a single line expression for this common task. I'm thinking of a shell script or another small program.
Note: each of the following solutions use concise […] array declaration syntax available in php 5.4+
array_diff + array_keys
if (0 === count(array_diff(['story', 'message', '…'], array_keys($source)))) {
// all keys found
} else {
// not all
}
(hat tip to Kim Stacks)
This approach is the most brief I've found. array_diff() returns an array of items present in argument 1 not present in argument2. Therefore an empty array indicates all keys were found. In php 5.5 you could simplify 0 === count(…) to be simply empty(…).
array_reduce + unset
if (0 === count(array_reduce(array_keys($source),
function($in, $key){ unset($in[array_search($key, $in)]); return $in; },
['story', 'message', '…'])))
{
// all keys found
} else {
// not all
}
Harder to read, easy to change. array_reduce() uses a callback to iterate over an array to arrive at a value. By feeding the keys we're interested in the $initial value of $in and then removing keys found in source we can expect to end with 0 elements if all keys were found.
The construction is easy to modify since the keys we're interested in fit nicely on the bottom line.
array_filter & in_array
if (2 === count(array_filter(array_keys($source), function($key) {
return in_array($key, ['story', 'message']); }
)))
{
// all keys found
} else {
// not all
}
Simpler to write than the array_reduce solution but slightly tricker to edit. array_filter is also an iterative callback that allows you to create a filtered array by returning true (copy item to new array) or false (don't copy) in the callback. The gotchya is that you must change 2 to the number of items you expect.
This can be made more durable but verge's on preposterous readability:
$find = ['story', 'message'];
if (count($find) === count(array_filter(array_keys($source), function($key) use ($find) { return in_array($key, $find); })))
{
// all keys found
} else {
// not all
}
One more possible solution:
if (!array_diff(['story', 'message'], array_keys($array))) {
// OK: all the keys are in $array
} else {
// FAIL: some keys are not
}
It seems to me, that the easiest method by far would be this:
$required = array('a','b','c','d');
$values = array(
'a' => '1',
'b' => '2'
);
$missing = array_diff_key(array_flip($required), $values);
Prints:
Array(
[c] => 2
[d] => 3
)
This also allows to check which keys are missing exactly. This might be useful for error handling.
The above solutions are clever, but unnecessarily slow. A simple foreach loop over a few keys is much faster.
function array_keys_exist($keys, $array){
foreach($keys as $key){
if(!array_key_exists($key, $array)) {
return false;
}
}
return true;
}
If you have something like this:
$stuff = array();
$stuff[0] = array('story' => 'A story', 'message' => 'in a bottle');
$stuff[1] = array('story' => 'Foo');
You could simply count():
foreach ($stuff as $value) {
if (count($value) == 2) {
// story and message
} else {
// only story
}
}
This only works if you know for sure that you ONLY have these array keys, and nothing else.
Using array_key_exists() only supports checking one key at a time, so you will need to check both seperately:
foreach ($stuff as $value) {
if (array_key_exists('story', $value) && array_key_exists('message', $value) {
// story and message
} else {
// either one or both keys missing
}
}
array_key_exists() returns true if the key is present in the array, but it is a real function and a lot to type. The language construct isset() will almost do the same, except if the tested value is NULL:
foreach ($stuff as $value) {
if (isset($value['story']) && isset($value['message']) {
// story and message
} else {
// either one or both keys missing
}
}
Additionally isset allows to check multiple variables at once:
foreach ($stuff as $value) {
if (isset($value['story'], $value['message']) {
// story and message
} else {
// either one or both keys missing
}
}
Now, to optimize the test for stuff that is set, you'd better use this "if":
foreach ($stuff as $value) {
if (isset($value['story']) {
if (isset($value['message']) {
// story and message
} else {
// only story
}
} else {
// No story - but message not checked
}
}
What about this:
isset($arr['key1'], $arr['key2'])
only return true if both are not null
if is null, key is not in array
I use something like this quite often
$wantedKeys = ['story', 'message'];
$hasWantedKeys = count(array_intersect(array_keys($source), $wantedKeys)) > 0
or to find the values for the wanted keys
$wantedValues = array_intersect_key($source, array_fill_keys($wantedKeys, 1))
try this
$required=['a','b'];$data=['a'=>1,'b'=>2];
if(count(array_intersect($required,array_keys($data))>0){
//a key or all keys in required exist in data
}else{
//no keys found
}
This is the function I wrote for myself to use within a class.
<?php
/**
* Check the keys of an array against a list of values. Returns true if all values in the list
is not in the array as a key. Returns false otherwise.
*
* #param $array Associative array with keys and values
* #param $mustHaveKeys Array whose values contain the keys that MUST exist in $array
* #param &$missingKeys Array. Pass by reference. An array of the missing keys in $array as string values.
* #return Boolean. Return true only if all the values in $mustHaveKeys appear in $array as keys.
*/
function checkIfKeysExist($array, $mustHaveKeys, &$missingKeys = array()) {
// extract the keys of $array as an array
$keys = array_keys($array);
// ensure the keys we look for are unique
$mustHaveKeys = array_unique($mustHaveKeys);
// $missingKeys = $mustHaveKeys - $keys
// we expect $missingKeys to be empty if all goes well
$missingKeys = array_diff($mustHaveKeys, $keys);
return empty($missingKeys);
}
$arrayHasStoryAsKey = array('story' => 'some value', 'some other key' => 'some other value');
$arrayHasMessageAsKey = array('message' => 'some value', 'some other key' => 'some other value');
$arrayHasStoryMessageAsKey = array('story' => 'some value', 'message' => 'some value','some other key' => 'some other value');
$arrayHasNone = array('xxx' => 'some value', 'some other key' => 'some other value');
$keys = array('story', 'message');
if (checkIfKeysExist($arrayHasStoryAsKey, $keys)) { // return false
echo "arrayHasStoryAsKey has all the keys<br />";
} else {
echo "arrayHasStoryAsKey does NOT have all the keys<br />";
}
if (checkIfKeysExist($arrayHasMessageAsKey, $keys)) { // return false
echo "arrayHasMessageAsKey has all the keys<br />";
} else {
echo "arrayHasMessageAsKey does NOT have all the keys<br />";
}
if (checkIfKeysExist($arrayHasStoryMessageAsKey, $keys)) { // return false
echo "arrayHasStoryMessageAsKey has all the keys<br />";
} else {
echo "arrayHasStoryMessageAsKey does NOT have all the keys<br />";
}
if (checkIfKeysExist($arrayHasNone, $keys)) { // return false
echo "arrayHasNone has all the keys<br />";
} else {
echo "arrayHasNone does NOT have all the keys<br />";
}
I am assuming you need to check for multiple keys ALL EXIST in an array. If you are looking for a match of at least one key, let me know so I can provide another function.
Codepad here http://codepad.viper-7.com/AKVPCH
Hope this helps:
function array_keys_exist($searchForKeys = array(), $inArray = array()) {
$inArrayKeys = array_keys($inArray);
return count(array_intersect($searchForKeys, $inArrayKeys)) == count($searchForKeys);
}
This is old and will probably get buried, but this is my attempt.
I had an issue similar to #Ryan. In some cases, I needed to only check if at least 1 key was in an array, and in some cases, all needed to be present.
So I wrote this function:
/**
* A key check of an array of keys
* #param array $keys_to_check An array of keys to check
* #param array $array_to_check The array to check against
* #param bool $strict Checks that all $keys_to_check are in $array_to_check | Default: false
* #return bool
*/
function array_keys_exist(array $keys_to_check, array $array_to_check, $strict = false) {
// Results to pass back //
$results = false;
// If all keys are expected //
if ($strict) {
// Strict check //
// Keys to check count //
$ktc = count($keys_to_check);
// Array to check count //
$atc = count(array_intersect($keys_to_check, array_keys($array_to_check)));
// Compare all //
if ($ktc === $atc) {
$results = true;
}
} else {
// Loose check - to see if some keys exist //
// Loop through all keys to check //
foreach ($keys_to_check as $ktc) {
// Check if key exists in array to check //
if (array_key_exists($ktc, $array_to_check)) {
$results = true;
// We found at least one, break loop //
break;
}
}
}
return $results;
}
This was a lot easier than having to write multiple || and && blocks.
$colsRequired = ["apple", "orange", "banana", "grapes"];
$data = ["apple"=>"some text", "orange"=>"some text"];
$presentInBoth = array_intersect($colsRequired,array_keys($data));
if( count($presentInBoth) != count($colsRequired))
echo "Missing keys :" . join(",",array_diff($colsRequired,$presentInBoth));
else
echo "All Required cols are present";
Does this not work?
array_key_exists('story', $myarray) && array_key_exists('message', $myarray)
<?php
function check_keys_exists($keys_str = "", $arr = array()){
$return = false;
if($keys_str != "" and !empty($arr)){
$keys = explode(',', $keys_str);
if(!empty($keys)){
foreach($keys as $key){
$return = array_key_exists($key, $arr);
if($return == false){
break;
}
}
}
}
return $return;
}
//run demo
$key = 'a,b,c';
$array = array('a'=>'aaaa','b'=>'ccc','c'=>'eeeee');
var_dump( check_keys_exists($key, $array));
I am not sure, if it is bad idea but I use very simple foreach loop to check multiple array key.
// get post attachment source url
$image = wp_get_attachment_image_src(get_post_thumbnail_id($post_id), 'single-post-thumbnail');
// read exif data
$tech_info = exif_read_data($image[0]);
// set require keys
$keys = array('Make', 'Model');
// run loop to add post metas foreach key
foreach ($keys as $key => $value)
{
if (array_key_exists($value, $tech_info))
{
// add/update post meta
update_post_meta($post_id, MPC_PREFIX . $value, $tech_info[$value]);
}
}
$myArray = array('key1' => '', 'key2' => '');
$keys = array('key1', 'key2', 'key3');
$keyExists = count(array_intersect($keys, array_keys($myArray)));
Will return true, because there are keys from $keys array in $myArray
Something as this could be used
//Say given this array
$array_in_use2 = ['hay' => 'come', 'message' => 'no', 'story' => 'yes'];
//This gives either true or false if story and message is there
count(array_intersect(['story', 'message'], array_keys($array_in_use2))) === 2;
Note the check against 2, if the values you want to search is different you can change.
This solution may not be efficient, but it works!
Updates
In one fat function:
/**
* Like php array_key_exists, this instead search if (one or more) keys exists in the array
* #param array $needles - keys to look for in the array
* #param array $haystack - the <b>Associative</b> array to search
* #param bool $all - [Optional] if false then checks if some keys are found
* #return bool true if the needles are found else false. <br>
* Note: if hastack is multidimentional only the first layer is checked<br>,
* the needles should <b>not be<b> an associative array else it returns false<br>
* The array to search must be associative array too else false may be returned
*/
function array_keys_exists($needles, $haystack, $all = true)
{
$size = count($needles);
if($all) return count(array_intersect($needles, array_keys($haystack))) === $size;
return !empty(array_intersect($needles, array_keys($haystack)));
}
So for example with this:
$array_in_use2 = ['hay' => 'come', 'message' => 'no', 'story' => 'yes'];
//One of them exists --> true
$one_or_more_exists = array_keys_exists(['story', 'message'], $array_in_use2, false);
//all of them exists --> true
$all_exists = array_keys_exists(['story', 'message'], $array_in_use2);
Hope this helps :)
I usually use a function to validate my post and it is an answer for this question too so let me post it.
to call my function I will use the 2 array like this
validatePost(['username', 'password', 'any other field'], $_POST))
then my function will look like this
function validatePost($requiredFields, $post)
{
$validation = [];
foreach($requiredFields as $required => $key)
{
if(!array_key_exists($key, $post))
{
$validation['required'][] = $key;
}
}
return $validation;
}
this will output this
"required": [
"username",
"password",
"any other field"
]
so what this function does is validate and return all the missing fields of the post request.
// sample data
$requiredKeys = ['key1', 'key2', 'key3'];
$arrayToValidate = ['key1' => 1, 'key2' => 2, 'key3' => 3];
function keysExist(array $requiredKeys, array $arrayToValidate) {
if ($requiredKeys === array_keys($arrayToValidate)) {
return true;
}
return false;
}

Categories