I am having the darndest time figuring out how to use a foreach inside a function.I have rewritten my code down to the simplest form and still cannot get it to run. This is the simple version of what I am trying to do:
$arr = array("first","second","third");
function myFunction(){
foreach($arr as $val){
echo $val.' | ';
}
}
myFunction();
I know the solution must be one of those "doh" moments but I must risk embarrassment 'cause I can't get it...
In PHP global variables need to be said inside the function. You simply need to say you using a global variable otherwise PHP won't know. So you just need to add global $arr; like so:
$arr = array("first","second","third");
function myFunction(){
global $arr; // <-- This states we are using the $arr defined globally.
foreach($arr as $val){
echo $val.' | ';
}
}
myFunction();
$arr = array("first","second","third");
function myFunction($target){
foreach($target as $val){
echo $val.' | ';
}
}
myFunction($arr);//$arr will send to function for process
Have a try!
You can also pass array to the function.
$arr = array("first","second","third");
function myFunction($arr){
foreach($arr as $val){
echo $val.' | ';
}
}
myFunction($arr);
Related
I tries to use multidimensional global arrays in PHP. Unfortunately, so far I don't know how to do it...
global $datawords;
function unfold_sentence($str)
{
$sentence_arr = preg_split('/[.?!]/',$str);
$i=0;
foreach ($sentence_arr as $value) {
$i++;
$datawords['sentence'][$i]['sentence'] = $value;
$datawords['sentence'][$i]['words'] = preg_split( '/[-?!.,;: ]+/', $value);
}
}
unfold_sentence("hello! how are you?");
print_r($datawords['sentence'][1]['sentence']); //empty echo
I tried to use $GLOBALS - instead of $datawords - unsuccessfully.
global is a keyword that you would use in the function where you want to reference the global variable. The PHP documentation gives an example for using the global keyword, and states:
By declaring $a and $b global within the function, all references to either variable will refer to the global version.
Note that you can have $i generated by the foreach loop itself.
So it should be:
function unfold_sentence($str)
{
global $datawords;
$sentence_arr = preg_split('/[.?!]/',$str);
foreach ($sentence_arr as $i => $value) {
$datawords['sentence'][$i]['sentence'] = $value;
$datawords['sentence'][$i]['words'] = preg_split( '/[-?!.,;: ]+/', $value);
}
}
PHP seems very inconsistent and (compiler) fails to generate the logic. Let's start our investigation, first with a simple set of JSON data.
[
{
"customer": "cust01",
"assembly": "assem01",
"date_received": "02-08-2015",
"time_received": "09:15",
"date_completed": "02-23-2015",
"time_completed": "10:27"
},
{
"customer": "lov_01",
"assembly": "lov_02",
"date_received": "lov_03",
"time_received": "lov_04",
"date_completed": "lov05",
"time_completed": "lov_06"
}
]
Then in the PHP, we retrieve an array of that data
$t_json_string = file_get_contents($t_json_file_path);
$t_json_arr = json_decode($t_json_string, true);
Assume we retrieve post values in an array like this
$t_new_entry = [
"customer" => "lov_01",
"assembly" => "lov_02",
"date_received" => "lov_03",
"time_received" => "lov_04",
"time_completed"=> "lov_05",
"time_completed"=> "lov_06"
];
and the goal is to verify as if new entry exists in the json array yet, by a condition whether both arrays have more than 2 similar values, for that I'm using $t_count to count the number of similar occurrences.
I wrote up 2 methods for checking that while passing the same data into the data pool.
// $t_boo = $db_entry_check($t_new_entry, $t_json_arr); echo $t_boo;
// true, $t_count shows 3.
$t_bool = $db_entry_exist($t_new_entry, $t_json_arr); echo $t_bool;
// False. It has to be true with the $t_count printed out at 3.
The first one employs call_user_function_array, which I tested and it works so I commented it out. Code for it here:
$db_entry_check = function($needle, $haystack){
$t_exist = 'false';
$t_count = 0;
function h_loop (&$t_count, $value, $array){
foreach ($array as $key => $val){
if (is_array($val)){
h_loop($t_count, $value, $val);
} else {
echo "<br/> --- value: ". $value. "<br/> --- val: ". $val . "<br/><br/>";
if ($val === $value){
$t_count += 1;
echo "<br/>" . $t_count . "<br/>";
continue;
}
}
}
}
function n_loop (&$t_count, $arr, $array){
foreach ($arr as $key => $value){
if (is_array($value)){
n_loop($t_count, $value, $array);
} else {
if ($t_count > 2) continue;
call_user_func_array('h_loop', [&$t_count, $value, $array]);
}
}
}
n_loop($t_count, $needle, $haystack);
echo "<br/>" . $t_count . "<br/>";
if ($t_count > 2) $t_exist = 'true';
return $t_exist;
};
The second one is my attempt to use lambdas on every component functions. I tried playing around putting $value, $array, and $t_count into use() part as those variables exist within the scope of $db_entry_exist for data binding & dependencies injection. When it comes to considering parameters (for the function) vs dependencies (for the use) Of the h_loop, I find it confusing, what an entire mess in PHP efforts to implement concepts of Javascript.
No matter what parameters I am passing onto the function part and no matter what variables got injected in the use() part. Many variations have been tested but none of them work. I usually get an error of 'Function name must be a string'. Invoking a closure within another closure in PHP seems not working as the logic in Javascript. It fails me whenever I tries to pass $h_loop($t_count, $value, $array); or echo $factorial(5); in the else part of the n_loop function. What I don't understand is that $db_entry_exist itself is a lambda (Closure as what PHP calls it) and n_loop function can be called inside without any error but calling/invoking a grandchild (h_loop) function by the same approach does not work, often resulting in the same error above.
$db_entry_exist = function($needle, $haystack){
$t_exist = 'false';
$t_count = 0;
// n_loop($t_count, $needle, $haystack);
$h_loop = function (&$t_count, $value, $array) use (&$h_loop) {
foreach ($array as $key => $val){
if (is_array($val)){
h_loop($t_count, $value, $val);
} else {
echo "<br/> --- value: ". $value. "<br/> --- val: ". $val . "<br/><br/>";
if ($val === $value){
$t_count += 1;
echo "<br/>" . $t_count . "<br/>";
continue;
}
}
}
};
$factoral = function($n) use (&$factoral) {
if ($n <= 1)
return 1;
else
return $n * $factoral($n - 1);
}; // source: https://gist.github.com/superic/8290704
$n_loop = function (&$t_count, $arr, $array) use (&$n_loop) {
foreach ($arr as $key => $value){
if (is_array($value)){
$n_loop($t_count, $value, $array);
} else {
if ($t_count > 2) continue;
$h_loop($t_count, $value, $array);
}
}
};
/*$n_loop = function ($arr, $array) use (&$n_loop, &$t_count){
// echo "<br/> --- nloop.t_count: " . $t_count . "<br/>";
foreach ($arr as $key => $value){
if (is_array($value)){
$n_loop($value);
} else {
if ($t_count > 2) continue;
// $h_loop($value, $array);
}
}
};*/
$n_loop($t_count, $needle, $haystack);
echo "<br/>" . $t_count . "<br/>";
if ($t_count > 2) $t_exist = 'true';
return $t_exist;
};
and here is the link to view my entire code:
<script src="http://ideone.com/e.js/YjLkZF" type="text/javascript" ></script>
To sum up, there are primarily 2 issues I don't understand and can't figure:
$n_loop is invoked fine within $db_entry_exist method but $h_loop isn't.
In the context of $db_entry_exist, how to pass and pass what variables to the function() and pass what as dependencies to the use() part.
$n_loop = function (&$t_count, $arr, $array) use (&$n_loop){}
// ------ OR ------- many other variations are there too.
$n_loop = function ($arr, $array) use (&$n_loop, &$t_count){}
Please investigate the code and let me know your thoughts. Thank you.
You have two misconceptions in your code that are affecting your understanding.
First: PHP does not actually have nested functions. When you say:
function outer()
{
function foo() {}
function bar() {}
}
what you are really saying is, when outer() is called, define foo() and bar() in the global scope. This means that once you call outer() once, anyone (not just outer()) can call foo() and bar(). This also means that calling outer() a second time results in a Cannot redeclare foo() error.
Second: Closures in PHP do not automatically close over any variables in their parent scope. Any variables intended to be part of the closure must be explicitly included in the use() list. This means that when you write:
$n_loop = function (&$t_count, $arr, $array) use (&$n_loop) {
//...
$h_loop($t_count, $value, $array);
//...
};
the call to $h_loop will always fail, because in the scope of that function, there is no variable named $h_loop. If you add $h_loop to your use() list, then you will be able to call it as expected.
I'm curious, how does the PHP's function extract do it's work? I would like to make a slightly modified version. I want my function to make the variable names when extracting from the keys of the array from snake notation to camelCase e.g:
Now extract does this:
$array = ['foo_bar' => 'baz'];
extract($array);
// $foo_bar = 'baz';
What I would like is:
camelExtract($array);
// $fooBar = 'baz';
Now I could of course camelCase the array first, but it would be nice if this could be done in a single function.
edit:
It seems some people misread my question. Yes I could do this:
function camelExtract($array)
{
$array = ['foo_bar' => 'baz'];
$camelCased = [];
foreach($array as $key => $val)
{
$camelCased[camelcase($key)] = $val;
}
extract($camelCased);
// $fooBar = 'baz';
// I can't "return" the extracted variables here
// .. now $fooBar is only available in this scope
}
camelExtract($array);
// Not here
But as I've stated, then the $fooBar is only visible within that scope.
I guess I could do something as extract(camelCaseArray($array)); and that would work.
This should work:-
function camel(array $arr)
{
foreach($arr as $a => $b)
{
$a = lcfirst(str_replace(" ", "", ucwords(str_replace("_", " ", $a))));
$GLOBALS[$a] = $b;
}
}
You can (cautiously) use variable variables:
function camelExtract($vals = array()) {
foreach ($vals as $key => $v) {
$splitVar = explode('_', $key);
$first = true;
foreach ($splitVar as &$word) {
if (!$first) {
$word = ucfirst($word);
}
$first = false;
}
$key = implode('', $splitVar);
global ${$key};
${$key} = $v;
}
}
This has now been tested and functions as expected. This condensed answer (after it addressed the lowercase first word) also works great and is much more condensed - mine is just a little more of a "step by step" to work through how the camel is done.
extract, and modification to the callees local symbol table from within a called function is magic. There is no way to perform the equivalent in plain-PHP without using it.
The final task can be solved using John Conde's suggesting of using extra after performing a transformation to the supplied array keys; although my recommendation is to avoid extract-like behavior entirely. The approach would then look similar to
extract(camelcase_keys($arr));
where such code is not wrapped in a function so that extract is executed from the scope of the symbol table in which to import the variables.
This extract behavior is is unlike variable-variables (in a called function) and is unlike using $GLOBALS as it mutates the callees (and only the callees) symbol table as see seen in this demo:
function extract_container () {
extract(array("foo" => "bar"));
return $foo;
}
echo "Extract: " . extract_container() . "\n"; // "bar" =>
echo "Current: " . $foo . "\n"; // => {no $foo in scope}
echo "Global: " . $GLOBALS['foo'] . "\n"; // => {no 'foo' in GLOBALS}
The C implementation for extract can be found in ext/standard/array.c. This behavior is allowed because the native function does not create a new/local PHP symbol table for itself; as such it is allowed to (trivially) modify the symbol table of the calling PHP context.
<?php
$arr = array('foo_bar'=>'smth');
function camelExtract($arr) {
foreach($arr as $k=>$v) {
$newName = lcfirst(str_replace(" ","",ucwords(str_replace("_"," ",$k))));
global $$newName;
$$newName = $v;
//var_dump($newName,$$newName);
}
}
camelExtract($arr);
?>
or just like (t's what you suggest, and better to mimic the original extract)
$camelArray[lcfirst(str_replace(" ","",ucwords(str_replace("_"," ",$k))))] = $v;
and extract on the resulting camelArray
Is there a function that works like $_GET ?
I mean a function that transforms
"?var1=5&var2=true"
to
$var1=5;
$var2="true";
So that I can use one variable (string) in a function and fetch many variables from it?
Like:
function manual_GET($args){ /* ? */}
function myFunction($args)
{
manual_GET($args);
if(isset($var1))/* doesn't have to be this way, btw */
{
do_something($var1);
}
//etc
}
p.s. : I don't want to use $_GET with URL because this file is a class file (namely database_library.php) so I don't execute it directly, or make an AJAX call. I just require_once(); it.
Yes, there is. It is called parse_str: http://php.net/manual/en/function.parse-str.php
One way to fix it.
function myFunction($args){
return parse_str($args,$values);
}
function parseQueryString($str) {
$op = array();
$pairs = explode("&", $str);
foreach ($pairs as $pair) {
list($k, $v) = array_map("urldecode", explode("=", $pair));
$op[$k] = $v;
}
return $op;
}
it works like parse_str but doesn't convert spaces and dots to underscores
"?var1=5&var2=true"
foreach ($_GET AS $k=>$v){
$$k=$v;
}
echo $var1; // print 5
echo $var2; // print true
Im working on a new minimal Project, but i've got an error, i dont know why.
Normally, i use arrays after i first created them with $array = array();
but in this case i create it without this code, heres an example full code, which outputs the error:
<?php $i = array('demo', 'demo'); $array['demo/demodemo'] = $i; ?>
<?php $i = array('demo', 'demo'); $array['demo/demodemo2'] = $i; ?>
<?php
foreach($array as $a)
{
echo $a[0] . '<br>';
}
function echo_array_demo() {
foreach($array as $a)
{
echo $a[0] . '<br>';
}
}
echo_array_demo();
?>
I create items for an array $array and if i call it (foreach) without an function, it works. But if i call in in a function, then the error comes up...
I ve got no idea why
Thank you...
Functions have their own variable scope. Variables defined outside the function are not automatically known to it.
You can "import" variables into a function using the global keyword.
function echo_array_demo() {
global $array;
foreach($array as $a)
{
echo $a[0] . '<br>';
}
}
Another way of making the variable known to the function is passing it as a reference:
function echo_array_demo(&$array) {
foreach($array as $a)
{
echo $a[0] . '<br>';
}
}
echo_array_demo($array);
Check out the PHP manual on variable scope.