How do I pass a PHP function expecting varargs a string? - php

I have a PHP function which takes a variable number of arguments.
function foo() {
$numargs = func_num_args();
if ($numargs < 3) {
die("expected number of args is 3, not " . $numargs);
}
...
If I call it like this:
foo(1, 12, 17, 3, 5);
it's fine, but if I call it like this:
$str = "1, 12, 17, 3, 5";
foo($str);
it fails because it says I am only passing one argument. What change do I need to make if I would prefer not to change the function itself, just the calling convention.
-- update: to save the explode call, I simply built an array. And because the function was a member function, the calling convention was a bit different. So the code wound up being
$list = array();
$list[] = 1;
$list[] = 12;
$list[] = 17;
// etc.
call_user_func_array(array($this, 'foo'), $list);
Thought this might be useful to someone else.

This should do the trick:
$str = "1, 12, 17, 3, 5";
$params = explode(', ', $str );
call_user_func_array ( 'foo', $params );
call_user_func_array() allows you to call a function and passing it arguments that are stored in a array. So array item at index 0 becomes the first parameter to the function, and so on.
http://www.php.net/manual/en/function.call-user-func-array.php
update: you will have to do some additional processing on the $params array if you wish that the arguments will be integers (they are passed as strings if you use the above snippet).

$str = "1, 12, 17, 3, 5";
call_user_func_array('foo',explode(',',$str));

Related

laravel 5.4 variable parameter in query, giving wrong result?

$ids = '1, 2, 3';
$data = Modelname::whereNotIn('id', [$ids])->take(1)->get();
Above query giving wrong result. but following query giving right result.
$data = Modelname::whereNotIn('id', [1, 2, 3])->take(1)->get();
So, how to pass the variable parameter in query(laravel 5.4).
Use as below to make array
$ids = '1, 2, 3';
$idArr = explode(", ",$ids);
$data = Modelname::whereNotIn('id', $idArr)->take(1)->get();
Take care of space among ids $ids = '1, 2, 3'; and exploding by string
The whereNotIn accepts an array as its second argument.
So if you have a comma separated string which you do in your first scenario you need to explode it into an array, and then pass it to whereNotIn.
$ids = '1,2,3';
$idsArray = explode(',', $ids); // produces [1, 2, 3]
// it's always a good idea to add a check because if array is empty then an SQL exception will be thrown.
if(count($idsArray) > 0) {
$data = Modelname::whereNotIn('id', $idsArray)->take(1)->get();
}
Hope this helps.

Issues with in_array

I have the following fairly simple code, where I need to determine if a certain value exists in an array:
$testvalue = $_GET['testvalue']; // 4
$list = '3, 4, 5';
$array = array($list);
if (in_array($testvalue, $array)) { // Code if found } else { // Code if not found }
Even though it is obvious that the number 4 is in the array, the code returns the code inside the else bracets. What have I done wrong?
Change the third line:
$array = array_map('trim', explode(',',$list));
$array here is:
$array = array('3, 4, 5');
which is not the same as:
$array = array(3, 4, 5);
So, fix the way you are creating this array.. don't do it from a string.
Your array contains just one value, the string 3, 4, 5.
See the example on CodePad.
If you want to convert your string in an array, you can use:
$array = explode(', ', $list);
I have added a space behind the comma, but a safer method would be to use just a comma and then trim all values.

Callback function using variables calculated outside of it

Basically I'd like to do something like this:
$arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
$avg = array_sum($arr) / count($arr);
$callback = function($val){ return $val < $avg };
return array_filter($arr, $callback);
Is this actually possible? Calculating a variable outside of the anonymous function and using it inside?
You can use the use keyword to inherit variables from the parent scope. In your example, you could do the following:
$callback = function($val) use ($avg) { return $val < $avg; };
For more information, see the manual page on anonymous functions.
If you're running PHP 7.4 or later, arrow functions can be used. Arrow functions are an alternative, more concise way of defining anonymous functions, which automatically capture outside variables, eliminating the need for use:
$callback = fn($val) => $val < $avg;
Given how concise arrow functions are, you can reasonably write them directly within the array_filter call:
return array_filter($arr, fn($val) => $val < $avg);
use global variables i.e $GLOBAL['avg']
$arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
$GLOBALS['avg'] = array_sum($arr) / count($arr);
$callback = function($val){ return $val < $GLOBALS['avg'] };
$return array_filter($arr, $callback);

Populating PHP list() with values in an array

I have an array:
$arr = array('foo', 'bar', 'bash', 'monkey', 'badger');
I want to have the elements in that array appear as the variables in my list():
list($foo, $bar, $bash, $monkey, $badger) = $data;
Without actually specifying the variables, I tried;
list(implode(",$", $arr)) = $data; and
list(extract($arr)) = $data;
But they don't work, I get:
Fatal error: Can't use function return value in write context
Does anyone have any idea whether this is possible?
UPDATE: more context:
I am getting a CSV of data from an API, the first row is column names, each subsequent row is data. I want to build an associative array that looks like this:
$data[0]['colname1'] = 'col1data';
$data[0]['colname2'] = 'col2data';
$data[0]['colname3'] = 'col3data';
$data[1]['colname1'] = 'col1data';
$data[1]['colname2'] = 'col2data';
$data[1]['colname3'] = 'col3data';
Before I do that, however, I want to make sure I have all the columns I need. So, I build an array with the column names I require, run some checks to ensure the CSV does contain all the columns I need. Once thats done, the code looks somewhat like this (which is executed on a foreach() for each row of data in the CSV):
//$data is an array of data WITHOUT string indexes
list( $col1,
$col2,
$col3,
...
$col14
) = $data;
foreach($colNames AS $name)
{
$newData[$i][$name] = $$name;
}
// Increemnt
$i++;
As I already HAVE an array of column name, I though it would save some time to use THAT in the list function, instead of explicitly putting in each variable name.
The data is cleaned and sanitised elsewhere.
Cheers,
Mike
I want to have the elements in that array appear as the variables in my list():
i think there is your problem in understanding. list() does not create a new list structure or variable, it can only be used to assign many variables at once:
$arr = array(1, 2, 3);
list($first, $second, $third) = $arr;
// $first = 1, $second = 2, $third = 3
see http://php.net/list for more information.
you are probably looking for an associative array. you can create it with the following code:
$arr = array('first' => 1, 'second' => 2, 'third' => 3);
// $arr['first'] = 1, …
If some rows in your input file are missing columns, you can't really know which one is missing. Counting the number of values and aborting or jumping to next row when less than expected should be enough.
... unless you set the rule that last columns are optional. I'll elaborate on this.
Your code sample is far for complete but it seems that your problem is that you are using arrays everywhere except when matching column names to cell values. Use arrays as well: you don't need individual variables and they only make it harder. This is one of the possible approaches, not necessarily the best one but (I hope) clear enough:
<?php
$required_columns = array('name', 'age', 'height');
$input_data = array(
array('John', 33, 169),
array('Bill', 40, 180),
array('Ashley', 21, 155),
array('Vincent', 13), // Incomplete record
array('Michael', 55, 182),
);
$output = array();
foreach($input_data as $row_index => $row){
foreach($required_columns as $col_index => $column_name){
if( isset($row[$col_index]) ){
$output[$row_index][$column_name] = $row[$col_index];
}
}
}
print_r($output);
?>
I've used $row_index and $col_index for simplicity.
Original answer, for historical purposes only ;-)
I can't really understand your specs but PHP features variable variables:
<?php
$arr = array('foo', 'bar', 'bash', 'monkey', 'badger');
foreach($arr as $i){
$$i = $i;
}
?>
Now your script has these variables available: $foo, $bar... It's quite useless and potentially dangerous but it does what you seem to need.
You are trying to use a language construct in a manner in which it's not meant to be used. Use variable variables as Alvaro mentioned.
$arr = array('foo', 'bar', 'bash', 'monkey', 'badger');
foreach ($arr as $index => $key) {
$$key = $data[$index];
}
or
$arr = array('foo', 'bar', 'bash', 'monkey', 'badger');
$result = array();
foreach ($arr as $index => $key) {
$result[$key] = $data[$index];
}
extract($result);
In short, do not use "list", use arrays and associated arrays. Write helper functions to make your code clearer.
why not immediatly call the vars like
$arr['foo']
or
$arr[0]
If you want to extract the elements of $data into the current context, you can do that with extract. You might find it useful to call array_intersect_key first to pare down $data to the elements that you want to extract.
May be try like this :
$arr = array('foo', 'bar', 'bash', 'monkey', 'badger');
$data = "$".implode(",", $arr);
echo str_replace(",", ",$", $data);

How to implement a function that can take arbitary parameters in PHP?

Does PHP has such a feature?
You can use these functions:
func_get_arg » http://php.net/manual/en/function.func-get-arg.php
func_get_args » http://php.net/manual/en/function.func-get-args.php
fung_num_args » http://php.net/manual/en/function.func-num-args.php
Example:
function my_sum() { // <--- No parameters! :D
$total = func_num_args();
$numbers = func_get_args();
if ($total < 1) {
trigger_error('Less than one number :(');
return 0;
} else {
// Calculate the sum
$sum = array_sum($numbers);
return ($sum / $total);
}
}
// Usage:
echo my_sum(1, 2, 5, 109, 10231);
?>
Use the function func_get_args(). It will give you an array of all the parameters passed to that function.
Sure, make a function with no parameters, call it with whatever you want, and inside the function use func_get_args() to get the actual arguments.
Prehaps a better way is to pass one argument, that is actually an array of arguments.
eg:
function my_sum($data){
$sum = 0;
foreach($sum as $value){
$sum+=$value;
}
return $sum;
}
echo my_sum(array(1, 2, 5, 109, 10231));
I often use an associative array to pass arguments to a function. This is very usefull if the arguments being submitted are optional, or change in nature.
eg:
$data = array(
'date' => '10/4/06',
'name' => 'biggles',
'occupation' => 'pilot'
);
add_person($data);
This will also allow for better error detection. if you have many many arguments, it is quite possible to get them in the wrong order. plus if you extend or modify teh function it is more likely to keep working with existing code.

Categories