1st argument in array_push only accepts variable - php

array_push
I have a PHP statement as follow (in a method of a class)
array_push(self::USER_BASIC_DETAIL_FIELDS, 'cname_username');
which gives me error
Cannot pass parameter 1 by reference
Then I tried it assigning it to variable and it all worked fine
$r = self::USER_BASIC_DETAIL_FIELDS;
array_push($r, 'cname_username');
My question is why does PHP throws an error in above case?
I have an answer but I am not sure so asked here. The answer is like:
array_push does not return the modified array but changes the variable given at argument 1. So change are made at the locations in memory where variable (argument 1) is stored.
If we are passing argument 1 as self::USER_BASIC_DETAIL_FIELDS then with the same behavior of array_push it will try to modify constant USER_BASIC_DETAIL_FIELDS of a class which will create mess for developer
Am I right?

The answer is: everything depends on the details of your project.
You can't modify the value of constants.
And the '$r' variable is not a pointer to 'self::USER_BASIC_DETAIL_FIELDS' it is a copy of 'self::USER_BASIC_DETAIL_FIELDS'.
I think than you need a static variable instead of constant in that case.

Related

Add values later to a constant-Array

Is there a possibility to add on an existing constant-array some values?
define("USERID", array(123));
I've tried with
define("USERID", '456');
And google didn't get an answer as well,-)
From : http://php.net/manual/en/language.constants.php
A constant is an identifier (name) for a simple value. As the name
suggests, that value cannot change during the execution of the script
You might have tried this:
define('USERID', [123, 456]);
But that won't work, defining a constant a second time is simply ignored by php and keeps the first value it was defined as.
Instead you might consider using a static class variable. Or even a public property or getter method for a class. Or just a global variable.

Why strtolower() does not follow the PHP strict Standard

If i use
strtolower(end(explode('.',$_FILES['file']['name'])));
it give me error
PHP Strict Standards: Only variables should be passed by reference in
I thought ok I just store the values in a variables first, and then use explode
$filename = $_FILES['file']['name'];
$filearray = explode('.',$filename);
and it works fine
But i have another line
strtolower(end($filearray));
I thought it should give me the same error , i mean i should first have to store end($filearray) in a variable then use that variable in strtolower(),
But this is not giving me any error ,So why strtolower() accepting a function as parameter , and not giving an error , can someone explain why ?
It's not strtolower that gives you the warning - but end function. Quoting the docs:
end() advances array's internal pointer to the last element, and
returns its value. [...] The array is passed by reference because it
is modified by the function. This means you must pass it a real
variable and not a function returning an array because only actual
variables may be passed by reference.
In your first example you attempt to end the result of explode call - i.e., not a real variable. While it's possible for PHP to ignore such a use case, it usually means that you've done something by mistake - and E_STRICT warning attempts to notify you about it.
Your third example works fine, because:
1) strtolower actually doesn't care about the reference. It returns a string with all alphabetic characters converted to lowercase instead of modifying the string in place.
2) end has a variable - array - passed in. It returns its last element, while advancing the internal pointer of that array to, well, its end. Have you attempted to employ this internal pointer (with current or some other means), you'd see the difference.
As a sidenote (already mentioned in comments by #DoktorOSwaldo), you can replace the all explode(end() stuff with simple pathinfo call:
$ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
Because some functions in php are passed as a reference. end is one of those functions. see doc : http://php.net/manual/en/function.end.php
But the strtolower function gets just a normal parameter.
So why does the end function gets a reference? End will not just return the last element, but will also move the array's internal pointer to the last element. so if you call current function after the end function you will get the last element.
So basically end function will modify the array passed in parameter. And therefore it needs to be a variable that it can modify get as a reference.

How do I access the contents of this variable in PHP?

I am using a library, XCRUD, which takes a string argument and is expecting a variable interpolation pattern. Here is how it is used in the documentation, which works fine.
$xcrud->column_pattern('username','My name is {value}');
I want to use this variable as a key to an array, but I can't figure out what syntax is required to access it.
I have tried the following:
$xcrud->column_pattern('PlanNo', $myArray['{value}']);
$xcrud->column_pattern('PlanNo', $myArray[eval('{value}')]);
$xcrud->column_pattern('PlanNo', $myArray[${value}]);
How is it that the function in the library I'm calling can access the variable through {}? Maybe it's unreasonable for me to expect it will exist in the current scope, and it just passes that string somewhere down the line.
Thanks for your help. :)
Try this
$xcrud->column_pattern('PlanNo', $myArray[eval("(" + value + ")")]);

Can I extract function return value?

I noticed that in PHP extract(some_function()); will work just like:
$stuff = some_function();
extract($stuff);
But in the PHP's documentation the extract function argument has the & thingy in front, and from what I know that means you have to pass a variable to it.
If the documentation was right, this would produce a strict standards message:
PHP Strict standards: Only variables should be passed by reference
So I think you just found a bug in the documentation. Congratulations.
EDIT
It still doesn't complain if you use it with EXTR_REFS as a second argument:
~❯ php -a
Interactive shell
php > function a(){return array('pwet'=> 42);}
php > extract(a(), EXTR_REFS);
php > echo $pwet;
42
Which is strange because referencing variables defined inside a function doesn't make much sense to me. I think the & might have been introduced because of this option, but appears only in the doc and is not enforced in the code.
EDIT
It seems I'm right, I found this comment in ext/standard/array.c (branches 5.3 and 5.4):
/* var_array is passed by ref for the needs of EXTR_REFS (needs to
* work on the original array to create refs to its members)
* simulate pass_by_value if EXTR_REFS is not used */
The ampersand passes a variable by reference so that when it is used in a function, you are manipulating the original object -- not a new variable with the same value. The documentation is telling you that if you pass a variable to the extract function, then the original object can be updated in some fashion by that function.
So, the answer is yes, you need to pass a variable to that function.
The reason $var_array parameter of the extract function is passed by reference (most likely) is from a holdover from older versions of PHP. Newer versions automatically pass arrays by reference.
The extract function creates a variable list from the contents of a (potentially large) array and it is not recommended that data of that type be passed by value.
Long story short, assign your array to a variable and pass it in that way.

