Saturday, December 19, 2009

Can is_string() be used without an isset() for unset variables in PHP?

The Short Answer


Yes, if there is the potential for an undeclared variable to be passed to functions like is_string(), then you must use the isset() function first.

Example:

if(isset($foo) && is_string($foo)) {
    // Do something with $foo
}


The Long Answer


I recently had an error occur in a 3rd party function I use on my web site. The code assumed that at a certain point that a variable would be set and a string function could be run against it. I wanted to modify the if statement to check to see if the variable was a string before continuing with the said block of code. What I did not know was whether or not the is_string function in PHP worked in the same way as the instanceOf operator in Java. In Java, you do not need to detect if the variable is null before the operation, because instanceOf has the built in ability to determine that a null is not an instance of anything.

The reason I wanted to test this is because the error resulted after a customer interaction with the site that I am not able to reproduce (this is intentional, because it involves translating a user's file, which I do not keep a copy of in accordance with my privacy statement).

Example Code


To test this I wrote a PHP page to determines what happens when a variable is in different states. I also expanded the testing to include is_array, is_bool, is_float, is_int, and is_object. I also include some custom error handling, so you can try this at home without filling up your error log.

To see this in action: Using is_string() and isset() Demo

<?php
/* we will do our own error handling */
function jamErrorHandler($errno, $errmsg, $filename, $linenum, $vars) {
    $errortype = array (
        E_ERROR => 'Error',
        E_WARNING => 'Warning',
        E_PARSE => 'Parsing Error',
        E_NOTICE => 'Notice',
        E_CORE_ERROR => 'Core Error',
        E_CORE_WARNING => 'Core Warning',
        E_COMPILE_ERROR => 'Compile Error',
        E_COMPILE_WARNING => 'Compile Warning',
        E_USER_ERROR => 'User Error',
        E_USER_WARNING => 'User Warning',
        E_USER_NOTICE => 'User Notice',
        E_ALL                => 'All Error',
        E_STRICT         => 'Strict Error',
        E_RECOVERABLE_ERROR    => 'Recoverable Error'
    );
    print '<strong>* ' . $errortype[$errno] . ': ' . $errmsg . ' *</strong><br />';
}
function jamExceptionHandler($exception){
    jamErrorHandler($exception->getCode(), $exception->getMessage(), $exception->getFile(), $exception->getLine(), $exception->getTrace());
}
set_error_handler('jamErrorHandler');
set_exception_handler('jamExceptionHandler');
print '<h2>$foo = 123</h2>';
$foo = 123;
if(isset($foo)) {
    print '<strong>$foo is set.</strong><br />';
} else {
    print '$foo is not set.<br />';
}
if(isset($foo) && is_string($foo)) {
    print '<strong>$foo isset and is a string.</strong><br />';
} else {
    if(isset($foo)){
        print '$foo isset, but is not a string.<br />';
    } else {
        print '$foo is not set, so is not string.<br />';
    }
}
if(is_string($foo)) {
    print '<strong>$foo is a string.</strong><br />';
} else {
    print '$foo is not a string.<br />';
}
if(is_float($foo)) {
    print '<strong>$foo is a float.</strong><br />';
} else {
    print '$foo is not a float.<br />';
}
if(is_int($foo)) {
    print '<strong>$foo is an integer.</strong><br />';
} else {
    print '$foo is not an integer.<br />';
}
if(is_bool($foo)) {
    print '<strong>$foo is a boolean.</strong><br />';
} else {
    print '$foo is not a boolean.<br />';
}
if(is_object($foo)) {
    print '<strong>$foo is an object.</strong><br />';
} else {
    print '$foo is not an object.<br />';
}
if(is_array($foo)) {
    print '<strong>$foo is an array.</strong><br />';
} else {
    print '$foo is not an array.<br />';
}
print '<h2>$foo = 123.456</h2>';
$foo = 123.456;
if(isset($foo)) {
    print '<strong>$foo is set.</strong><br />';
} else {
    print '$foo is not set.<br />';
}
if(isset($foo) && is_string($foo)) {
    print '<strong>$foo isset and is a string.</strong><br />';
} else {
    if(isset($foo)){
        print '$foo isset, but is not a string.<br />';
    } else {
        print '$foo is not set, so is not string.<br />';
    }
}
if(is_string($foo)) {
    print '<strong>$foo is a string.</strong><br />';
} else {
    print '$foo is not a string.<br />';
}
if(is_float($foo)) {
    print '<strong>$foo is a float.</strong><br />';
} else {
    print '$foo is not a float.<br />';
}
if(is_int($foo)) {
    print '<strong>$foo is an integer.</strong><br />';
} else {
    print '$foo is not an integer.<br />';
}
if(is_bool($foo)) {
    print '<strong>$foo is a boolean.</strong><br />';
} else {
    print '$foo is not a boolean.<br />';
}
if(is_object($foo)) {
    print '<strong>$foo is an object.</strong><br />';
} else {
    print '$foo is not an object.<br />';
}
if(is_array($foo)) {
    print '<strong>$foo is an array.</strong><br />';
} else {
    print '$foo is not an array.<br />';
}
print '<h2>$foo = \'123\'</h2>';
$foo = '123';
if(isset($foo)) {
    print '<strong>$foo is set.</strong><br />';
} else {
    print '$foo is not set.<br />';
}
if(isset($foo) && is_string($foo)) {
    print '<strong>$foo isset and is a string.</strong><br />';
} else {
    if(isset($foo)){
        print '$foo isset, but is not a string.<br />';
    } else {
        print '$foo is not set, so is not string.<br />';
    }
}
if(is_string($foo)) {
    print '<strong>$foo is a string.</strong><br />';
} else {
    print '$foo is not a string.<br />';
}
if(is_float($foo)) {
    print '<strong>$foo is a float.</strong><br />';
} else {
    print '$foo is not a float.<br />';
}
if(is_int($foo)) {
    print '<strong>$foo is an integer.</strong><br />';
} else {
    print '$foo is not an integer.<br />';
}
if(is_bool($foo)) {
    print '<strong>$foo is a boolean.</strong><br />';
} else {
    print '$foo is not a boolean.<br />';
}
if(is_object($foo)) {
    print '<strong>$foo is an object.</strong><br />';
} else {
    print '$foo is not an object.<br />';
}
if(is_array($foo)) {
    print '<strong>$foo is an array.</strong><br />';
} else {
    print '$foo is not an array.<br />';
}
print '<h2>$foo = \'abc\'</h2>';
$foo = 'abc';
if(isset($foo)) {
    print '<strong>$foo is set.</strong><br />';
} else {
    print '$foo is not set.<br />';
}
if(isset($foo) && is_string($foo)) {
    print '<strong>$foo isset and is a string.</strong><br />';
} else {
    if(isset($foo)){
        print '$foo isset, but is not a string.<br />';
    } else {
        print '$foo is not set, so is not string.<br />';
    }
}
if(is_string($foo)) {
    print '<strong>$foo is a string.</strong><br />';
} else {
    print '$foo is not a string.<br />';
}
if(is_float($foo)) {
    print '<strong>$foo is a float.</strong><br />';
} else {
    print '$foo is not a float.<br />';
}
if(is_int($foo)) {
    print '<strong>$foo is an integer.</strong><br />';
} else {
    print '$foo is not an integer.<br />';
}
if(is_bool($foo)) {
    print '<strong>$foo is a boolean.</strong><br />';
} else {
    print '$foo is not a boolean.<br />';
}
if(is_object($foo)) {
    print '<strong>$foo is an object.</strong><br />';
} else {
    print '$foo is not an object.<br />';
}
if(is_array($foo)) {
    print '<strong>$foo is an array.</strong><br />';
} else {
    print '$foo is not an array.<br />';
}
print '<h2>$foo = date(\'r\')</h2>';
$foo = date('r');
if(isset($foo)) {
    print '<strong>$foo is set.</strong><br />';
} else {
    print '$foo is not set.<br />';
}
if(isset($foo) && is_string($foo)) {
    print '<strong>$foo isset and is a string.</strong><br />';
} else {
    if(isset($foo)){
        print '$foo isset, but is not a string.<br />';
    } else {
        print '$foo is not set, so is not string.<br />';
    }
}
if(is_string($foo)) {
    print '<strong>$foo is a string.</strong><br />';
} else {
    print '$foo is not a string.<br />';
}
if(is_float($foo)) {
    print '<strong>$foo is a float.</strong><br />';
} else {
    print '$foo is not a float.<br />';
}
if(is_int($foo)) {
    print '<strong>$foo is an integer.</strong><br />';
} else {
    print '$foo is not an integer.<br />';
}
if(is_bool($foo)) {
    print '<strong>$foo is a boolean.</strong><br />';
} else {
    print '$foo is not a boolean.<br />';
}
if(is_object($foo)) {
    print '<strong>$foo is an object.</strong><br />';
} else {
    print '$foo is not an object.<br />';
}
if(is_array($foo)) {
    print '<strong>$foo is an array.</strong><br />';
} else {
    print '$foo is not an array.<br />';
}
print '<h2>$foo = true</h2>';
$foo = true;
if(isset($foo)) {
    print '<strong>$foo is set.</strong><br />';
} else {
    print '$foo is not set.<br />';
}
if(isset($foo) && is_string($foo)) {
    print '<strong>$foo isset and is a string.</strong><br />';
} else {
    if(isset($foo)){
        print '$foo isset, but is not a string.<br />';
    } else {
        print '$foo is not set, so is not string.<br />';
    }
}
if(is_string($foo)) {
    print '<strong>$foo is a string.</strong><br />';
} else {
    print '$foo is not a string.<br />';
}
if(is_float($foo)) {
    print '<strong>$foo is a float.</strong><br />';
} else {
    print '$foo is not a float.<br />';
}
if(is_int($foo)) {
    print '<strong>$foo is an integer.</strong><br />';
} else {
    print '$foo is not an integer.<br />';
}
if(is_bool($foo)) {
    print '<strong>$foo is a boolean.</strong><br />';
} else {
    print '$foo is not a boolean.<br />';
}
if(is_object($foo)) {
    print '<strong>$foo is an object.</strong><br />';
} else {
    print '$foo is not an object.<br />';
}
if(is_array($foo)) {
    print '<strong>$foo is an array.</strong><br />';
} else {
    print '$foo is not an array.<br />';
}
print '<h2>$foo = false</h2>';
$foo = false;
if(isset($foo)) {
    print '<strong>$foo is set.</strong><br />';
} else {
    print '$foo is not set.<br />';
}
if(isset($foo) && is_string($foo)) {
    print '<strong>$foo isset and is a string.</strong><br />';
} else {
    if(isset($foo)){
        print '$foo isset, but is not a string.<br />';
    } else {
        print '$foo is not set, so is not string.<br />';
    }
}
if(is_string($foo)) {
    print '<strong>$foo is a string.</strong><br />';
} else {
    print '$foo is not a string.<br />';
}
if(is_float($foo)) {
    print '<strong>$foo is a float.</strong><br />';
} else {
    print '$foo is not a float.<br />';
}
if(is_int($foo)) {
    print '<strong>$foo is an integer.</strong><br />';
} else {
    print '$foo is not an integer.<br />';
}
if(is_bool($foo)) {
    print '<strong>$foo is a boolean.</strong><br />';
} else {
    print '$foo is not a boolean.<br />';
}
if(is_object($foo)) {
    print '<strong>$foo is an object.</strong><br />';
} else {
    print '$foo is not an object.<br />';
}
if(is_array($foo)) {
    print '<strong>$foo is an array.</strong><br />';
} else {
    print '$foo is not an array.<br />';
}
print '<h2>$foo = array(\'1\', \'a\')</h2>';
$foo = array('1', 'a');
if(isset($foo)) {
    print '<strong>$foo is set.</strong><br />';
} else {
    print '$foo is not set.<br />';
}
if(isset($foo) && is_string($foo)) {
    print '<strong>$foo isset and is a string.</strong><br />';
} else {
    if(isset($foo)){
        print '$foo isset, but is not a string.<br />';
    } else {
        print '$foo is not set, so is not string.<br />';
    }
}
if(is_string($foo)) {
    print '<strong>$foo is a string.</strong><br />';
} else {
    print '$foo is not a string.<br />';
}
if(is_float($foo)) {
    print '<strong>$foo is a float.</strong><br />';
} else {
    print '$foo is not a float.<br />';
}
if(is_int($foo)) {
    print '<strong>$foo is an integer.</strong><br />';
} else {
    print '$foo is not an integer.<br />';
}
if(is_bool($foo)) {
    print '<strong>$foo is a boolean.</strong><br />';
} else {
    print '$foo is not a boolean.<br />';
}
if(is_object($foo)) {
    print '<strong>$foo is an object.</strong><br />';
} else {
    print '$foo is not an object.<br />';
}
if(is_array($foo)) {
    print '<strong>$foo is an array.</strong><br />';
} else {
    print '$foo is not an array.<br />';
}
print '<h2>$foo = jamObject()</h2>';
class jamObject {
function test() {
print 'test';
}
}
$foo = new jamObject();
if(isset($foo)) {
    print '<strong>$foo is set.</strong><br />';
} else {
    print '$foo is not set.<br />';
}
if(isset($foo) && is_string($foo)) {
    print '<strong>$foo isset and is a string.</strong><br />';
} else {
    if(isset($foo)){
        print '$foo isset, but is not a string.<br />';
    } else {
        print '$foo is not set, so is not string.<br />';
    }
}
if(is_string($foo)) {
    print '<strong>$foo is a string.</strong><br />';
} else {
    print '$foo is not a string.<br />';
}
if(is_float($foo)) {
    print '<strong>$foo is a float.</strong><br />';
} else {
    print '$foo is not a float.<br />';
}
if(is_int($foo)) {
    print '<strong>$foo is an integer.</strong><br />';
} else {
    print '$foo is not an integer.<br />';
}
if(is_bool($foo)) {
    print '<strong>$foo is a boolean.</strong><br />';
} else {
    print '$foo is not a boolean.<br />';
}
if(is_object($foo)) {
    print '<strong>$foo is an object.</strong><br />';
} else {
    print '$foo is not an object.<br />';
}
if(is_array($foo)) {
    print '<strong>$foo is an array.</strong><br />';
} else {
    print '$foo is not an array.<br />';
}
print '<h2>unset($foo)</h2>';
unset($foo);
if(isset($foo)) {
    print '<strong>$foo is set.</strong><br />';
} else {
    print '$foo is not set.<br />';
}
if(isset($foo) && is_string($foo)) {
    print '<strong>$foo isset and is a string.</strong><br />';
} else {
    if(isset($foo)){
        print '$foo isset, but is not a string.<br />';
    } else {
        print '$foo is not set, so is not string.<br />';
    }
}
try {
    if(is_string($foo)) { // Produces error!
        print '<strong>$foo is a string.</strong><br />';
    } else {
        print '$foo is not a string.<br />';
    }
} catch (Exception $e) {
    print '<strong>Error in is_string($foo)</strong>' . $e->getMessage() . '<br />';
}
if(is_float($foo)) {
    print '<strong>$foo is a float.</strong><br />';
} else {
    print '$foo is not a float.<br />';
}
if(is_int($foo)) {
    print '<strong>$foo is an integer.</strong><br />';
} else {
    print '$foo is not an integer.<br />';
}
if(is_bool($foo)) {
    print '<strong>$foo is a boolean.</strong><br />';
} else {
    print '$foo is not a boolean.<br />';
}
if(is_object($foo)) {
    print '<strong>$foo is an object.</strong><br />';
} else {
    print '$foo is not an object.<br />';
}
if(is_array($foo)) {
    print '<strong>$foo is an array.</strong><br />';
} else {
    print '$foo is not an array.<br />';
}
?>