I'm just starting to learn PHP and am using the W3 Schools tut. In the error handling section there is this code:
<?php
function customError($errno,$errstr) {
echo '<b>Error:</b> [$errno] $errstr<br />';
}
set_error_handler('customError');
echo($test);
?>
Why is the customError() function being passed as a string? Is this a mistake in the tut?
Also, why isnt $test defined?
Why is the customError() function being passed as a string?
For the same reason that usort or ob_start take strings for function specifiers. PHP just needs the name of the function. A function name not enclosed in quotes with either try being executed as a constant or (if followed by parenthesis) will be executed and the result passed to the function.
Because of the way PHP parses documents for execution, you have to work within the means of the language (use strings instead of "pointers" to function calls).
Also, why isnt $test defined?
This is a purposeful call to trigger an error. They are trying to get you to work with an undefined variable so an error occurs and the code you just wrote (with the custom handling) catches the error.
No, it's not an error. It's not so common, but some standard PHP functions accept functions name as parameter when you have to pass a function for same reason. set-error-handler is one of these function.
If you are curios about that, you can read here:
http://it2.php.net/manual/en/language.pseudo-types.php#language.types.callback(dead link)
The set_error_handler method takes a string as its first parameter -> http://php.net/manual/en/function.set-error-handler.php this is the function invoked for errors
The echo($test) causes an error to be thrown thus invoking the customError function
Because customError is not actually being passed as a string, per se, but rather its name is being passed as a string to PHP. See http://php.net/manual/en/function.set-error-handler.php , it allows you to specify a custom error handler function to PHP.
Related
Recently, I was following this PHP talk See it on YouTube. There is a part about new features in PHP7 that is a really strange stuff for me (in "Uniform variable syntax" part of the talk), which wrote:
// support all operations on dereferencable scalars
// (not very useful)
"string"->toLower()
What is a dereferencable scalar? I know when I call a method on a non-object, for example:
echo "string"->toLower();
I'll get the following Error in PHP7:
Fatal Error: Uncaught Error: Call to a member function toLower() on string
Also, I cannot find a way to declare methods on strings (like something we see in JavaScript); as I know, there is no way to do it.
So, what is the code above saying? How can we do the stuff above? What is the use case for it? Saying it generally, what is "string"->toLower()?
(Editted) Note: While the PHP talks says it exists as of PHP 7.0, it seems to be a mistake by Mr. Lerdorf (it could be a rejected patch, for example).
Thanks in advance.
Short answer: this would be a syntax sugar.
Longer answer: This is a way to call functions with the syntax which aligns with the object syntax.
For example, an object (i.e. a class instance) could have a method called "length()". The invocation of this method would be expressed with the following "arrow" syntax:
$length = $myObject->length();
But, for example, to get a length of a string, you can't currently use the same syntax, because strings are not objects. Instead, you must put the variable name within the parentheses, as a parameter to the strlen function , i.e.:
$length = strlen($myString);
What you have mentioned is an idea to unify the syntax, i.e.
$length = $myString->strlen();
would be another possible syntax to call the strlen function. This would make operations on scalars (and arrays) syntactically closer to the objects' method calls.
Note that PHP doesn't support this syntax yet, as of 2018-09-14.
I have the following code:
$family = cis_resempty(wp_get_post_terms($post->ID,'family'),0);
I get the following error:
Notice: Only variables should be passed by reference in
C:\xampp.....xxx.php on line 18
If I do the following:
$family = cis_resempty(array('a'),0);
I even get
Fatal error: Only variables can be passed by reference in
C:\xampp...xxx.php on line 16
The function cis_resempty is like this (but its from a library):
function cis_resempty(&$var,$key) { ... }
Found out that if I remove the & reference sign within the parameter list of cis_resempty there are no errors.
If I do this:
$family = #cis_resempty(wp_get_post_terms($post->ID,'family'),0);
There is no notice and everything works - but Netbeans says:
Misuse of the error control operator
But if I do this:
$family = #cis_resempty(array('a'),0);
The fatal error continues to exist.
Why can I pass a function by reference and suppress the notice with the error control operator but if I pass an array I get a fatal error?
Why is it bad to pass a non variable by reference?
NOTE: never use '#' for suppressing.
Why can I pass a function by reference and suppress the notice with
the error control operator but if I pass an array I get a fatal error?
Read here Passing by Reference first note:
There is no reference sign on a function call - only on function definitions. Function definitions alone are enough to correctly pass the argument by reference. As of PHP 5.3.0, you will get a warning saying that "call-time pass-by-reference" is deprecated when you use & in foo(&$a);. And as of PHP 5.4.0, call-time pass-by-reference was removed, so using it will raise a fatal error.
PHP doesn't "support" it since 5.4.0 => you get E_FATAL in any case. With # or without #. For function - you get E_STRICT. All right. Then, read about # work more here Error Control Operators. Again, first note:
Note: The #-operator works only on expressions. A simple rule of thumb is: if you can take the value of something, you can prepend the # operator to it. For instance, you can prepend it to variables, function and include calls, constants, and so forth. You cannot prepend it to function or class definitions, or conditional structures such as if and foreach, and so forth.
Try this code ( it will shed light) :
error_reporting(E_ALL);
$arr = [1,2,3,4,5,];
$a_closure = function(){
return [1,2,3,4,5];
};
function a(){
return [1,2,3,4,5];
}
function ref_func(&$input){
foreach($input as &$in){
$in++;
}
}
ref_func($a); // #ref_func($a);
ref_func(a()); // #ref_func($a());
ref_func($a_closure); // #ref_func($a_closure);
// Fatals in both
ref_func([1,2,3,4,5]); // #ref_func([1,2,3,4,5]);
The term "non-variable" refers to any variable which the programmer cannot reference by name. These are temporary variables allocated by the executor at runtime: The result of a function call or some other expression, that is not assigned to a named variable.
To pass something by reference only makes sense if the variable being passed by reference is named, so that when the call is over, the caller can access that which was passed by reference to the callee.
When PHP comes across a function call at compile time, the space for the result of the function call, and parameters of the function call are reserved, and then allocated at execution time relative to the execution frame. When you pass the result of a function call by reference, the executor is able to force by-reference behaviour for the variable, because there is space on the heap and it can just ignore that the variable has no name ... it doesn't usually make sense to do that, but remains for backward compatibility reasons.
When PHP comes across a literal (array) at compile time, it allocates the space for the data relative to the op array (function) itself. Because of that difference forcing by-reference behaviour of literals would be dangerous and cause very unexpected behaviour: Consider what would happen when the function is re-entered, concurrently or otherwise.
I have been looking for an error in my code since an hour. This was the error:
Writing:
if(isset(($_POST['to'])))
instead of
if(isset($_POST['to']))
I don't get why is this extra pair of brackets causing an Internal Server Error.
I don't think putting brackets around a variable never changes its value. I mean,
$a = $b;
$c = ($b);
$a==$c; //True
I am curious as to know why is it an error?
Thank you.
EDIT:
The above error was occurring for normal variable also.
This is because isset is not a function but a language construct; as such, its definition can be found in the language parser.
T_ISSET '(' isset_variables ')' { $$ = $3; }
It only expects one pair of braces; passing another pair will cause a parse error.
Im pretty sure it has something to do with the fact that isset can not take a function in parameter. You have to pass it a value. Your extra pair of parenthesis may be evaluated as a 'function' or something that need to be evaluated.
Normally, when you try to pass a function to isset, you get this error :
Can't use method return value in write context
isset:
Warning
isset() only works with variables as passing anything else will result in a parse error. For checking if constants are set use the defined() function.
Information can be passed to functions through arguments. An argument is just like a variable.
Arguments are specified after the function name, inside the parentheses. You can add as many arguments as you want, just seperate them with a comma.
The following example has a function with one argument ($fname). When the familyName() function is called, we also pass along a name (e.g. Jani), and the name is used inside the function, which outputs several different first names, but an equal last name:
<?php
function familyName($fname)
{
echo "$fname Refsnes.<br>";
}
familyName("Jani");
familyName("Hege");
familyName("Stale");
familyName("Kai Jim");
familyName("Borge");
?>
I have a couple of libraries that use code similar to the following one.
$args = array_merge(array(&$target, $context), $args);
$result = call_user_func_array($callback, $args);
The code is different in both the cases, but the code I shown is what essentially is done. The $callback function uses the following signature:
function callback(&$target, $context);
Both the libraries document that, and third-party code (call it plug-in, or extension) adopts that function signature, which means none of the extensions defines the callback as, e.g., function my_extension_loader_callback($target, $context).
What confuses me are the following sentence in the documentation for call_user_func_array().
Before PHP 5.4, referenced variables in param_arr are passed to the function by reference, regardless of whether the function expects the respective parameter to be passed by reference. This form of call-time pass by reference does not emit a deprecation notice, but it is nonetheless deprecated, and has been removed in PHP 5.4. Furthermore, this does not apply to internal functions, for which the function signature is honored. Passing by value when the function expects a parameter by reference results in a warning and having call_user_func() return FALSE.
In particular, the highlighted sentence seems to suggest that is not done for functions define in PHP code.
Does using call_user_func_array() in this way work in PHP 5.4?
When using call_user_func_array, passing by value when a function expects a reference is considered an error, in newer versions of PHP.
This was valid PHP code before PHP 5.3.3:
//first param is pass by reference:
my_function(&$strName){
}
//passing by value, not by reference, is now incorrect if passing by reference is expected:
call_user_func_array("my_function", array($strSomething));
//correct usage
call_user_func_array("my_function", array(&$strSomething));
The above pass by value is no longer possible without a warning (my project is also set to throw exceptions on any kind of error (notice, warning, etc).) so I had to fix this.
Solution
I've hit this problem and this is how I solved it (I have a small RPC server, so there is no such thing as referenced values after deserializing params):
//generic utility function for this kind of situations
function &array_make_references(&$arrSomething)
{
$arrAllValuesReferencesToOriginalValues=array();
foreach($arrSomething as $mxKey=>&$mxValue)
$arrAllValuesReferencesToOriginalValues[$mxKey]=&$mxValue;
return $arrAllValuesReferencesToOriginalValues;
}
Although $strSomething is not passed by reference, array_make_references will make it a reference to itself:
call_user_func_array("my_function", array_make_references(array($strSomething)));
I think the PHP guys were thinking of helping people catch incorrectly called functions (a well concealed pitfall), which happens often when going through call_user_func_array.
If call_user_func_array() returns false you have a problem, otherwise everything should be fine.
Parameters aren't passed by reference by default anymore, but you do it explicitly.
The only trouble could be that your reference gets lost during array_merge(), haven't tested that.
I've found this same problem when upgrading to PHP5.4 when there were several sites using call_user_func_array with arguments passed by reference.
The workaround I've made is very simple and consists on replacing the call_user_func_array itself with the full function call using eval(). It's not the most elegant solution but it fits the purpose for me :)
Here's the old code:
call_user_func_array($target, &$arguments);
Which I replace with:
$my_arguments = '';
for ($i=0; $i<count($arguments); $i++) {
if ($i > 0) { $my_arguments.= ", "; }
$my_arguments.= "\$arguments[$i]";
}
$evalthis = " $target ( $my_arguments );";
eval($evalthis);
Hope this helps!
For example, the array_map function. You pass it a string which is the name of a function. Presumably it doesn't directly eval the string, since you get a specific error:
PHP Warning: array_map() expects parameter 1 to be a valid callback, function 'dfdgdfg' not found or invalid function name
Which is different from the "Call to undefined function" error that you get if you call an undefined function.
So, is it looking up your string in the global symbol table, checking if it exists, and if not, throwing the above exception?
That still doesn't explain how it's calling the function though. Is it doing an eval on the string after checking if it's a defined function?