PHP: less ugly syntax for named parameters / arrays? - php

Here's what I am trying to accomplish:
function foo($args) {
switch($args['type']) {
case 'bar':
bar($args['data']); // do something
break;
}
}
// or something like that
Which is basically a way of using named parameters in PHP.
Now, in order to build this $args array, I am forced to write ugly syntax like:
$builtArgs = array('type' => 'bar',
'data' => array(1, 2, 3),
'data2' => array(5, 10, 20)
);
foo($builtArgs);
Which gets uglier as I add more dimensions to the array, and also forces me to write tons of array(...) constructs. Is there a prettier way to do this?
For one thing, it could be done if we could use Python-like syntax:
$buildArgs = {'type' : 'bar', 'data' : [1, 2, 3], 'data2' : [5, 10, 20]};
But it is PHP.

You could create a JSON-encoded string and use json_decode() to convert it into a variable. This has syntax very similar to the Python-like syntax you mentioned.
$argstr = '{"type" : "bar", "data" : [1, 2, 3], "data2" : [5, 10, 20]}';
$buildArgs = json_decode($argstr, true);
EDIT: Updated code to accommodate #therefromhere's suggestion.

No. Alternative syntaxes for creating arrays have been proposed several times (the link lists 5 separate threads in the dev mailing list), but they were rejected.

No, there is no "short-syntax" to write arrays nor objects, in PHP : you have to write all those array().
(At least, there is no such syntax... yet ; might come in a future version of PHP ; who knows ^^ )
But note that have too many imbricated arrays like that will makes things harder for people who will have to call your functions : using real-parameters means auto-completion and type-hinting in the IDE...

There are no alternatives to constructing these nested arrays-- but there are options in how you can format your code that makes it readable. This is strictly preference:
return array
(
'text' => array
(
'name' => 'this is the second',
'this' => 'this is the third',
'newarr' => array
(
'example'
),
)
);
// Or using the long way
$array = array();
$array += array
(
'this' => 'is the first array'
);

Related

If the function only use a part of array, should I pass this part of array or whole array as the argument?

Just like following:
// situation1: pass whole array, and function use a part of this array.
function funcA1($array) {
return $array['a']['a1'];
}
// situation2: pass $array['a'];
function funcA2($array) {
return $array['a1'];
}
$a = ['a' => ['a1' => 1, 'a2' => 2], 'b' => 2, 'c' => 3];
$situation1 = funcA1($a);
$situation2 = funcA2($a['a']);
I think situation1 use more memory, but it's simple to use, and situation2 use less memory, but difficult to use. Is it right?
In the case of the array is very large and the funciton will be called for a lot of times, what solution should I choose, or other solution? And Why?

PHP - merge only keys of an array?

Let's say I have a PHP array:
$array1 = array(
'protein' => array('PROT', 100, 150),
'fat' => array('FAT', 100, 250),
'carbs' => arary('CARBS', 10, 20)
);
$array2 = array(
'vitaminA' => array('vitA', 1, 2),
'vitaminB' => array('vitB', 1, 2),
'vitaminC' => arary('vitC', 1, 2)
);
Now I want a combined array of those nutrients (something like array_merge()), but I only need the keys, not the values themselves.
So either this:
$combined = array(
'protein' => NULL,
'fat' => NULL,
'carbs' => NULL,
'vitaminA'=> NULL,
'vitaminB'=> NULL,
'vitaminC'=> NULL
);
OR
$combined = array('protein', 'fat', 'carbs', 'vitaminA', 'vitaminB', 'vitaminC');
I can do this manually with a foreach loop, but I was hoping there's a function which would make this process fast and optimized.
Wouldn't this do the trick?
$combined = array_merge(array_keys($array1), array_keys($array2));
This would result in your option #2.
I haven't done any benchmarks but I know that isset() is faster than in_array() in many cases; something tells me that it will be the same for isset() versus array_key_exists(). If it matters that much, you could try to use this:
$combined = array_flip(array_merge(array_keys($array1), array_keys($array2)));
Which would result in something like this:
$combined = array(
'protein' => 1,
'fat' => 2,
'carbs' => 3,
'vitaminA'=> 4,
'vitaminB'=> 5,
'vitaminC'=> 6
);
That would allow you to use isset(), e.g. option #1.
#edit I did some research on the performance of all three mentioned functions and most, if not all, case studies show that isset() is the fastest of all (1, 2); mainly because it is not actually a function but a language construct.
However do note that we now use array_flip() to be able to use isset(), so we lose quite a few microseconds to flip the array; therefore the total execution time is only decreasing if (and only if) you use isset() quite often.
This:
function array_merge_keys($arr1, $arr2) {
return array_merge(array_keys($arr1), array_keys($arr2));
}
should do the trick.

Efficient array value replacement

I have an array of values in PHP looking something like this:
$test = array (
array( 'val' => 2, 'color' => 'blue' ),
array( 'val' => 5, 'color' => 'green' ),
);
I want to go through all elements of $test and add 1 to all val indices. Now I realize a foreach loop could work, but I am looking for something a little more efficient. The array will potentially have 10's of thousands of elements and hundreds of sub-elements.
I am wondering if there is some type of way that PHP can go through and modify just that index throughout the entire array, based on the argument that I set.
you can use array_walk and a closure to do it
array_walk($yourArray,function(&$col){$col['val']++});

