php: array_replace_recursive alternative - php

I need a solution for array_replace_recursive, because my php-version isn't high enough. I want to use this code:
$_GET = array_replace_recursive($_GET, array("__amp__"=>"&"));
easy, isn't it?

On the PHP docs page for array_replace_recursive, someone posted the following source code to use in place of it:
<?php
if (!function_exists('array_replace_recursive'))
{
function array_replace_recursive($array, $array1)
{
function recurse($array, $array1)
{
foreach ($array1 as $key => $value)
{
// create new key in $array, if it is empty or not an array
if (!isset($array[$key]) || (isset($array[$key]) && !is_array($array[$key])))
{
$array[$key] = array();
}
// overwrite the value in the base array
if (is_array($value))
{
$value = recurse($array[$key], $value);
}
$array[$key] = $value;
}
return $array;
}
// handle the arguments, merge one by one
$args = func_get_args();
$array = $args[0];
if (!is_array($array))
{
return $array;
}
for ($i = 1; $i < count($args); $i++)
{
if (is_array($args[$i]))
{
$array = recurse($array, $args[$i]);
}
}
return $array;
}
}
?>

The code above by #Justin is ok, save for 2 things:
Function is not readily available at start of php execution be cause it is wrapped in if(). PHP docu says
When a function is defined in a conditional manner such as the two examples shown. Its definition must be processed prior to being called.
Most importantly; calling the function twice results in fatal error.
PHP docu says
All functions and classes in PHP have the global scope - they can be called outside a function even if they were defined inside and vice versa.
So I just moved the recurse function outside array_replace_recursive function and it worked well. I also removed the if() condition and renamed it to array_replace_recursive_b4php53 for fear of future upgradings

Related

Anonymous function with dynamic number of arguments/parameters

