If/Else Ternary Operator with Blank Else Statement Issue - php

Usually I can get away with using something like:
$a = ($condition)? array(1,2,3) : '';
But now I have a method that accepts a multidimensional array and I must pass or not pass one of the arrays conditionally.
$this->mymethod(
'myarrays'=> array(
array('key' => 'lang_code'),
array('key' => 'lang_description'),
array('key' => 'lang_direction'),
($mycondition==true)? array('key' => 'lang_export') : ),
)
);
Basically, the issue is with the last array passed. And more specifically the ELSE statement in the ternary If operator. It seems that I can't pass simply a blank space after the : and I can't pass anything else like FALSE or '' (empty string), because later on in the code the foreach that runs through this array gives errors.
My question is:
How to pass a parameter to a function/method based on a condition?

array_filter(array(
array('key' => 'lang_code'),
array('key' => 'lang_description'),
array('key' => 'lang_direction'),
$mycondition ? array('key' => 'lang_export') : null),
));
This will remove the null

Use:
$mycondition? array('key' => 'lang_export') : null
Now, you could simply run it through array_filter(..), to remove that NULL element.

Aim for readability, not for how can you type less. The ternary operator is great because in certain cases it increases readability. This is certainly not that case.
Be nice to the people reading your code later, including yourself.
Here is an example (comments are the thoughts of the future reader):
//OK, so here we have an array
$array = array(
array('key' => 'lang_code'),
array('key' => 'lang_description'),
array('key' => 'lang_direction'),
);
//So the array can have one more element based on this condition
if ($mycondition) {
$array[] = array('key' => 'lang_export');
}
//And then we pass this array to the method
$this->mymethod(array('myarrays' => $array));
You are free to use variables and don't have to write all your code in one statement (well, I must admit I thought that was cool earlier).

You could evaluate the condition before the function call, e.g. with a helper-function:
function evaluate_condition (array $mandatory, array $optional, $condition) {
if (true === $condition) {
$mandatory[] = $optional;
}
return $mandatory;
}
$this->mymethod(
'myarrays'=> $this->evaluate_condition(
array(
array('key' => 'lang_code'),
array('key' => 'lang_description'),
array('key' => 'lang_direction')
),
array('key' => 'lang_export'),
$mycondition
)
);

Related

array_diff_assoc() or foreach()? Which is faster?

