I know that if $var is NEVER declared, it can be declared WITH a sub-object like $var->mysubvar=1;
But if $var = “123” is mentioned ahead of time, then $var->mysubvar=1 will cause error. As it is declared ahead of time
I heard it was named "Dynamic Binding". But when I actually look into the term, I can not really find such description inside PHP Manual that match with this scenario and behavior.
Is this behavior call "Dynamic Binding"? Is there a specific name for it. But if it is the name then why PHP Manual did not include such technique or behavior?
The question is that What is the name to describe such behavior that one does not need to declare object ahead of time and an object will be automatically generated if there is sub-object is declared. (for example, javascript will not allow to manipulate an object without doing var myvar=1 (or equivalent), first.)
Answer:
Ah yea, its indeed deal with dynamic typing.
What is Dynamic Typing?
The issue you mentioned is related to dynamic typing, not necessarily dynamic binding. The PHP documentation on variable types covers this.
The type of a variable is not usually set by the programmer; rather, it is decided at runtime by PHP depending on the context in which that variable is used.
The reason your examples throw errors is because of a type mismatch.
For example, assuming $var isn't set, executing $var->mysubvar = 1 will create $var as an object. Attempting to follow it with $var = 5 will result in an error because your previous command specified that $var will be an object, not a scalar.
Related
Is there any directive in the recent PHPs (maybe similar to that of declare( strict_types = 1 );) that tells the PHP interpreter to "force" return types in the functions, and if there's no return type, it fails due to a parse/syntax error?
I'd like that having this in the code:
public function add( int $a, int $b ) : int
{
return $a + $b;
}
is allowed but this one:
public function add( int $a, int $b )
{
return $a + $b;
}
is forbidden by the interpreter resulting in a parse error so the script never gets executed even if the function is not called.
I mean:
It is not that I want to "force a return type in a certain function" (I already do that). What I want is that the configuration "forces me to force return types in all the functions of a file or project".
I had a look at PHP RFC: Return Type Declarations and there is no way (for now and for future release) to do such a thing ...
It's the same for declare(strict_types=1) (PHP RFC: Scalar Type Declarations) which only ensure that the existing declarations are strictly typed checked.
The short answer to your question is No. PHP doesn't have anything to force you to define your return type. It also doesn't have anything to force you to define types for your arguments either -- strict_types = 1 forces passed values to be of the correct type for the method if the type is defined, but you can still write methods with arguments that don't define a type.
It is possible that PHP may make changes in a future release along the lines you're looking for, but it isn't on the cards for any version right now.
In the meanwhile, I would suggest using a code checking tool to help you enforce this kind of detail in your code. A tool like PHP Code Sniffer will be a good start. You can add it to your IDE so that you get warnings in real time when your code doesn't meet your defined standards, and you can add it to your workflow so that it prevents code from being committed and/or deployed if it fails the test.
What exactly is your problem with not having a forced fixed return type? I like the lazy way of coding with PHP. I could be cumbersome in large projects to find a mistyped variable name or wrong typed return value I admit. But there are remedies to that.
If a caller expects a definitive type it can (must!) test it anyway. This could be done by converting the result to the requested type and throwing an exception on failure as shown in PHP String-to-Integer Exception. Or in case of integer simply using is_numeric, is_nan, is_real etc.. You can put those tests in member functions for each type in the base object or even use a global singleton tester object with those member functions etc..
I've been searching for quite a while and cannot find what this method is actually called.
In PHP example:
$var->{'property_name'}
Depending on what you are accessing it will be called...
A variable variable
A variable property
A variable function
It is worth noting that the curly-braces are only needed when you need to disambiguate an expression (bear in mind the string you use may itself be stored in a variable!)
And so on. This is documented in the PHP manual for variable variables.
I've read about this interesting syntax in PHP:
$value = (new MyClass)->attribute1;
Is it ok to use it? I've never seen anything like this in any code I've analyzed. Any pros and cons?
Why can't I set the attribute using this syntax? Structures like this:
(new MyClass)->attribute1 = 'value1';
throw errors at '=' sign, no matter if the attribute exists in the class already.
Well i don't see the point of using it since you loose your reference to the object, you cannot use it anymore, and it breaks the OO concept.
I think (new MyClass)->attribute1 is resolved first, so it is the same as writing something like 42 = 12
This may have a sense, if the class MyClass supports internal static list (or hashmap) of all existing instances. This way you can create new object and get its unique ID or index in the list for future references (for example, by sending it via cookies to a client).
As for assignment, you'd post exact error message for this case. I can guess, that the error is about assigning something to a temporary value which is about to be destroyed.
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 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...
}