I have a custom validator function which checks different properties of a passed variable including if the variable isset(). However if the variable is not set, the warning is thrown when I call the validator function. The warnings are not displayed and the script runs without a hitch, but I don't want my error log cluttered with all of these entries.
The easy solution is to prefix all of the calls to the function with #, but I'd rather not for obvious reasons. Alternatively I could remove the isset() from the function (or leave it I guess) and instead place the isset() check along side the function call.
I can't see these being the only options; How else can I perform the isset() within the validator function while preventing these warnings from being logged. I'd like to still have undefined variables warnings logged overall, just not when calling this function.
Here is the function:
function validate_data($value, $required = false, $min = false, $max = false, $numeric = false, $email = false){
if($required === true && (!isset($value) || strlen(trim($value)) < 1) ){
return false;
}
if($min !== false && strlen(trim($value)) < $min){
return false;
}
if($max !== false && strlen(trim($value)) > $max){
return false;
}
if(strlen(trim($value)) > 0 && $numeric === true && (!is_numeric(trim($value)))){
return false;
}
if(strlen(trim($value)) > 0 && $email === true && !filter_var(trim($value), FILTER_VALIDATE_EMAIL)){
return false;
}
return true;
}//validate_data()
Here is an example call:
if(!$someClassName->validate_data($var, true, false, false, false, false)){
//Do some stuff
}
isset() and empty() are special functions which accept undefined variables without a warning. You cannot create your own function which accepts this.
But if you work with an undefined variable, you have probably other problems to deal with. Even if not needed in php it is good practise to initialize all variables. A (bad) workaround might be something like this:
if (!isset($var)) $var = null;
Related
Got an interesting issue. In some legacy code we have following statements.
if (empty($result['email_address']) && empty($result['mobile_number'])) {
$token = '';
} else {
$tokenFinder = new TokenFinder();
$tokenFinder->setEmailAddress($result['email_address']);
$tokenFinder->setMobileNumber($result['mobile_number']);
$token = $tokenFinder->generate();
}
The relevant bits of the token finder look like the following:
class TokenFinder{
public function setEmailAddress($email) {
$this->email = $email;
}
public function setMobileNumber($mobile) {
$this->mobile = $mobile;
}
public function generate(){
if ($this->email == '' && $this->mobile == ''){
Throw new Exception('TokenFinder: You cannot fetch a token with no email or mobile number');
}
Yesterday, for the first time ever, the exception in the generate() method was triggered. I have run all of the recipients in the failed message through this block of code and the exception doesn't trigger. The data has not changed since the Exception was thrown. It is a strange one.
Does anyone know any values which will lead empty($var) to evaluate to false and $var == '' to evalute to true.
empty() returns true in case of:
empty string
0 integer
0.0 float
0 as string
null
false
empty array
empty variable
(see http://php.net/empty)
The error must lie in php's tricky type juggling. It could be, that $result['email_address'] or $result['mobile_numer'] contain an object which __toString implementation return an empty string. emtpy will see an object and == '' sees an empty string.
There could be dozens of other cases though. So your best possibility is to get rid of the logic duplication (the if statements) and implement maybe a static method in TokenFinder like isDataValid and use it to check the array outside of the class.
PHP manual:
empty() Returns FALSE if var exists and has a non-empty, non-zero
value. Otherwise returns TRUE.
Why does this code work correctly?
function isLoggedIn(){
return false; //or true
}
if($user = isLoggedIn())
{
echo "Hello ".$user['name']; //if isLoggedIn returns true, this prints
} else {
echo "Please login to proceed!";//if isLoggedIn returns false, this prints
}
I always thought assignment operator inside an if() condition will always evaluate to true since it is only evaluating whether the value of right hand side can be assigned to left hand side...
It's evaluating the value of $user after assigning the return of isLoggedIn() to $user. It's the same as:
$user = isLoggedIn();
if($user) {}
It's especially handy in loops:
while($var = someFunction()) {
//do stuff with $var
}
And more expressions:
if($var = someFunction() && $var !== 'bad') {}
if($var = someFunction() && $var === 'good') {}
In PHP, an assignment operation actually has a return value, and it's the value that was assigned. Your if() condition works for the exact same reason that
$x = $y = $z = 42;
works. This statement will assign the value 42 to all three variables, and is functionally the equivalent of
$z = 42;
$y = $z;
$x = $y;
In your case, your isLoggedIn() function call will execute and return a value. That value assigned to $user. Then that value is "returned" to the if() statement itself and is used for the logic test.
If your function had returned boolean false, or a "falsey" value, then the "else" clause would have executed. e.g.
function returns_false() {
return false;
}
if ($foo = returns_false()) {
echo 'if was true';
} else {
echo 'if was false'; // this line will get executed
}
Even though the assignment operation succeeded, it's the value that got assigned that matters, not the success/failure of the operation. so the "it was false" code path gets executed, because the function call returned a false, which propagated up the decision tree.
The condition considers $user after assignment.
Therefore it will be true or false depending on the value returned by isLoggedIn()
There is one note. Code like this will not work as expected:
if($var = someFunction() && $var !== 'bad') {}
if($var = someFunction() && $var === 'good') {}
Because $var will contain not a value returned by someFunction(), but a boolean value of the whole expression, like this:
$var = (someFunction() && $var !== 'bad');
if($var) {}
To get the result you need you should use brackets:
if(($var = someFunction()) && $var !== 'bad') {}
if(($var = someFunction()) && $var === 'good') {}
You can find details on the php.net website.
It works because the IF is TRUE. Oddly enough it will always be TRUE. Because you are assigning the value when you only use one = sign. If you want to check the contents, you have to use ==.
As everyone has already suggested, there are two parts to the statement:
It assigns the value of isLoggedIn() to $user.
It then returns the same value to whichever construct asked for it. In this case, it's
returned to the if () statement.
It is worth noting that although the if () statement expects to receive a boolean value true or false. If the if () receives a value that isn't a boolean, it is still acceptable in PHP (as well as JavaScript). If any operator or statement receives a value of the wrong type, PHP will convert it to boolean=true in most cases.
Say I have a long(ish) variable, $row['data']['manybullets']['bullets']['bullet'][0], and want to test whether it's set using the ternary operator:
$bulletx =
isset($row['data']['property']['bullets']['bullet'][0]) // condition
? $row['data']['property']['bullets']['bullet'][0] // true
: 'empty'; // false
Is there anyway for me to reference the subject of the expression rather than repeating it. E.g.
$bulletx =
isset($row['data']['property']['bullets']['bullet'][0]) // condition
? SUBJECT // true
: 'empty'; // false
Curious.
PHP supports foo ?: bar but unfortunately this won't work because of the isset() in your condition.
So unfortunately there is no really good way to do this in a shorter way. Besides using another language of course (e.g. foo.get(..., 'empty') in python)
However, if the default value being evaluated in any case is not a problem (e.g. because it's just a static value anyway) you can use a function:
function ifsetor(&$value, $default) {
return isset($value) ? $value : $default;
}
Because of the reference argument this will not throw an E_NOTICE in case of an undefined value.
You can do it like this:
$bulletx = ($r=$row['data']['property']['bullets']['bullet'][0]) ? $r : 'empty';
See working demo
Not really, without triggering an E_NOTICE warning, but if you decide to ignore those you could achieve it like this.
$bulletx =
$row['data']['property']['bullets']['bullet'][0] // true
?: 'empty'; // false
No built-in way, but you can write a wrapper for isset that checks the array keys.
function array_isset(&$array /* ... */) {
$a = $array;
if (! is_array($a)) {
return false;
}
for ($i = 1; $i < func_num_args(); $i++) {
$k = func_get_arg($i);
if (isset($a[$k])) {
$a = $a[$k];
} else {
return false;
}
}
return $a;
}
$bulletx = array_isset($row, 'data', 'property', 'bullets', 'bullet', 0) ?: 'empty';
I like this way, as it keeps the same API as isset() and can make use of the ?: short cut.
In the past when I needed to check if a variable was set and also a number, I would do:
if( isset($_GET['var']) && is_numeric($_GET['var']) )
But I think that's kind of ugly, especially when I need to check a bunch of variables in the same if statement, so I made a function:
function setAndNum($var)
{
if(isset($var) && is_numeric($var))
return 1;
else
return 0;
}
The problem is that when I pass an undefined variable to the function, like this (supposing the variable in the GET array is undefined):
if( setAndNum($_GET['var']) )
I get the php error:
Notice: Undefined index: ...
So the whole purpose of the function is basically defeated (or half the purpose, at least ;) ).
One thing that confuses me is how the isset() function works, and why I can pass an undefined variable to it but not to my own function?
Is it possible to make my setAndNum() function work?
Your problem is with $_GET being an array. When you pass $_GET['var'] to your function, this array value is already looked up and used as an argument to the function. Therefore you cannot effectively check the presence of 'var' in $_GET from within this function. You could rewrite it a bit to make it work for array values, something like this:
function setAndNum($key, $array)
{
if(array_key_exists($key, $array) && is_numeric($array[$key]))
return 1;
else
return 0;
}
Then call it like this:
if( setAndNum('var', $_GET) )
It's good practice to verify a key exists before using it:
if (array_key_exists($_GET, 'var')) {
// do stuff with $_GET['var']
}
function setAndNum(&$var)
{
if(isset($var) && is_numeric($var))
return 1;
else
return 0;
}
Please, try using this version:
function setAndNum(&$var)
{
if(isset($var) && is_numeric($var))
return 1;
else
return 0;
}
You can use the # operator to prevent error reporting:
setAndNum(#$_GET['var']);
This way, the error message of the non-existant index will not be printed, and the return value will be 0.
You could also write two functions, one that checks for an array and one that checks for normal variable
function setAndNum($var)
{
if(isset($var) && is_numeric($var))
return 1;
else
return 0;
}
function setAndNumArray($array, $key)
{
if(isset($array) && isset($array[$key]) && is_numeric($array[$key]))
return 1;
else
return 0;
}
if you are using variables from GET or POST method you may do like this as these are super globals.
function setAndNum()
{
if(isset($_GET['var']) && is_numeric($_GET['var']))
return 1;
else
return 0;
}
now coming to your another query. isset checks whether a variable is s et or not like
if(isset($_POST['submit']))
{
// any code under button click
}
I want to check if a variable called $smth is blank (I mean empty space), and I also want to check if it is set using the function I defined below:
function is_blank($var){
$var = trim($var);
if( $var == '' ){
return true;
} else {
return false;
}
}
The problem is I can't find a way to check if variable $smth is set inside is_blank() function. The following code solves my problem but uses two functions:
if( !isset($smth) || is_blank($smth) ){
// code;
}
If I use an undeclared variable as an argument for a function it says:
if( is_blank($smth) ){
//code;
}
Undefined variable: smth in D:\Www\www\project\code.php on line 41
Do you have a solution for this?
Solution
This is what I came up with:
function is_blank(&$var){
if( !isset($var) ){
return true;
} else {
if( is_string($var) && trim($var) == '' ){
return true;
} else {
return false;
}
}
}
and works like a charm. Thank you very much for the idea, NikiC.
Simply pass by reference and then do isset check:
function is_blank(&$var){
return !isset($var) || trim($var) == '';
}
Whenever you use a variable outside of empty and isset it will be checked if it was set before. So your solution with isset is correct and you cant' defer the check into the is_blank function. If you only want to check if the variable is empty, use just the empty function instead. But if you want to specifically check for an empty string after a trim operation, use isset + your is_blank function.
Use empty. It checks whether the variable is either 0, empty, or not set at all.
if(empty($smth))
{
//code;
}