how to Extract variables without using extract()? - php

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.

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

Can't access global array outside of an if statement?

I am having some issues with setting a global array in php. The data I get from $_POST is straight from my database. I sent it through an external page to JSON decode/etc. (that part works, so I didnt paste the code). I only want to do this if data is set, then I want to take that array and do other things with it throughout the rest of my code. The problem I am having is the array outside of the if statement is null. I can't seem to figure out why? If I were to echo a var_dump inside the if statement, the values are inside the GLOBALS['Array']
function is_assoc($array) {
foreach (array_keys($array) as $k => $v) {
if ($k !== $v)
return true;
}
return false;
}
$GLOBALS['Array'] = array();
if (isset($_POST['data'])) {
$Data = $_POST['data'];
$decode = new JSONdecoder($Data);
$decode->decodeNew($Data);
$Data = $decode->decodedArray;
$decryptor = new DataDecryptor(base64_decode($_POST['key']), $_POST['tracking'], $hostName);
$decodedData = $decryptor->decrypt_arr($Data);
foreach($decodedData as $key => $val){
if(is_assoc($val)){
foreach($val as $key2 => $val2){
$theArray[$key2] = $val2;
}
}else{
$theArray[$key] = $val;
}
}
$GLOBALS['Array'] = $theArray;
}
echo var_Dump($Array);
Your issue is somewhere else. $GLOBALS is a superglobal variable accessible from any scope.
When you define a new entry in $GLOBALS, it automatically creates a variable holding the same name, but that variable is only visible in that particular scope. If you are in another scope and you want to initialize that as a variable, you need to use the global keyword : global $var; (look at the code below for an example - inside the test() function).
Are you sure 100% that you are always doing the same tests (Are you 100% positive that when testing, you are always entering the foreach statement?)
To clarify the behavior of $GLOBALS:
<?php
$GLOBALS['foo'] = 'bar';
var_dump($foo); // outputs 'bar'
if (true) {
$GLOBALS['foo'] = 'bar2';
}
var_dump($foo); // outputs 'bar2'
function test() {
var_dump($foo); // notice undefined variable - outputs NULL
var_dump($GLOBALS['foo']); // outputs 'bar2'
global $foo;
var_dump($foo); // outputs 'bar2';
}
test();

php extract() associative array when a function is called

I have this function:
function extractAvailable($assoc1, $assoc2){
if($assoc1) extract($assoc1);
else extract($assoc2);
}
What I expect is to call this function later in the global scope, and have my variables available, like so:
$arr1 = [];
$arr2 = ['one'=>1, 'two'=>'SecondItem'];
extractAvailable($arr1, $arr2);
With the call on extractAvailable(), I need to have the varialbes $one and $two available in the current scope. Obviously, I've got something wrongly figured concerning variable scope use here, 'cause it isn't working. When I try to use the variable, what I get instead is Notice: Undefined variable: one.
How do I get this to work?
You could add the new data to the $GLOBALS array which would have the effect of making them available in other scopes.
function extractAvailable($assoc1, $assoc2){
if($assoc1) {
foreach ($assoc1 as $key => $value) {
$GLOBALS[$key] = $value;
}
} else {
foreach ($assoc2 as $key => $value) {
$GLOBALS[$key] = $value;
}
}
}
But I have to wonder why you need to extract anything from a perfectly good array and place the exact same data into scalar variables.
All this does is double your memory requirement for no benefit whatsoever
If you want them to be available in the global scope, you can use variable variables instead of extract, and specify them as global.
function extractAvailable($assoc1, $assoc2){
if($assoc1) {
foreach ($assoc1 as $key => $value) {
global $$key;
$$key = $value;
}
} else {
foreach ($assoc2 as $key => $value) {
global $$key;
$$key = $value;
}
}
}

How can I use PHP 5.3 Closures like We use Blocks in Ruby

How can I use PHP 5.3 Closures like We use Blocks in Ruby.
I never used 'for' Loop in Ruby due to using Blocks with 'each' 'find_all' 'inject' Methods.
How can I use PHP 5.3 Closures like Ruby Blocks and say bye-bye to 'for' Loops :)
Like Between { and } is a Closure(or Block or Anonymous Function)
fruit = %w[apple banana orange]
fruit.each { |f| print "#{f}, " }
I do it in PHP this way,
$fruit = array('apple', 'banana', 'orange');
foreach ($fruit as $f)
{
print "$f, ";
}
Is there a way to do this the Ruby way using PHP Closures as PHP 5.3 supports it.
If you are looking at using lambdas to iterate over a PHP array, there are certain functions that you could use to accomplish that. Better illustrate it, I used a wrapper class enum:
class enum {
public $arr;
function __construct($array) {
$this->arr = $array;
}
function each($lambda) {
array_walk($this->arr, $lambda);
}
function find_all($lambda) {
return array_filter($this->arr, $lambda);
}
function inject($lambda, $initial=null) {
if ($initial == null) {
$first = array_shift($this->arr);
$result = array_reduce($this->arr, $lambda, $first);
array_unshift($this->arr, $first);
return $result;
} else {
return array_reduce($this->arr, $lambda, $initial);
}
}
}
$list = new enum(array(-1, 3, 4, 5, -7));
$list->each(function($a) { print $a . "\n";});
// in PHP you can also assign a closure to a variable
$pos = function($a) { return ($a < 0) ? false : true;};
$positives = $list->find_all($pos);
// inject() examples
$list = new enum(range(5, 10));
$sum = $list->inject(function($sum, $n) { return $sum+$n; });
$product = $list->inject(function($acc, $n) { return $acc*$n; }, 1);
$list = new enum(array('cat', 'sheep', 'bear'));
$longest = $list->inject(function($memo, $word) {
return (strlen($memo) > strlen($word)) ? $memo : $word; }
);
That being said, closures in PHP aren't meant to replace the for loop nor do they behave like ruby blocks.
I think array_map() and array_walk() look better as RubyBlocks replacement.
I don't think an anonymous function is a substitute for a for loop, nor do I think it's necessary to replace for loops with them.
What it is useful for is a callback. Take this for example:
(yes, it is a lame bubble sort, but it is an example)
<?php
function bubble_sort($sort_rule, $elements) {
do {
$swapped = false;
for ($i = 0; $i < count($elements) - 1; $i++) {
if ($sort_rule($elements[$i], $elements[$i + 1])) {
$elements[$i] ^= $elements[$i + 1];
$elements[$i + 1] ^= $elements[$i];
$elements[$i] ^= $elements[$i + 1];
$swapped = true;
}
}
} while($swapped);
return $elements;
}
print_r(bubble_sort(function ($a, $b) { if ($a > $b) return true; else return false; }
,array(1,6,3,7,42,-1,0,6)));
?>
Closures aren't a replacement for for loops in a procedural programming language like php. Sure if you're using lisp or scheme they are, but that's out of necessity.
You can write them that way, all you'll really be doing is creating an anonymous function with a for loop inside it. I think recursion would just be unnecessary if the task is just as easily accomplished with a for loop, and therefore you're not kissing for loops good bye.
Anonymous functions are very useful in event driven programming as well, when you want to just define a callback method really quick.
Simple answer: you don't. Ruby is not devoid of for() loops, they just mask the word "for" and change the syntax a bit. If you wanted to use a closure, it'd just be a closure with a loop inside it, or an ugly (and less efficient) recursive closure.
And closures are NOT the same thing as blocks. Closures are comparable to functions in JavaScript-- that is, they can be stored in variables and sent as arguments.

php: array_replace_recursive alternative

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

Categories