Below is a fragment of one of my functions, but I figured this seemed redundant and thus wanted to avoid it.
function cellMaker($cell){
$label= $cell['label'];
$type= $cell['type'];
$return= $cell['return'];
$size= $cell['size'];
$name= $cell['name'];
$value= $cell['value'];
........
The reason I am doing this is to avoid having to fill in nulls with the function if I only need to pass two of the parameters, like just label and type and value. That would look like cellMaker('how?', 'text' null, null, null, 'because');
Rather I only would need to do cellMaker(["label" => "how?", "type"=> "text", "value" => "because"]) which saves me from having to remember the order the variables are defined in the function and from having to deal with unnecessary variables. However I also do not want to have to type $cell['variable'] rather than $variable each time.
Is there a way to automatically assign all variables of an object to function variables of the same name?
You may use extract function to get separate variables from an array.
$array = ["label" => "how?", "type"=> "text", "value" => "because"];
extract($array);
This will give you three variables named after keys in the array containing corresponding values.
Be warned though. It may become rather unpredictable. You wouldn't know for sure what kind of keys there may be in the input array.
Related
In CoffeeScript, Clojure, ES6 and many other languages we have destructuring of objects/maps/etc somewhat like this:
obj = {keyA: 'Hello from A', keyB: 'Hello from B'}
{keyA, keyB} = obj
I've found the list function in php which lets you destructure arrays like so:
$info = array('coffee', 'brown', 'caffeine');
list($drink, $color, $power) = $info;
Is there a way to destructure objects or associative arrays in PHP? If not in the core libs maybe someone wrote some smart helper function?
For PHP 7.0 and below that is beyond the functionality of list. The docs state:
list only works on numerical arrays and assumes the numerical indices start at 0.
One of the things that could suit your purpose would be the extract() function which imports variables from an array into the current symbol table. While with list you are able to define variable names explicitly, extract() does not give you this freedom.
Extracting an associative array
With extract you could do something like that:
<?php
$info = [ 'drink' => 'coffee', 'color' => 'brown', 'power' => 'caffeine' ];
extract($info);
var_dump($drink); // string(6) "coffee"
var_dump($color); // string(5) "brown"
var_dump($power); // string(8) "caffeine"
Extracting an Object
Extracting an object works almost the same. Since extract only takes an array as an argument we need to get the objects properties as an array. get_object_vars does that for you. It returns an associative array with all public properties as key and their values as value.
<?php
class User {
public $name = 'Thomas';
}
$user = new User();
extract( get_object_vars($user) );
var_dump($name); // string(6) "Thomas"
Pitfalls
extract() is not the same as list since it does not allow you to explicitly define the variable names that get exported to the symbol table. The variable names correspond the array keys by default.
list is a language construct while extract() is a function
It might happen that you overwrite variables that you have defined beforehand unintentionally
Your array keys might be invalid as variable names
With the $flags parameter that you can pass as second argument to extract() you can influence the behavior in case of colliding or invalid variables. But still it's important to know how extract() works and to use it with cauton.
Edit: As of PHP 7.1 this is possible:
http://php.net/manual/en/migration71.new-features.php#migration71.new-features.support-for-keys-in-list
You can now specify keys in list(), or its new shorthand [] syntax. This enables destructuring of arrays with non-integer or non-sequential keys.
https://php.net/manual/en/migration71.new-features.php#migration71.new-features.symmetric-array-destructuring
The shorthand array syntax ([]) may now be used to destructure arrays for assignments (including within foreach), as an alternative to the existing list() syntax, which is still supported.
For example this:
$test_arr = ['a' => 1, 'b' => 2];
list('a' => $a, 'b' => $b) = $test_arr;
var_dump($a);
var_dump($b);
Will output the following as of 7.1.0
int(1)
int(2)
I noticed the accepted answer missed out examples that use the short-hand notation, security issues with using extract, and IDE issues.
Numerical Array Destructuring (PHP 7.1)
As of PHP 7.1 numerical array destructuring (Symetric array destructuring) is supported like so:
<?php
$data = [55, 'John', 'UK'];
[$id, $name] = $data; // short-hand (recommended)
list($id, $name) = $data; // long-hand
Notice that you can miss items out if you don't want them.
Associative Array Destructuring (PHP 7.1)
You can also destructure associative arrays (Support for keys in list) like so:
<?php
$data = ['id' => 55, 'firstName' => 'John', 'country' => 'UK']
['id' => $id, 'firstName' => $name] = $data; // short-hand (recommended)
list('id' => $id, 'firstName' => $name) = $data; // long-hand
Notice that you can miss items out if you don't want them. Also the variable name can be different to the property name.
Object Destructuring (PHP 7.1)
Unfortunately there is no object destructuring. However you can convert an object to an associative array using get_object_vars, and then use associative array destructuring.
<?php
class User {
public $id;
public $name;
public $country;
}
$user = new User();
$user->id = 55;
$user->name = 'John';
$user->country = 'UK';
['id' => $id, 'firstName' => $name] = get_object_vars($user)
However, this can break some IDE features. These are some issues I noticed when using PHPStorm 2019.1:
IDE's may no longer understand the type for the variables, so you would need to add some #var Type PHPDocs to maintain auto-complete functionality
Does not work well with refactoring tools. For example, if you rename one of the properties, the array destructuring portion will not also automatically rename.
So I recommend just doing it the normal way:
$id = $user->id
$name = $user->firstName
Do NOT use extract
With extract, all variables are always set. There it is a really bad idea to use it because:
It can lead to security issues. Even if your careful, it can lead to non-obvious security holes in the future. If you do use it, don't use it with user input (e.g. $_GET, $_POST), unless you want to make a malicious hacker's day.
Can lead to hard to detect bugs
If the class or array changes in the future, by introducing new properties, it can break your code if it coincides with an already used variable, unless you use the EXTR_SKIP flag or similar
Variable variables are one way to achieve this:
$args = ['a' => 1, 'b' => 2, 'c' => 3];
foreach (['a', 'c'] as $v) $$v = $args[$v];
// $a is 1, $b is undefined, $c is 3
It's really not pretty, and thankfully this has been addressed in 7.1 by https://wiki.php.net/rfc/short_list_syntax . This would let you say ['a' => $a, 'c' => $c] = $args; in the above example.
Since 7.1 includes a way to use a different name for your var than the assoc array key. This is pretty straight-forward using variable variables here too:
foreach (['a' => 'eh', 'b' => 'bee'] as $k => $v) $$v = $args[$k];
// $eh is 1, $bee is 2
Some developers, and some coding styles, define $$var as an anti-pattern similar to using eval, extract, and the GPR magic variables directly. This is because using variable variables makes code harder to understand, which leads directly to bugs and prevents static code analysis tools from functioning.
If you do adopt $$var, it can be helpful to use the ${$var} form instead, which makes it obvious that the author didn't simply type one too many $'s, and may spare the author immediate negative feedback when their code is audited.
One simple solution is to read the Object as an Array. So assuming you use #Yahya Uddin's User object, you can do like so:
['id' => $id, 'firstName' => $name] = (array)$user
// $id = 55, name = 'john'
This will tell PHP to read this objective as an associative Array.
I have an array consisting of 4 fields.
$retval[] = array(
"name" => "$dir$entry/",
"type" => filetype("$dir$entry"),
"size" => 0,
"lastmod" => filemtime("$dir$entry")
);
I want to sort this array depending on a variable, which contains either 1 of the 4 field (eg: type, name etc)
$sortBy = $_GET['sortBy'];
This function should use the $sortBy variable:
function compare_field($a, $b){
return strnatcmp($a["'.$sortBy.'"], $b["'.$sortBy.'"])
}
And is called like this:
usort($retval, "compare_field");
But the construction doesn't work ..
Hope someone can point me in the right direction, being the obvious newby I am.
First, you're sorting by a key that is actually: '..', not the value of $sortBy. You're trying to use a variables value as the key, to do that, you don't need to mess around with quotes, just write $arrayName[$keyVariable]. That's it.
Second is that compare_field had no access to the $sortBy variable. That variable is local to the scope where it was created, or it's a global variable. Either way, functions don't have access to it.
If you want the usort callback to have access to the $sortBy variable, the easiest way would be to use a closure (anonymous function) as callback:
usort($retval, function ($a, $b) use ($sortBy) {
return strnatcmp($a[$sortBy], $b[$sortBy]);
});
The best praticle to handle parameters (or arguments) in a functions it is about to know exactly what the function needs in a ordered list (see func_get_args()) so to get the corresponding variables (locale scope) and values.
What about if you know what you need as input inside a function but you don't know what are you are going to get? (How many arguments? What order? What type?)
I suppose that there could be different ways to do that and I've found myself the following code lines:
function myvars() {
$vars = array( "firstname" => "string", "lastname" => "string", "age" => "int", "alive" => "bool" );
$args = func_get_args();
foreach ($args as $arg) {
foreach($vars as $var => $type) {
if (preg_match('/^' . $type . '/i', gettype($arg))) {
$$var = $arg;
unset($vars[$var]);
break;
}
}
}
var_dump($firstname);
var_dump($lastname);
var_dump($age);
var_dump($alive);
}
myvars(31, "Mark", true, "Green");
I would appriciate other snippets to work out this issue.
On two occasions I have been asked, "Pray, Mr. Babbage, if you put
into the machine wrong figures, will the right answers come out?" ...
I am not able rightly to apprehend the kind of confusion of ideas that
could provoke such a question.
—Charles Babbage, Passages from the Life of a Philosopher
Function signatures and declarations are precisely to establish an interface or contract between two different parts of your code. Why would you ever declare a function without any specification and why would you ever call that function without any idea of what you're doing and why would you still expect to get a sensible result?
Have your function declare its parameters by name, or at least accept an array or object with named keys. You can't get code structure without structuring your code. Your example code is non-deterministic, since you're getting two strings and cannot distinguish them from one another. There's no guarantee you can make that this function always produces the correct output.
Hey just wondering if there is a simpler way to declare an array inside a function call besides array()
$setup = new setupPage();
$setup->setup(array(
type => "static",
size => 350
));
class setupPage {
public function setup($config){
echo $config[size] . $config[type];
}
}
Thanks :D
If you use PHP 5.4+ you can use the shorthand, however it makes no difference in performance, but in actuality may make it harder to read:
$setup->setup(['type' => 'static',
'size' => 350]);
Create a PHP program with an array (student) with the following
categories: student_id, student_name, student_address,
student_state, student_zip, and student_age. A function within
the program will accept all the values and restrict the data type
passed for each. The function creates the array and place the
values into the array. Display the values in the array. Use try/catch
to display an error message if one or more of the values are not the
proper data type.
I have a function that returns an array of variables. The variables it returns vary depending on what it needs to return. For example one time it could return array($pet,$color); and another time it could return array($height,$width,$table);
On the receiving end I want to make these variables available. If I knew I was expecting $pet and $color, I could do something like
list($pet, $color) = myfunction();
but I don't know what the function is going to return each time. So is there a way I could still recreate these variables under the same names when I receive the function output?
Edit: I was hoping to not have to do it by defining an associative array that has the name of the variable saved as a string in addition to the variable itself.
Does the function return an associative array, eg
return array(
'height' => $height,
'width' => $width,
'table' => $table
);
If so, you can then use the extract function to bring each entry into the current scope's symbol table
I think you need to use associative arrays instead, so entries will have fixed names associated with them:
array('height'=>$height, 'width'=>$width, 'table'=>$table)