Php function argument error suppression, empty() isset() emulation - php

I'm pretty sure the answer to this question is no, but in case there's some PHP guru
is it possible to write a function in a way where invalid arguments or non existent variables can be passed in and php will not error without the use of '#'
Much like empty and isset do. You can pass in a variable you just made up and it won't error.
ex:
empty($someBogusVar); // no error
myHappyFunction($someBogusVar); // Php warning / notice

You don't get any error when a variable is passed by reference (PHP will create a new variable silently):
function myHappyFunction(&$var)
{
}
But I recommend against abusing this for hiding programming errors.

Summing up, the proper answer is no, you shouldn't (see caveat below).
There are workarounds already mentioned by many people in this thread, like using reference variables or isset() or empty() in conditions and suppressing notices in PHP configuration. That in addition to the obvious workaround, using #, which you don't want.
Summarizing an interesting comment discussion with Gerry: Passing the variable by reference is indeed valid if you check for the value of the variable inside the function and handle undefined or null cases properly. Just don't use reference passing as a way of shutting PHP up (this is where my original shouldn't points to).

You can do this using func_get_args like so:
error_reporting(E_ALL);
ini_set('display_errors', 1);
function defaultValue() {
$args = func_get_args();
foreach($args as $arg) {
if (!is_array($arg)) {
$arg = array($arg);
}
foreach($arg as $a) {
if(!empty($a)) {
return $a;
}
}
}
return false;
}
$var = 'bob';
echo defaultValue(compact('var'), 'alpha') . "\n"; //returns 'bob'
echo defaultValue(compact('var2'), 'alpha') . "\n"; //returns 'alpha'
echo defaultValue('alpha') . "\n"; //return
echo defaultValue() . "\n";
This func goes one step further and would give you the first non empty value of any number of args (you could always force it to only take up to two args but this look more useful to me like this).
EDIT: original version didn't use compact to try and make an array of args and STILL gave an error. Error reporting bumped up a notch and this new version with compact is a little less tidy, but still does the same thing and allows you to provide a default value for non existent vars.

There are valid cases where checking becomes cumbersome and unnessesary.
Therfore i've written this little magic function:
/**
* Shortcut for getting a value from a possibly unset variable.
* Normal:
* if (isset($_GET['foo']) && $_GET['foo'] == 'bar') {
* Short:
* if (value($_GET['foo']) == 'bar') {
*
* #param mixed $variable
* #return mixed Returns null if not set
*/
function value(&$variable) {
if (isset($variable)) {
return $variable;
}
}
It doesn't require any changes to myHappyFunction().
You'll have to change
myHappyFunction($someBogusVar);
to
myHappyFunction(value($someBogusVar));
Stating your intent explicitly. which makes it good practice in my book.

No, because this isn't really anything to do with the function; the error is coming from attempting to de-reference a non-existent array key. You can change the warning level of your PHP setup to surpress these errors, but you're better off just not doing this.
Having said that, you could do something like
function safeLookup($array, $key)
{
if (isset($array, $key))
return $array[$key];
return 0;
}
And use it in place of array key lookup
defaultValue(safeLookup($foo, "bar"), "baz);
Now I need to take a shower :)