Why does PHP's call_user_func() function not support passing by reference?

Why don't the function handling functions like call_user_func() support passing parameters by reference?
The docs say terse things like "Note that the parameters for call_user_func() are not passed by reference." I assume the PHP devs had some kind of reason for disabling that capability in this case.
Were they facing a technical limitation? Was it a language design choice? How did this come about?
EDIT:
In order to clarify this, here is an example.
<?php
function more(&$var){ $var++; }
$count = 0;
print "The count is $count.\n";
more($count);
print "The count is $count.\n";
call_user_func('more', $count);
print "The count is $count.\n";
// Output:
// The count is 0.
// The count is 1.
// The count is 1.
This is functioning normally; call_user_func does not pass $count by reference, even though more() declared it as a referenced variable. The call_user_func documentation clearly says that this is the way it's supposed to work.
I am well aware that I can get the effect I need by using call_user_func_array('more', array(&$count)).
The question is: why was call_user_func designed to work this way? The passing by reference documentation says that "Function definitions alone are enough to correctly pass the argument by reference." The behavior of call_user_func is an exception to that. Why?
The answer is embedded deep down in the way references work in PHP's model - not necessarily the implementation, because that can vary a lot, particularly in the 5.x versions. I'm sure you've heard the lines, they're not like C pointers, or C++ references, etc etc... Basically when a variable is assigned or bound, it can happen in two ways - either by value (in which case the new variable is bound to a new 'box' containing a copy of the old value), or by reference (in which case the new variable is bound to the same value box as the old value). This is true whether we're talking about variables, or function arguments, or cells in arrays.
Things start to get a bit hairy when you start passing references into functions - obviously the intent is to be able to modify the original variables. Quite some time ago, call-time pass-by-reference (the ability to pass a reference into a function that wasn't expecting one) got deprecated, because a function that wasn't aware it was dealing with a reference might 'accidentally' modify the input. Taking it to another level, if that function calls a second function, that itself wasn't expecting a reference... then everything ends up getting disconnected. It might work, but it's not guaranteed, and may break in some PHP version.
This is where call_user_func() comes in. Suppose you pass a reference into it (and get the associated the call-time pass-by-reference warning). Then your reference gets bound to a new variable - the parameters of call_user_func() itself. Then when your target function is called, its parameters are not bound where you expect. They're not bound to the original parameters at all. They're bound to the local variables that are in the call_user_func() declaration. call_user_func_array() requires caution too. Putting a reference in an array cell could be trouble - since PHP passes that array with "copy-on-write" semantics, you can't be sure if the array won't get modified underneath you, and the copy won't get detached from the original reference.
The most insightful explanation I've seen (which helped me get my head around references) was in a comment on the PHP 'passing by reference' manual:
http://ca.php.net/manual/en/language.references.pass.php#99549
Basically the logic goes like this. How would you write your own version of call_user_func() ? - and then explain how that breaks with references, and how it fails when you avoid call-time pass-by-reference. In other words, the right way to call functions (specify the value, and let PHP decide from the function declaration whether to pass value or reference) isn't going to work when you use call_user_func() - you're calling two functions deep, the first by value, and the second by reference to the values in the first.
Get your head around this, and you'll have a much deeper understanding of PHP references (and a much greater motivation to steer clear if you can).
See this:
http://hakre.wordpress.com/2011/03/09/call_user_func_array-php-5-3-and-passing-by-reference/
Is it possible to pass parameters by reference using call_user_func_array()?
http://bugs.php.net/bug.php?id=17309&edit=1
Passing references in an array works correctly.
Updated Answer:
You can use:
call_user_func('more', &$count)
to achieve the same effect as:
call_user_func_array('more', array(&$count))
For this reason I believe (unfoundedly) that call_user_func is just a compiler time short cut. (i.e. it gets replaced with the later at compile time)
To give my view on you actual question "Why was call_user_func designed to work this way?":
It probably falls under the same lines as "Why is some methods strstr and other str_replace?, why is array functions haystack, needle and string functions needle, haystack?
Its because PHP was designed, by many different people, over a long period of time, and with no strict standards in place at the time.
Original Answer:
You must make sure you set the variable inside the array to a reference as well.
Try this and take note of the array(&$t) part:
function test(&$t) {
$t++;
echo '$t is '.$t.' inside function'.PHP_EOL;
}
$t = 0;
echo '$t is '.$t.' in global scope'.PHP_EOL;
test($t);
$t++;
echo '$t is '.$t.' in global scope'.PHP_EOL;
call_user_func_array('test', array(&$t));
$t++;
echo '$t is '.$t.' in global scope'.PHP_EOL;
Should output:
$t is 0 in global scope
$t is 1 inside function
$t is 2 in global scope
$t is 3 inside function
$t is 4 in global scope
Another possible way - the by-reference syntax stays the 'right' way:
$data = 'some data';
$func = 'more';
$func($more);
function more(&$data) {
// Do something with $data here...
}

Categories