I have two arrays, for example $session and $post with 100+ values. I will compare the $post array values with $session array. If post is different then it will be taken to result array else not.
We can try this using array_diff_assoc($post, $session) and foreach(). Which one is faster?
For profiling, Phil has suggested a great way in his reply, but I will link it here too, just in case:
Simplest way to profile a PHP script
Practically, you need to know what each approach does. in array_diff_assoc, you are returning the difference between 2 collections, after comparing the key/value couples for each element. It will then return an array that contains the entries from array1 that are not present in array2 or array3, etc.
In a for each loop, you will need to hard code the same function (assuming that's what you need). You will need to take the first element, then look for the combination in your other arrays. If it matches your requirements, you will save it into your output array, or even print it directly.
Same principles apply, but then again, it will be up to profiling to determine the faster approach. Try doing so on a large number of big arrays, as the difference isn't noticeable at smaller scales.
I'll leave this as a stub/example, please edit, or use for profiling.
<?php
$before = [
'name' => 'Bertie',
'age' => '23'
];
$after = [
'name' => 'Harold',
'age' => '23',
'occupation' => 'Bus driver'
];
function changed_1($after, $before) {
return array_diff_assoc($after, $before);
}
function changed_2($after, $before) {
$changed = [];
foreach($after as $k => $v) {
if(isset($before[$k]) && $before[$k] !== $v)
$changed[$k] = $v;
if(!isset($before[$k]))
$changed[$k] = $v;
}
return $changed;
}
var_export(changed_1($after, $before));
var_export(changed_2($after, $before));
Output:
array (
'name' => 'Harold',
'occupation' => 'Bus driver',
)array (
'name' => 'Harold',
'occupation' => 'Bus driver',
)

Remove deeply nested element from multi-dimensional array?

I need to remove an element form a deeply nested array of unknown structure (i.e. I do not know what the key sequence would be to address the element in order to unset it). The element I am removing however does have a consistent structure (stdObject), so I can search the entire multidimensional array to find it, but then it must be removed. Thoughts on how to accomplish this?
EDIT: This is the function I have right now trying to achieve this.
function _subqueue_filter_reference(&$where)
{
foreach ($where as $key => $value) {
if (is_array($value))
{
foreach ($value as $filter_key => $filter)
{
if (isset($filter['field']) && is_string($filter['field']) && $filter['field'] == 'nodequeue_nodes_node__nodequeue_subqueue.reference')
{
unset($value[$filter_key]);
return TRUE;
}
}
return _subqueue_filter_reference($value);
}
}
return FALSE;
}
EDIT #2: Snipped of array structure from var_dump.
array (size=1)
1 =>
array (size=3)
'conditions' =>
array (size=5)
0 =>
array (size=3)
...
1 =>
array (size=3)
...
2 =>
array (size=3)
...
3 =>
array (size=3)
...
4 =>
array (size=3)
...
'args' =>
array (size=0)
empty
'type' => string 'AND' (length=3)
...so assuming that this entire structure is assigned to $array, the element I need to remove is $array[1]['conditions'][4] where that target is an array with three fields:
field
value
operator
...all of which are string values.
This is just a cursor problem.
function recursive_unset(&$array)
{
foreach ($array as $key => &$value) # See the added & here.
{
if(is_array($value))
{
if(isset($value['field']) && $value['field'] == 'nodequeue_nodes_node__nodequeue_subqueue.reference')
{
unset($array[$key]);
}
recursive_unset($value);
}
}
}
Notes : you don't need to use is_string here, you can just make the comparison as you're comparing to a string and the value exists.
Don't use return unless you're sure there is only one occurrence of your value.
Edit :
Here is a complete example with an array similar to what you showed :
$test = array (
1 => array (
'conditions' =>
array (
0 => array ('field' => 'dont_care1', 'value' => 'test', 'operator' => 'whatever'),
1 => array ('field' => 'dont_care2', 'value' => 'test', 'operator' => 'whatever'),
2 => array ('field' => 'nodequeue_nodes_node__nodequeue_subqueue.reference', 'value' => 'test', 'operator' => 'whatever'),
3 => array ('field' => 'dont_care3', 'value' => 'test', 'operator' => 'whatever')
),
'args' => array (),
'type' => 'AND'
));
var_dump($test);
function recursive_unset(&$array)
{
foreach ($array as $key => &$value)
{
if(is_array($value))
{
if(isset($value['field']) && $value['field'] == 'nodequeue_nodes_node__nodequeue_subqueue.reference')
{
unset($array[$key]);
}
recursive_unset($value);
}
}
}
recursive_unset($test);
var_dump($test);
One way to solve this was to extend your recursive function with a second parameter:
function _subqueue_filter_reference(&$where, $keyPath = array())
You'd still do the initial call the same way, but the internal call to itself would be this:
return _subqueue_filter_reference($value, array_merge($keyPath, array($key)));
This would provide you with the full path of keys to reach the current part of the array in the $keyPath variable. You can then use this in your unset. If you're feeling really dirty, you might even use eval for this as a valid shortcut, since the source of the input you'd give it would be fully within your control.
Edit: On another note, it may not be a good idea to delete items from the array while you're looping over it. I'm not sure how a foreach compiles but if you get weird errors you may want to separate your finding logic from the deleting logic.
I have arrived at a solution that is a spin-off of the function found at http://www.php.net/manual/en/function.array-search.php#79535 (array_search documentation).
Code:
function _subqueue_filter_reference($haystack,&$tree=array(),$index="")
{
// dpm($haystack);
if (is_array($haystack))
{
$result = array();
if (count($tree)==0)
{
$tree = array() + $haystack;
}
foreach($haystack as $k=>$current)
{
if (is_array($current))
{
if (isset($current['field']) && is_string($current['field']) && $current['field'] == 'nodequeue_nodes_node__nodequeue_subqueue.reference')
{
eval("unset(\$tree{$index}[{$k}]);"); // unset all elements = empty array
}
_subqueue_filter_reference($current,$tree,$index."[$k]");
}
}
}
return $tree;
}
I hate having to use eval as it SCREAMS of a giant, gaping security hole, but it's pretty secure and the values being called in eval are generated explicitly by Drupal core and Views. I'm okay with using it for now.
Anyway, when I return the tree I simply replace the old array with the newly returned tree array. Works like a charm.

Check if an array value exist

$city = $_GET['cityselect'];
add_query_arg( array ( 'city' => $city, 'key' => 'value' );
Basically i want to check if $city exists and if not i want to remove both key and value, ie 'city' => $city, (comma included). So the output would be:
add_query_arg( array ( 'key' => 'value' );
Any idea?
Only add the city key if it is set, like this:
$arg = array( 'key' => 'value');
if( isset( $_GET['cityselect']))
$arg['city'] = $_GET['cityselect'];
add_query_arg( $arg);
try this
$data = array();
if(isset($_GET["cityselect"])){
$data["city"] = $_GET["cityselect"];
}
add_query_arg($data); // ..
For the short but ugly one-liner version:
add_query_arg($args = (!empty($_GET['cityselect'])) ? array('city' => $_GET['cityselect'], 'key' => 'value') : array('key' => 'value');
Slightly more elegant:
if(!empty($_GET['cityselect']))
add_query_arg(array('city' => $_GET['cityselect'], 'key' => 'value'));
else
add_query_arg(array('key' => 'value'));
Have assumed use of empty, but substitute for isset if applicable to your circumstances.
If you're attempting to remove city if it doesn't exist, you could do:
$city = isset($_GET['cityselect']) ? $_GET['cityselect'] : null;
if (empty($city)) unset($yourArray['city']);
This assumes you already have an array, $yourArray, pre-defined with a city index.
I would recommend to only insert the city index after you've verified it though, such as:
if (isset($_GET['cityselect']) && !empty($_GET['cityselect'])) {
$yourArray['city'] = $_GET['cityselect'];
}
UPDATE: You could also use array_filter() to remove all indexes with missing values after you're done populating it:
$yourArray = array_filter($yourArray);
This will return an array with all empty values stripped; In your case, if city is empty it will be removed from the array.
You can use array_search() (Searches the array for a given value and returns the corresponding key if successful).

Add some logic in array filing

I'm trying to fill an array and I want to add some logic in it so it won't give me back errors...
Here is the code:
$entries_mixes = array();
foreach ($entries_query->result_array() as $entry) {
$entries_mixes[] = array('title' => $entry['title'],
'body' => $entry['body'],
'author' => $entry['author'],
'date_time' => $entry['date_time'],
'id' => $entry['id'],
'mix_name' => $mix['name'],
'photo_name' =>$photo['name']
);
}
what I want to do is to be able to check if some of the variables exist before I put them into the array....
so for example if(isset($mix['name'])) then insert to array or else do nothing
The point is not having undeclared variables trying to be inserted to my array cause it gives back errors...thanks!
You can use the ? : ternary operator:
$entries_mixes[] = array(
'title' => (isset($entry['title']) ? $entry['title'] : null),
'author' => (isset($entry['author']) ? $entry['author'] : null),
...
alternatively, use empty() for the check
You could use the ternary operator so that if the variables don't exist, NULL is used as the value. But you actually want to omit certain keys from the array altogether in that case. So just set each key separately:
$entry[] = array();
...
if (isset($mix['name'])) {
$entry['mix_name'] = $mix['name'];
}
...
$entries_mixes[] = $entry;
The following will check if title doesn't exists in the entry array or if it's blank. If so, it'll skip the entry completely and continue to the next element in the loop.
$entries_mixes = array();
foreach ($entries_query->result_array() as $entry) {
if (empty($entry['title'])) {
continue;
}
$entries_mixes[] = array('title' => $entry['title'],
'body' => $entry['body'],
'author' => $entry['author'],
'date_time' => $entry['date_time'],
'id' => $entry['id'],
'mix_name' => $mix['name'],
'photo_name' =>$photo['name']
);
}

Need help about array

What do
$categories[$id] = array('name' => $name, 'children' => array());
and
$categories[$parentId]['children'][] = array('id' => $id, 'name' => $name);
mean?
Thanks a lot.
How should i format the output so i can learn the results that was returned?
You can format your code into tables by looping on the array using for or foreach. Read the docs for each if you don't have a grasp on looping.
2.What does
$categories[$id] = array('name' => $name, 'children' => array());
and
$categories[$parentId]['children'][] = array('id' => $id, 'name' => $name);
The first line assigns an associative array to another element of the $categories array. For instance if you wanted the name of the category with ID of 6 it would look like this:
$categories[6]['name']
The second line does something similar, except when you are working with an array in PHP, you can use the [] operator to automatically add another element to the array with the next available index.
What is the uses of .= ?
This is the concatenation assignment operator. The following two statements are equal:
$string1 .= $string2
$string1 = $string1 . $string2
These all have to do with nesting arrays.
first example:
$categories[$id] = array('name' => $name, 'children' => array());
$categories is an array, and you are setting the key id to contain another array, which contains name and another array. you could accomplish something similar with this:
$categories = array(
$id => array(
'name' => $name,
'children' => array()
)
)
The second one is setting the children array from the first example. when you have arrays inside of arrays, you can use multiple indexes. It is then setting an ID and Name in that array. here is a another way to look at example #2:
$categories = array(
$parentID => array(
'children' => array(
'id' = $id,
'name' => $name
)
)
)
note: my two ways of rewriting are functionally identical to what you posted, I'm just hoping this makes it easier to visualize what's going on.

Categories