is it possible to write a function in a way where invalid arguments or non existent variables can be passed in and php will not error without the use of '#'
Yes you can!
porneL is correct [edit:I don't have enough points to link to his answer or vote it up, but it's on this page]
He is also correct when he cautions "But I recommend against abusing this for hiding programming errors." however error suppression via the Error Control Operator (#) should also be avoided for this same reason.
I'm new to Stack Overflow, but I hope it's not common for an incorrect answer to be ranked the highest on a page while the correct answer receives no votes. :(

#Brian: I use a trinary operation to do the check for me:
return $value ? $value : $default;
this returns either $value OR $default. Depending upon the value of $value. If it is 0, false, empty or anything similar the value in $default will be returned.
I'm more going for the challenge to emulate functions like empty() and isset()

#Sean That was already answered by Brian
return isset($input) ? $input : $default;

Sean, you could do:
$result = ($func_result = doLargeIntenseFunction()) ? $func_result : 'no result';
EDIT:
I'm sure there could be a great
discussion on ternary operators vrs
function calls. But the point of this
question was to see if we can create a
function that won't throw an error if
a non existent value is passed in
without using the '#'
And I told you, check it with isset(). A ternary conditional's first part doesn't check null or not null, it checks true or false. If you try to check true or false on a null value in PHP, you get these warnings. isset() checks whether a variable or expression returns a null value or not, and it returns a boolean, which can be evaluated by the first part of your ternary without any errors.

I'm sure there could be a great discussion on ternary operators vrs function calls. But the point of this question was to see if we can create a function that won't throw an error if a non existent value is passed in without using the '#'

While the answer to the original question is "no", there is an options no one has mentioned.
When you use the # sign, all PHP is doing is overriding the error_reporting level and temporarily setting it to zero. You can use "ini_restore('error_reporting');" to set it back to whatever it was before the # was used.
This was useful to me in the situation where I wanted to write a convenience function to check and see if a variable was set, and had some other properties as well, otherwise, return a default value. But, sending an unset variable through caused a PHP notice, so I used the # to suppress that, but then set error_reporting back to the original value inside the function.
Something like:
$var = #foo($bar);
function foo($test_var)
{
ini_restore('error_reporting');
if(is_set($test_var) && strlen($test_var))
{
return $test_var;
}
else
{
return -1;
}
}
So, in the case above, if $bar is not set, I won't get an error when I call foo() with a non-existent variable. However, I will get an error from within the function where I mistakenly typed is_set instead of isset.
This could be a useful option covering what the original question was asking in spirit, if not in actual fact.

If you simply add a default value to the parameter, you can skip it when calling the function. For example:
function empty($paramName = ""){
if(isset($paramName){
//Code here
}
else if(empty($paramName)){
//Code here
}
}

With a single line, you can acomplish it: myHappyFunction($someBogusVar="");
I hope this is what you are looking for. If you read the php documentation, under default argument values, you can see that assigning a default value to an function's argument helps you prevent an error message when using functions.
In this example you can see the difference of using a default argument and it's advantages:
PHP code:
<?php
function test1($argument)
{
echo $argument;
echo "\n";
}
function test2($argument="")
{
echo $argument;
echo "\n";
}
test1();
test1("Hello");
test1($argument);
$argument = "Hello world";
test1($argument);
test2();
test2("Hello");
test2($argument);
$argument = "Hello world";
test2($argument);
?>
Output for test1() lines:
Warning: Missing argument 1 for test1() .
Hello.
.
Hello world.
Output for test2() lines:
.
Hello.
Hello world.
This can also be used in combination to isset() and other functions to accomplish what you want.

And going further up the abstraction tree, what are you using this for?
You could either initialize those values in each class as appropriate or create a specific class containing all the default values and attributes, like:
class Configuration {
private var $configValues = array( 'cool' => 'Defaultcoolval' ,
'uncool' => 'Defuncoolval' );
public setCool($val) {
$this->configValues['cool'] = $val;
}
public getCool() {
return $this->configValues['cool'];
}
}
The idea being that, when using defaultValue function everywhere up and down in your code, it will become a maintenance nightmare whenever you have to change a value, looking for all the places where you've put a defaultValue call. And it'll also probably lead you to repeat yourself, violating DRY.
Whereas this is a single place to store all those default values. You might be tempted to avoid creating those setters and getters, but they also help in maintenance, in case it becomse pertinent to do some modification of outputs or validation of inputs.

Related

I am installing the script and getting the error "Can't use method return value in write context" [duplicate]

I would think the following piece of code should work, but it doesn't (Edited: Now works in PHP 5.5+):
if (!empty($r->getError()))
Where getError() is simply:
public function getError()
{
return $this->error;
}
Yet I end up with this error:
can't use method return value in write context
What does this mean? Isn't this just a read?
empty() needs to access the value by reference (in order to check whether that reference points to something that exists), and PHP before 5.5 didn't support references to temporary values returned from functions.
However, the real problem you have is that you use empty() at all, mistakenly believing that "empty" value is any different from "false".
Empty is just an alias for !isset($thing) || !$thing. When the thing you're checking always exists (in PHP results of function calls always exist), the empty() function is nothing but a negation operator.
PHP doesn't have concept of emptyness. Values that evaluate to false are empty, values that evaluate to true are non-empty. It's the same thing. This code:
$x = something();
if (empty($x)) …
and this:
$x = something();
if (!$x) …
has always the same result, in all cases, for all datatypes (because $x is defined empty() is redundant).
Return value from the method always exists (even if you don't have return statement, return value exists and contains null). Therefore:
if (!empty($r->getError()))
is logically equivalent to:
if ($r->getError())
Note: This is a very high voted answer with a high visibility, but please note that it promotes bad, unnecessary coding practices! See #Kornel's answer for the correct way.
Note #2: I endorse the suggestions to use #Kornel's answer. When I wrote this answer three years ago, I merely meant to explain the nature of the error, not necessarily endorse the alternative. The code snippet below is not recommended.
It's a limitation of empty() in PHP versions below 5.5.
Note: empty() only checks variables as
anything else will result in a parse
error. In other words, the following
will not work: empty(trim($name)).
You'd have to change to this
// Not recommended, just illustrates the issue
$err = $r->getError();
if (!empty($err))
Prior to PHP 5.5, the the PHP docs used to say:
empty() only checks variables as anything else will result in a parse error
In PHP < 5.5 you weren't able use empty() directly on a function's return value. Instead, you could assign the return from getError() to a variable and run empty() on the variable.
In PHP >= 5.5 this is no longer necessary.
I usually create a global function called is_empty() just to get around this issue
function is_empty($var)
{
return empty($var);
}
Then anywhere I would normally have used empty() I just use is_empty()
As pointed out by others, it's a (weird) limitation of empty().
For most purproses, doing this is equal as calling empty, but this works:
if ($r->getError() != '')
The issue is this, you want to know if the error is not empty.
public function getError() {
return $this->error;
}
Adding a method isErrorSet() will solve the problem.
public function isErrorSet() {
if (isset($this->error) && !empty($this->error)) {
return true;
} else {
return false;
}
}
Now this will work fine with this code with no notice.
if (!($x->isErrorSet())) {
echo $x->getError();
}
I'm not sure if this would be a common mistake, but if you do something like:
$var = 'value' .= 'value2';
this will also produce the same error
Can't use method return value in write context
You can't have an = and a .= in the same statement. You can use one or the other, but not both.
Note, I understand this is unrelated to the actual code in the question, however this question is the top result when searching for the error message, so I wanted to post it here for completeness.
The alternative way to check if an array is empty could be:
count($array)>0
It works for me without that error

Fatal error: Can't use method return value in write context in /home/xeontech/public_html/hrms/application/controllers/admin/Profile.php on line 191 [duplicate]

I would think the following piece of code should work, but it doesn't (Edited: Now works in PHP 5.5+):
if (!empty($r->getError()))
Where getError() is simply:
public function getError()
{
return $this->error;
}
Yet I end up with this error:
can't use method return value in write context
What does this mean? Isn't this just a read?
empty() needs to access the value by reference (in order to check whether that reference points to something that exists), and PHP before 5.5 didn't support references to temporary values returned from functions.
However, the real problem you have is that you use empty() at all, mistakenly believing that "empty" value is any different from "false".
Empty is just an alias for !isset($thing) || !$thing. When the thing you're checking always exists (in PHP results of function calls always exist), the empty() function is nothing but a negation operator.
PHP doesn't have concept of emptyness. Values that evaluate to false are empty, values that evaluate to true are non-empty. It's the same thing. This code:
$x = something();
if (empty($x)) …
and this:
$x = something();
if (!$x) …
has always the same result, in all cases, for all datatypes (because $x is defined empty() is redundant).
Return value from the method always exists (even if you don't have return statement, return value exists and contains null). Therefore:
if (!empty($r->getError()))
is logically equivalent to:
if ($r->getError())
Note: This is a very high voted answer with a high visibility, but please note that it promotes bad, unnecessary coding practices! See #Kornel's answer for the correct way.
Note #2: I endorse the suggestions to use #Kornel's answer. When I wrote this answer three years ago, I merely meant to explain the nature of the error, not necessarily endorse the alternative. The code snippet below is not recommended.
It's a limitation of empty() in PHP versions below 5.5.
Note: empty() only checks variables as
anything else will result in a parse
error. In other words, the following
will not work: empty(trim($name)).
You'd have to change to this
// Not recommended, just illustrates the issue
$err = $r->getError();
if (!empty($err))
Prior to PHP 5.5, the the PHP docs used to say:
empty() only checks variables as anything else will result in a parse error
In PHP < 5.5 you weren't able use empty() directly on a function's return value. Instead, you could assign the return from getError() to a variable and run empty() on the variable.
In PHP >= 5.5 this is no longer necessary.
I usually create a global function called is_empty() just to get around this issue
function is_empty($var)
{
return empty($var);
}
Then anywhere I would normally have used empty() I just use is_empty()
As pointed out by others, it's a (weird) limitation of empty().
For most purproses, doing this is equal as calling empty, but this works:
if ($r->getError() != '')
The issue is this, you want to know if the error is not empty.
public function getError() {
return $this->error;
}
Adding a method isErrorSet() will solve the problem.
public function isErrorSet() {
if (isset($this->error) && !empty($this->error)) {
return true;
} else {
return false;
}
}
Now this will work fine with this code with no notice.
if (!($x->isErrorSet())) {
echo $x->getError();
}
I'm not sure if this would be a common mistake, but if you do something like:
$var = 'value' .= 'value2';
this will also produce the same error
Can't use method return value in write context
You can't have an = and a .= in the same statement. You can use one or the other, but not both.
Note, I understand this is unrelated to the actual code in the question, however this question is the top result when searching for the error message, so I wanted to post it here for completeness.
The alternative way to check if an array is empty could be:
count($array)>0
It works for me without that error

PHP - Pass a variable to a function, even if undefined

I have the following snippet:
// Some post is made and I have access to it using Input::get('name_of_field');
if (Input::has('optionalField'))
{
$thisVariable = myMagicalFunction();
}
// more operation
// being performed
ultimateFunction($thisVariable);
return true;
As you can see, $thisVariable may sometimes not be set, and so the ultimateFunction($thisVariable) may sometimes return error saying the variable is undefined. I can of course use
if (isset($thisVariable)) ultimateFunction($thisVariable);
But is there a way to force pass the variable anyhow without checking if it is set? I will then check if it is set inside ultimateFunction.
The simplest way is to just declare the variable before it is used:-
$thisVariable = null;
if (Input::has('optionalField'))
{
$thisVariable = myMagicalFunction();
}
// more operation
// being performed
ultimateFunction($thisVariable);
return true;
You can suppress the error with #, so:
ultimateFunction(#$thisVariable);
But it's better to check first. I personally use # all the time. It's bad practice.
It is at best a hack to suppress your error this way. You are ignoring warnings and writing code which is not optimized. Even though it saves you a bit of time, I strongly suggest you avoid doing this.
Ideally, create a service container for $_GET and $_POST which performs this check for you. It can return null if it does not exist.
Alternatively, a procedural answer is something like this:
function formGet($input) {
if(isset($_GET[$input])) {
return $_GET[$input];
}
return false;
}
Now you can simply input your data using formGet($input).
It is possible to use PHP's error control operator (at-sign):
// ...
ultimateFunction(#$thisVariable);
There will be null force-passed as the ultimateFunction's first argument and inside function you will be able to normally check with isset() or empty() whether variable was passed.
But if it is possible, that does not mean you should use it. As #degenerate said too, it is really bad practice, because PHP parser expands the code above using # operator to code snippet like following:
$old = error_reporting(0);
ultimateFunction($thisVariable);
error_reporting($old);
Additionally use of this operator might slower the application.

Fatal error: Can't use function return value in write context

I have a pretty nasty error I can't get rid of. Here's the function causing the issue:
function get_info_by_WatIAM($WatIAM, $info) {
$users_info = array();
exec("uwdir -v userid={$WatIAM}", $users_info);
foreach ($users_info as $user_info) {
$exploded_info = explode(":", $user_info);
if (isset($exploded_info[1])){
$infoArray[$exploded_info[0]] = $exploded_info[1];
}
}
return $infoArray[$info]; }
Here's what's calling the function:
} elseif ( empty(get_info_by_WatIAM($_POST['ownerId'])) ) { ...
I would really appreciate any suggestion. Thanks very much!
If the code doesn't make sense, here's a further explanation: exec uses a program that stores information on all the users in a school. These include things like faculty, name, userid, etc. The $_POST['ownerId'] is a username -- the idea is that, upon entering a username, all of the user's information is automatically filled in
You do not need empty around function calls, in fact empty only works with variables and not functions (as you see). You only need empty if you want to test a variable that may not be set for thruthiness. It is pointless around a function call, since that function call must exist. Instead simply use:
} else if (!get_info_by_WatIAM($_POST['ownerId'])) { ...
It does the same thing. For an in-depth explanation, read The Definitive Guide To PHP's isset And empty.
empty can only be used on variables, not on expressions (such as the result of calling a function). There's a warning on the documentation page:
Note:
empty() only checks variables as anything else will result in a parse
error. In other words, the following will not work: empty(trim($name)).
Just one of PHP's best-left-alone quirks.
One workaround is to store the result in a variable and call empty on that, although it's clunky. In this specific case, you can also use
if (!get_info_by_WatIAM(...))
...although in general, if (empty($a)) and if(!$a) are not equivalent.
get the value of this
$a = get_info_by_WatIAM($_POST['ownerId'])
then chack
empty($a)
it will work

PHP: Best Practices for Silent Failure

I find myself doing this a lot:
$something = #$_GET['else'];
if ($something) {
// ...
} else {
// ...
}
Like, almost whenever I deal with arrays. I'm used to JavaScript and the ability to simply check for a falsy value. But is this appropriate in PHP? Am I trying to force PHP to be something I already understand, instead of learning it as its own language?
EDIT
I udnerstand that I can just use isset (I also *under*stand it), but it feels clunky to me, and it leads to even clunkier situations where I'm trying to echo the value:
// what I want to do
echo '<input type="text" name="whatever" value="', #$values['whatever'], '" />';
// what I fear I must do
echo '<input type="text" name="whatever" value="';
if (isset($values['whatever'])) {
echo $values['whatever'];
}
echo '" />';
Setting aside the sanitation issue, I prefer the first version. But I have a sneaking suspiscion that it's a big no-no. (I also have a sneaking suspicion that I don't know how to spell "suspicion.")
I recommend NEVER using the # operator. It encourages bad code and can make your life miserable when something doesn't work and you're trying to debug it.
You can of course disable notices in php.ini, but if I were you I would start using isset() more :)
You can do something like this:
echo '<input type="text" name="whatever" value="', (isset($values['whatever'])?$values['whatever']:''), '" />';
You can read more about how horrible # is, here: http://php.net/manual/en/language.operators.errorcontrol.php
Well, it's the actual error triggering that is expensive. Using # triggers the error. Checking with isset() instead, does not. http://seanmonstar.com/post/909029460/php-error-suppression-performance
To answer the title: Best way is to turn off display_errors.
For what you're doing specifically, use isset().
Note: To those complaining that this 'turns off' all errors -- from the PHP manual:
This is a feature to support your development and should never be used on production systems (e.g. systems connected to the internet).
After the Edit: You could either make sure the variables you're going to use have some value (just blindly echoing a get/post var isn't the best practice) - or you could use an object to store the variables you want to output (as properties) and use __get() to return an empty string (or a false) when the property hasn't been set.
That would leave you with something like:
echo $view->something;
if($view->something){
//stuff to do when something is set
}
I believe that would be similar to what a lot of template/view libraries do.
Update: Noticed this old(ish) answer, and thought something could be added to it. For this use case (where values may or may not be in an array), array_merge() could be used:
$default = array('user' => false);
$params = array_merge($default, $_GET);
if($params['user']){ //safe to use, will have default value if not in $_GET
}
Why you want to surpress something, that will not occur, if you check the array before accessing it?
$something = array_key_exists('else', $_GET) ? $_GET['else'] : null;
$something = isset($_GET['else']) ? $_GET['else'] : null;
Your way seems to be just the solution for the lazy ones.
However, the #-operator is never a good idea as long as you can avoid it (and there are really very less situation, where you cant avoid it). Its also quite inperformant.
Use a general function for array accesses:
/**
* Function for accessing array elements and returning a
* default value if the element is not set or null.
* #param string $key Name of index
* #param array $array Reference to an array
* #param string $default Value to return if the key is not
* found in the array
* #return mixed Value of array element (if it exists) or whatever
* is passed for default.
*/
function element( $key, &$a, $default = '' )
{
if( array_key_exists( $key, $a ) && !is_null( $a[$k] ) )
{
return $a[$key];
}
return $default;
}
Then your HTML output can look like this:
echo '<input type="text" name="whatever" value="'
, element( 'whatever', $values ), '" />'
;
I've said it before and am happy to say it again:
$else = isset($_GET['else']) ? $_GET['else'] : null;
Is equivalent to:
$else = #$_GET["else"];
The difference is that one is less readable due to syntactic salt for error suppression, and the other uses the intended language feature for that. Also notice how in the second case the notice (many people don't comprehend the difference to errors) can still be uncovered by custom handlers.
For all practical purposes you should use neither. Use simply:
$else = $_GET["else"];
Turn off debug notices while you don't need them.
(Practically I'm also usually using the dumb isset() method. But I'm using object-oriented superglobals, rather than PHP4-style $_POST and $_GET arrays, so it's just one hidden isset() and doesn't pollute my code.)
This is a common problem and while the solution is simple, you're right that it's not pretty. Personally I like to use wrappers. You can very easily write a simple class that implements ArrayAccess by wrapping the array passed in. It would do the key check internally (in one place), and quietly return null when asked for a non-existent key. The result looks something like this:
'bar'));
var_dump($arr['foo']);
var_dump($arr['zing']);
// string(3) "bar"
// NULL
?>
This may also feel more familiar to you, coming from Javascript, as you can add new functionality to the class as well, like custom sorting, or maybe filtering.

Categories