Is there a way to make the arguments of a function act as an array? I'm finding this difficult to explain.
Here's kind of an example.. When you declare an array, you can define the keys => values like so:
$array = array(
"key" => "value",
"other_key" => "other_value"
);
And if I make a function that for an example outputs these onto the document, I could have:
function write($ar)
{
foreach($ar as $key => $value)
echo "$key: $value<br />";
}
write($array); // parse previously mentioned array
What I want to be able to do is omit the need to parse an array like above or below examples..
write(array(
"key" => "value",
"other_key" => "other_value"
));
I know I can use func_get_args() to list any amount of arguments, but is there a similar function that lets you parse key => value pairs rather than just a list of values?
Hope I described this in a way that makes sense, what I essentially want to end up with is something like:
write(
"key" => "value",
"other_key" => "other_value"
);
A function cannot take the argument as an array structure, so your best bet would be to use the method you specified in your second to last example:
write(array(
"key" => "value",
"other_key" => "other_value"
));
You could then have a default array within your function (if desired) so you could merge the two together so you always have a decent set of data.
EDIT
Unless you want to go crazy and pass it through as a string:
write('
"key" => "value",
"other_key" => "other_value"
');
And then parse that out on the other side... but IMO I wouldn't bother, potentially opening yourself up to issues here.
I know I can use func_get_args() to list any amount of arguments, but is there a similar function that lets you parse key => value pairs rather than just a list of values?
No, that's not possible in PHP. However you can fork PHP and implement such a syntax or make a code preprocessor ;)
well, I assume that you can send an object instead of an array and declare like that.
//the class
class CustomType{
public $key1;
public $key2;
}
//the function
function write(CustomType $customType){
}
//call the funcion write
$a = new CustomType();
$a->key1 = 1;
$a->key2 = 2;
write($a);
the above will force the user to send a custom object.
it is better than arrays, but then again, the user can ignore and not set $key2.
BTW, if you choose this method, you might as well do it in JAVA style with getters and setters. like here: http://www.abbeyworkshop.com/howto/java/salesTaxBean/index.html
that is as good as it gets since php is typeless, but i think it is much better then arrays
Edit
One of the bad usage in PHP is using arrays as params.
Almost every framework does that and you can find your self diving into sources in order to understand the array structure.
When you declare a class, you get it as autocomplete in your editor, and if not you just need to open the class to understand its structure.
I believe this is better programming style.
Related
I've been hitting my head on this problem for some time now. I am working on a piece of software that creates a tree from a MySQL result checking for changes between each row to decide where in the tree to put the new data.
I'm now at a dead end while trying to understand how I can dynamically tell PHP to address different parts of my array.
I though about using variable variables but it doesn't seem to be working. To make my life easier I tried to set up a test file in which to test this behavior and this is the result...
$array = [
0 => [
"name" => "test"
],
1 => [
"name" => "test",
"data" => [
"content" => 5
]
]
];
$ref = 'array["1"]["name"]';
echo $ref."\n";
echo $$ref;
Output
array["1"]["name"]
Notice: Undefined variable: array["1"]["name"] in P:\xampp\htdocs\assets\php\test.php on line 23
I was instead expecting something like test.
I would also like to mention that I've tried the ${} method but I doesn't affect the array, but instead adds the data to another variable those rare times it doesn't output an error.
Anyone can help? Thanks!
after thinking about the problem once again I came up with a work-around to achieve the intended result.
I decided to use references make with &$var.
I, so, decided to tweak the code to create an array of each step to do to arrive at the intended location, instead of a string. Example follows:
// Old method
$ref = 'array["1"]["name"];
// New method
$ref = ["1", "name"];
The code then follows by cycling through the array referencing the original array but slowly deeper...
// Referencing the original array
$referencedArray = &$array;
// Going one step at the time inside the nested array
foreach ($ref as $k => $v) {
$referencedArray = &$referencedArray[$rav];
}
I believe this solution could fit my case, but if you have any suggestions please let me know.
I know that prepending a '&' to your PHP variable sets up a reference to the original variable instead of copying its value like so:
$original = 'apples';
$secondary = &$original;
$original = 'oranges';
echo $secondary; // 'oranges'
If it works this way, why not just use the original variable then?
Passing by reference is useful and necessary when passing a variable as a parameter to a function, expecting that variable to be modified without a copy being created in memory. Many of PHP's native array_*() functions operate on array references, for example.
This function, for example, receives an array reference and appends an element onto the original array. If this was done without the & reference, a new array copy would be created in scope of the function. It would then have to be returned and reassigned to be used.
function add_to_an_array(&$array)
{
// Append a value to the array
$array[] = 'another value';
}
$array = array('one', 'two', 'three');
add_to_an_array($array);
print_r($array);
Array
(
[0] => one
[1] => two
[2] => three
[3] => another value
)
$original = 'apples';
function foo($word) {
$word = 'oranges';
}
foo($original);
echo $original; // apples, because only local $word was changed, not $original.
foo(&$original);
echo $original; // oranges, because $original and $word are the same
Pass by reference is really a cop out and goes against good encapsulation. If you need to manipulate a variable in that way, it probably should belong to a class as a member variable and then does not need to be passed to the function. Good OO design would usually make member variables immutable with a "final" keyword, but PHP doesn't have this. It's not intuitive that passing a variable to a function might change it's value which is why it should be avoided in most cases.
Also going to a more full OO design prevents you have having method signatures that are long and complex with many optional parameters that are difficult to re-factor.
A more interesting use of the is when it's used in the formal argument to a function
foo($a);
...
function foo (&$a) {
....
}
this allows you to modify a in the function.
There are many uses for references.
You can pass a reference to a variable to a function so you can change the value inside the function
You can use references to create linked lists
etc...
Just keep in mind that they're there, and you'll surely find an application for them when the time comes and you face a problem that can be solved with references.
Check out the following article for other ideas and uses of references:
http://www.elated.com/articles/php-references/
I am new to php. I was wondering how I could declare a static array in php. Here is what I would do in C. How is the corresponding php code for it?
char a[][] = { (1,1), (1,2), (1,3), (2,1), (2,2), (2,3), (3,1), (3,2), (3,3) };
From what I read it has to be something like this -
$a = array( 1 => array(1,1), 2 => array(1,2), ... );
Is this correct? If so it sucks :) I hope I am wrong.
Thanks,
- Pav
You've already found the way to do it natively.
Another option would be to declare your data as JSON (a very concise and human-friendly format). This could be either in a separate file bundled with your app, or directly in your code in a string. Then parse the JSON at runtime. Since PHP isn't exactly known for speed, this may or may not make your noticeably app slower to start.
you have it already figured out in your question.
One thing I would add is that you do not need to explicitly define the keys if you are intending to use a zero based array, this is assumed and can be done like so...
$a = array(array(1,1),array(1,2), ... );
You can also use what is called associative arrays which use string keys and you define them the same way you do in your example, except use strings instead of numbers...
$ass_array = array( 'array_1' => array(1,1), 'array_2' => array(1,2), ... );
you would then call your associative array like this...
$ass_array['array_1'];
Also, if you want to append single items to an array (for example in a loop to load an array)...
$ass_array[] = $item;
Further to jondavidjohn's anwser, you could just write a quick script to grab your list of values and generate the array statement for you.
No need to care how verbose the syntax is then. If the task is long and repetitious enough to care, don't do it by hand. :)
In short, what I want is a kind of export() function (but not export()), it creates new variables in symbol table and returns the number of created vars.
I'm trying to figure out if it is possible to declare a function
function foo($bar, $baz)
{
var_dump(func_get_args());
}
And after that pass an array so that each value of array would represent param.
Just wondering if it is possible (seems that is not).
I need this for dynamic loading, so number of arguments, size of array may vary - please dont offer to pass it as
foo($arr['bar']);
and so on.
Again, ideal thing solution will look like
foo(array('foo'=>'1', 'bar'=>'2', ..., 'zzz'=>64));
for declaration
function foo($foo, $bar, ..., $zzz) {}
As far as I rememeber in some dynamical languages lists may behave like that (or maybe I'm wrong).
(I want to create dynamically parametrized methods in class and built-in mechanism of controlling functions arguments number, default value and so on is quite good for this, so I could get rid of array params and func_get_args and func_get_num calls in the method body).
Thanks in advance.
You're looking for call_user_func_array
example:
function foo($bar, $baz)
{
return call_user_func_array('beepboop',func_get_args());
}
function beepboop($bar, $baz){
print($bar.' '.$baz);
}
foo('this','works');
//outputs: this works
I don't know about the speed but you could use ReflectionFunction::getParameters() to get what name you gave the parameters, combined with call_user_func_array() to call the function. ReflectionFunction::invokeArgs() could be used as well for invoking.
What about just passing in an associative array and acting on that array?
How about using extract()?
<?php
/* Suppose that $var_array is an array returned from
wddx_deserialize */
$size = "large";
$var_array = array("color" => "blue",
"size" => "medium",
"shape" => "sphere");
extract($var_array, EXTR_PREFIX_SAME, "wddx");
echo "$color, $size, $shape, $wddx_size\n";
?>
(Code taken from PHP example)
DISCLAIMER:
Please read carefully as this is NOT a question about storing arrays in constants or simple eval() or serialize() techniques. This IS a question primarily about how constants work in PHP and why the constant() function is not working to convert a constant name into a constant value. Thanks.
BACKGROUND:
For various reasons, I started out with a flat config file for a homebrewed LAMP(PHP) CMS (in private development). Looking back this may have been misguided, and I have transitioned my variable storage into a DB table. However, the bulk of the code still depends on the CONSTs, so I use eval("define(A, B...);") to load the DB values A and B into constants. This part works fine. But it gets a bit more complicated.
PROBLEM:
The problem I'm having now is with constants in arrays (NB. NOT arrays in constants). I have a big, GLOBAL array called defaults that contains config settings in the format shown below.
Initially, I declare: <?php define('THIS_IS_A_CONSTANT', 'abcdefg'); ?> (And THIS WORKS...)
Next, I define $GLOBALS['defaults'] as the following nested array:
Array
(
'var_name' => Array
(
'display' => THIS_IS_A_CONSTANT,
'value' => 12,
'type' => 'int',
'params' => Array ( ... )
),
...
Lots more variables...
...
)
To prevent the client (who has file system access but no direct DB access but can change certain values, including most constants, via the CMS's administrative backend) from mucking up this array structure, I serialize the array structure and store that string in the DB. On each page request, I first define all the constants (stored in the DB) using the eval(define(A,B...)), then I unserialize the array above (which was serialized and stored in the DB). However, no matter what I try I cannot get the values at $GLOBALS['defaults']['var_name']['display'] to be recognized as the values that the constants contain. Instead, the constant name shows up and NOT the constant value (in other words, my output contains THIS_IS_A_CONSTANT instead of 'abcdefg'). Very frustrating, right?
I've tried something like the following (where $arr contains the unserialized array that I fetch from the DB):
foreach ($arr as $item => $contents) {
$display = isset($contents['display']) ? $contents['display'] : 1;
$value = constant("$display");
// This doesn't work, though it seems like it should
$contents['display'] = $value;
// Neither does this, no matter how much I juggle the quotation marks and backslashes
eval("\$contents['display'] = constant(\"$value\");");
// or this ...
eval("\$contents['display'] = $value;");
// or this ...
eval("\$contents['display'] = \$value;");
// or a number of other things...
}
$GLOBALS['defaults'] = $arr;
QUESTIONS:
Has anyone dealt with this kind of situation before? Can anyone advise me how to force my constants to be recognized as CONSTANTS and not strings. Do I need to serialize my array differently? Or maybe process the unserialized array differently (after retrieving it from the DB)? Is these some combination of eval() and constant() that will allow me to do this? Why are the constants within my array behaving badly while the constants I define normally are working without problem? Any help at all would be greatly appreciated, as I've been puzzling over this for a few days now and haven't come to any solutions.
All the best, Dakota.
Although eval does have its uses, this is not one of those cases. You have no idea what is being submitted to the eval at run time - and by the sounds of things you are storing something which you are then treating as code in a user-data storage location.
If the constant was defined before the array was declared then the serialized version would contain the value instead of the label. I can only assume that the value may differ depending on the context at run-time.
I would suggest that a better solution would be to roll your own macro language in PHP, e.g. something like:
<?php
global $defs;
$defs=array(
'THIS_IS_A_CONSTANT' => 'abcdefg',
'SO_IS_THIS' => 23
);
// for inline constants
foreach ($defs as $label =>$val) {
define($label, $key);
}
replacer($defs,true);
function replacer($in, $init=false;)
{
static $defs;
static $vals;
if ($init) {
$defs=array_keys($in);
$vals=array_values($in);
return count($in);
}
return str_replace($defs, $vals, $in);
// you might want to use preg_replace() with a pattern based on $defs for a neater solution
}
function fix_var(&$in)
{
if (is_array($in)) {
foreach ($in as $key=>$dummy) {
fix_var($in[$key]);
}
} else {
$in=replacer($in);
}
}
?>
C.
First, why are you evaling? From what you are saying you want the value of $GLOBALS['defaults']['var_name']['display'] to be the value of the constant THIS_IS_A_CONSTANT. You have de-serialized the string from your database and shoved in in $GLOBALS['defaults'] and the string stored the value as the constant name, not the value of the constant.
Have you tried:
<?php
define('THIS_IS_A_CONSTANT', 'abcdefg');
$value = constant($GLOBALS['defaults']['var_name']['display']);
//$value should now be abcdefg not THIS_IS_A_CONSTANT
$GLOBALS['defaults']['var_name']['display'] = $value;
?>
If "$GLOBALS['defaults']['var_name']['display']" does contain the string THIS_IS_A_CONSTANT then all you should need to do is pass that string to the constant funct.
Am I missing something?