How to pass an array via $_GET in php?

How can I pass one or more variables of type array to another page via $_GET?
I always passed variable values in the form ?a=1&b=2&c=3
What about passing a=[1,2,3] ?
Do I need to write a for loop and append all the values?
Thanks
You can use the [] syntax to pass arrays through _GET:
?a[]=1&a[]=2&a[]=3
PHP understands this syntax, so $_GET['a'] will be equal to array(1, 2, 3).
You can also specify keys:
?a[42]=1&a[foo]=2&a[bar]=3
Multidimentional arrays work too:
?a[42][b][c]=1&a[foo]=2
http_build_query() does this automatically:
http_build_query(array('a' => array(1, 2, 3))) // "a[]=1&a[]=2&a[]=3"
http_build_query(array(
'a' => array(
'foo' => 'bar',
'bar' => array(1, 2, 3),
)
)); // "a[foo]=bar&a[bar][]=1&a[bar][]=2&a[bar][]=3"
An alternative would be to pass json encoded arrays:
?a=[1,2,3]
And you can parse a with json_decode:
$a = json_decode($_GET['a']); // array(1, 2, 3)
And encode it again with json_encode:
json_encode(array(1, 2, 3)); // "[1,2,3]"
Dont ever use serialize() for this purpose. Serialize allows to serialize objects, and there is ways to make them execute code. So you should never deserialize untrusted strings.
You can pass an associative array to http_build_query() and append the resulting string as the query string to the URL. The array will automatically be parsed by PHP so $_GET on the receiving page will contain an array.
Example
$query_str = http_build_query(array(
'a' => array(1, 2, 3)
));
$city_names = array(
'delhi',
'mumbai',
'kolkata',
'chennai'
);
$city_query = http_build_query(array('city' => $city_names));
this will give you:
city[0]=delhi&city[1]=mumbai&city[2]=kolkata&city[3]=chennai
if you want to encode the brackets also then use the below code:
$city_query = urlencode(http_build_query(array('city' => $city_names)));
Output:
city%255B0%255D%3Ddelhi%26city%255B1%255D%3Dmumbai .....
Reference: http_build_query, urlencode
Just repeat your $_GET variables like this: name=john&name=lea
This gives you an array.
I used to believe it would be overwritten!

Find intersecting rows between two 2d arrays comparing differently keyed columns

I have two arrays,
The $first has 5000 arrays inside it and looks like:
array(
array('number' => 1),
array('number' => 2),
array('number' => 3),
array('number' => 4),
...
array('number' => 5000)
);
and the $second has 16000 rows and looks like:
array(
array('key' => 1, 'val' => 'something'),
array('key' => 2, 'val' => 'something'),
array('key' => 3, 'val' => 'something'),
...
array('key' => 16000, 'val' => 'something'),
)
I want to create a third array that contains $second[$i]['val'] IF $second[$i][$key] is in $first[$i][$number]
currently I am doing:
$third = array();
foreach($first as &$f)
$f = $f['number'];
foreach($second as $s){
if(in_array($s['key'], $first)
$third[] = $s['val];
}
but, unless I use php's set_timeout(0) it is timing out, is there a more efficient way?
$third = array();
$ftemp = array();
foreach($first as $f)
$ftemp[$f['number']] = true;
foreach($second as $s){
if(isset($ftemp[$s['key']]))
$third[] = $s['val'];
}
should be waaay faster.
Don't try to make lookup dictionary in more convoluted way like below, because it actually is slower than above straightforward loop:
$third = array();
$ftemp = array_flip(reset(call_user_func_array('array_map', array_merge(array(null), $first))));
// $ftemp = array_flip(array_map('reset', $first)); // this is also slower
// array_unshift($first, null); $ftemp = array_flip(reset(call_user_func_array('array_map', $first))); // and this is even slower and modifies $first array
foreach($second as $s){
if(isset($ftemp[$s['key']]))
$third[] = $s['val'];
}
It's probably serious nitpicking but you could replace the foreach with a for which is a little faster, but i doubt that will make a big difference. You are working on a big dataset which might simply be not really fast to process on a webserver.
You are asking for "intersections" between the two arrays but on specific column keys which are not identical. Not to worry, PHP has a native function that is optimized under the hood for this task. array_uintersect() with no special data preparation. Within the custom callback function, null coalesce to the opposite array's key name. The reason for this fallback is because $a and $b do not represent array1 and array2. Because the intersect/diff family of native array functions sort while they filter, there may be instances where column values from the same array will be compared against each other. Again, this is part of the source code optimization.
Code: (Demo)
var_export(
array_uintersect(
$keyValues,
$numbers,
fn($a, $b) => ($a['number'] ?? $a['key']) <=> ($b['number'] ?? $b['key'])
)
);
As a general rule, though, if you are going to make a lot of array comparisons and speed matters, it is better to make key-based comparisons instead of value-based comparisons. Because of the way that PHP handles arrays as hashmaps, key-comparison functions/processes always outpace their value-comparing equivalent.
If you need to isolate the val column data after filtering, array_column() will fix this up for you quickly.

Categories