So, some time ago I build a parser for jQuery Query Builder plugin, which parses the formula into PHP code that returns some calculation based on added parameters, it could range from return $a + $b; to something like
if($a == 'some_value' || $c == 'other_value') {
return $something;
} else if($b == 'something' && $d == 'anything') {
return $something_else;
} else {
return $anything;
}
and it could be even more complex. The thing is that it creates this as a string, which I then passed to another function which returns a dynamic function created with create_function, but that constructor in PHP is deprecated as of version 7.2.0.
My problem now is that I need to be able to create anonymous function with dynamic number of parameters, and those parameters need to have dynamic variable names. Here is my previous code
protected function createFunction($formula, &$data)
{
$args = '';
foreach($data as $key => $value) {
$args .= '$' . $key . ', ';
}
return create_function(substr($args, 0, strlen($args) - 2), $formula);
}
As you can see, the $formula is that dynamic PHP code I wrote above, and $data is an associative array (usually a row from database). Any ideas?
Edit: Forgot to mention, the formula itself is not the problem, as I can just use eval() function for that (I'm not concerned with security here so it's ok), it's just that I'm not sure how to add dynamic number of parameters with dynamic variable names.
You may go with Anonymous functions with this.
I had used eval in this case due to your comment :
Edit: Forgot to mention, the formula itself is not the problem, as I
can just use eval() function for that (I'm not concerned with security
here so it's ok)
class Foo
{
public function createFunction($formula, $args)
{
$func = function ($args) use ($formula) {
foreach ($args as $key => $val) {
$$key = $val;
}
return eval($formula);
};
return $func($args);
}
}
$foo = new Foo;
$foo->createFunction('echo $a + $b;', ['a' => 1, 'b' => 2]);
a live sample for your code
https://3v4l.org/HrMKN

Caching large arrays

I have following function:
function f($idx, $arr) {
static $a;
if ($a == NULL) {
foreach ($arr as $v) {
$key = $v['key'];
if (!isset($a[$key])) {
$a[$key] = array();
}
$a[$key][] = $v;
}
}
return $a[$idx];
}
And the initial conditions are:
function f() is called many-many times in 1 request
$arr is always very large
$arr may differ in different function calls (low cardinality)
$idx differs almost in every function call (high cardinality)
And now I need to know, if $arr is already cached and if not, then create this "cached version", but keep also all previous arrays.
According to 2. I'm not able to use md5(serialize($arr)) to use it as identifier, so I need another way to determine that. Do you have any idea how to achieve such hight-performance caching functionality (let's say I'm not able to do any changes outside this function)?
If it's not imperative that $arr not be modified, then I'd just add your optimized key access directly to it:
// note the argument has been changed to &$arr - we're passing by reference
function f($idx, &$arr) {
if (empty($arr['___cached'])) {
$arr['___cached'] = array();
foreach ($arr as $k => $v) {
if ($k === '___cached') continue;
if (!isset($arr['___cached'][$v['key']])) {
$arr['___cached'][$v['key']] = array();
}
$arr['___cached'][$v['key']][] = $v;
}
}
return $arr['___cached'][$idx];
}

how to Extract variables without using extract()?

I would like a function to export variables to the scope it's called within without using extract(), e.g.
function get_vars(){
$return['a'] = 1;
$return['b'] = 2
return $return;
}
and then rather than using :
exctract(get_vars());
I would just use
get_vars();
is there anyway available??
Saw that possible solution at the php manuel of the extract function.
(http://www.php.net/manual/en/function.extract.php#62727)
function free_args (&$V) {
foreach ($V as $k => &$v) {
$$k =& $v;
}
unset ($k); unset ($v); unset ($V);
// be careful that if you need to extract $k, $v or $V variables you should find other names for them in the lines above (ie. $__k, $__v and $__V)
}
You can try to use global keyword
function get_vars() {
global $a, $b;
$a = 1;
$b =2;
}
But as for me, it is a very weird approach. I prefer to use OOP.

abs of an array

Which is the easy way of getting the abs of an array in php? It has to be a better way. This works, but in multidimensional array it has some limitations
function make_abs($numbers) {
$abs_array = array();
foreach($numbers as $key=>$value)
$abs_array[$key] = abs($value);
return $abs_array;
}
Use a map function:
array_map("abs", $numbers)
http://php.net/manual/en/function.array-map.php
Your variant using references (this does not solve your recursion problem, just FYI):
function make_abs(&$numbers)
{
foreach($numbers as &$value)
$value = abs($value)
;
}
For the recursion problem, you need to step into each array:
function make_abs(&$numbers)
{
foreach($numbers as &$value)
is_array($value) ? make_abs($value) : $value = abs($value)
;
}
PHP itself has a somewhat handy function for that, array_walk_recursiveDocs. The problem with that function is, it expects the callback to have two parameters, value (by reference) and key. Many PHP functions do not fit those requirements. You can work around that by creating yourself a helper function to use any function that only takes one parameter and returns the modified value. You pass the function as with array_mapDocs:
function array_walk_recursive_map(array &$array, $callback)
{
$byRef = function(&$item, $key) use ($callback)
{
$item = $callback($item);
};
array_walk_recursive($array, $byRef);
}
# Usage:
array_walk_recursive_map($numbers, 'abs');
Hope this is helpful.
You could do array_walk_recursive($numbers, 'make_abs');
http://php.net/manual/en/function.array-walk-recursive.php
Edit
$numbers = array(1, 35, 107);
function make_abs(&$item,$key) { // use with reference
$item = abs($item);
}
array_walk_recursive($numbers, 'make_abs');
This example works with multidimensional arrays.

PHP global declaration

I'm using PHP's global declaration to make an array available to a number of functions in a script. The variable is declared at the top of the script and is referenced with global in each of the functions which uses it, as follows:
<?php
$myarray = array(1, 2, 3);
function print_my_array() {
global $myarray;
print '<ul>';
foreach($myarray as $entry) {
print '<li>'.$entry.'</li>';
}
print '</ul>';
return 0;
}
print_my_array();
?>
Sometimes, but not always, the array is not set when the function is called, generating an error when the foreach is called. In the actual code, the array used is given a very unique name and so should not be causing any collisions with anything else. Am I mis-using the global declaration?
No, the snippet is correct. The problem you're having is the problem of using global variables – they can be accessed and changed from anywhere (perhaps accidental), thereby creating hard-to-find bugs.
By using globals you can hit quite a few gotchas, they'll also make you code less reusable.
Here's an example of your function which can be re-used many times across the site.
(untested)
<?php
function arrayTags($items, $open = '<li>', $close = '</li>')
{
if (is_array($items) && count($items) != 0)
{
$output = null;
foreach ($items as $item) {
$output .= $open . $item . $close;
}
return $output;
}
else
{
return '';
}
}
// Default, <li>
echo '<ul>' . arrayTags($myarray) . '</ul>';
// or, spans:
echo '<div id="container">' . arrayTags($myarray, '<span>', '</span>') . '</div>';
The least you could do is check if the array is null at the top of the function, before you run the foreach. that would at least prevent the error:
function print_my_array() {
global $myarray;
if(!empty($myarray)) {
print '<ul>';
foreach($myarray as $entry) {
print '<li>'.$entry.'</li>';
}
print '</ul>';
}
}
Also, I wouldn't just return 0 for the hell of it. You may want to incorporate whether or not the array was empty into what you return from this function.
$myarray = array(1, 2, 3);
In short you have to only declare it like so:
$myarray = array();
and if you want to populate it with values do that in the class constructor:
public function __construct(){
$myarray = array(1,2,3);
}
I'm no guru, but in my experience it seems that php doesn't like to execute function calls outside of a function within a class.
THIS DOES NOT WORK:
class MyClass {
public $mystring = myfunction();
public function myFunction(){
return true; //and your function code
}
}
so when you use array() it doesn't actually trigger any function call, it just creats an empty variable of type array. when you use array(1,2,3), it has to effectively run the 'create array' which is like a function.
I know annoying, I'd like it to be different, but I don't know a way of doing what you want in php. Let me know if there is a nice way I'd love to hear it!

Categories