Pastebin launched a little side project called HostCabi.net, check it out ;-)Don't like ads? PRO users don't see any ads ;-)
Guest

Boolean Loose Casting Function Tests

By: a guest on Jul 15th, 2012  |  syntax: PHP  |  size: 8.88 KB  |  hits: 27  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. <!doctype html>
  2. <html>
  3. <head>
  4.         <meta charset="utf-8">
  5.         <title>Boolean Loose Casting Function Tests</title>
  6.         <style>
  7.                 table {
  8.                         width: 100%;
  9.                 }
  10.                 td {
  11.                         width: 50%;
  12.                         border-bottom: 1px solid #ccc;
  13.                 }
  14.                 td.type {
  15.                         width: auto;
  16.                         font-weight: bold;
  17.                         color: #ccc;
  18.                 }
  19.                
  20.                 section {
  21.                         margin-bottom: 10em;
  22.                 }
  23.                 section h1 {
  24.                         background-color: #eee;
  25.                 }
  26.                
  27.                 .truthy {
  28.                         color: limegreen;
  29.                 }
  30.                 .falsy {
  31.                         color: red;
  32.                 }
  33.                 .null {
  34.                         color: orange;
  35.                 }
  36.         </style>
  37. </head>
  38. <body>
  39. <h1>Boolean Loose Casting Function Tests</h1>
  40. <h2>PHP Version <?php echo phpversion(); ?></h2>
  41. <?php
  42.         error_reporting(-1);
  43.  
  44.         /**
  45.          * some dummy classes used to create test objects
  46.          */
  47.         class StringyThing {
  48.                 private $value;
  49.                 public function __construct($value) {
  50.                         $this->value = $value;
  51.                 }
  52.                 public function __toString() {
  53.                         return (string) $this->value;
  54.                 }
  55.         }
  56.         class CountableThing implements Countable {
  57.                 private $values = array();
  58.                 public function __construct($values) {
  59.                         $this->values = $values;
  60.                 }
  61.                 public function count() {
  62.                         return count($this->values);
  63.                 }
  64.         }
  65.         class StringyAndCountableThing implements Countable {
  66.                 private $values = array();
  67.                 private $value;
  68.                 public function __construct($stringy_value, $countable_values) {
  69.                         $this->value = $stringy_value;
  70.                         $this->values = $countable_values;
  71.                 }
  72.                 public function count() {
  73.                         return count($this->values);
  74.                 }
  75.                 public function __toString() {
  76.                         return (string) $this->value;
  77.                 }
  78.         }
  79.        
  80.        
  81.         /**
  82.          * runs a test function on all test data, outputting tables of results
  83.          */
  84.         function run_test($test) {
  85.                 global $test_data;
  86.                 echo '<section>';
  87.                 echo '<h1>'.$test.'</h1>';
  88.        
  89.                 foreach($test_data as $set_name => $set) {
  90.                         echo '<h2>'.$set_name.'</h2>';
  91.                         echo '<table>';
  92.                         foreach($set as $index => $value) {
  93.                                 echo '<tr>';
  94.                                
  95.                                 echo '<td class="type">';
  96.                                 echo gettype($value);
  97.                                 echo '</td>';
  98.                                
  99.                                 echo '<td class="test-value">';
  100.                                 // be clever with test values
  101.                                 if(is_string($index)) {
  102.                                         // use the index as a placeholder representation
  103.                                         echo $index;
  104.                                 } else if(is_resource($value)) {
  105.                                         echo get_resource_type($value);
  106.                                 } else {
  107.                                         var_export($value);
  108.                                 }
  109.                                 echo '</td>';
  110.                                
  111.                                 $result = $test($value);
  112.                                
  113.                                 $class = ($result ? 'truthy' : 'falsy');
  114.                                 if(is_null($result)) $class .= ' null';
  115.                                 echo '<td class="test-result '.$class.'">';
  116.                                 var_export($result);
  117.                                 echo '</td>';
  118.                                
  119.                                 echo '</tr>';
  120.                         }
  121.                         echo '</table>';
  122.                 }
  123.                 echo '</section>';
  124.         };
  125.        
  126.        
  127.         /**
  128.          * data to run through for all tests
  129.          * string keys in subarrays can be used to represent values in test output
  130.          */
  131.         $test_data = array(
  132.                 'ought to be true' => array(
  133.                         true,
  134.                         1,
  135.                         'true',
  136.                         'yes',
  137.                         'YES',
  138.                         'on',
  139.                         '1',
  140.                         'y',
  141.                         'this should probably be TRUE',
  142.                         'รก',
  143.                         100,
  144.                         0.1,
  145.                         -1,
  146.                         INF,
  147.                         -INF,
  148.                        
  149.                         // for performance testing more than anything else
  150.                         // depending on the length used, may hit PHP's memory limit
  151.                         // http://www.php.net/manual/en/ini.core.php#ini.memory-limit
  152.                         // '(A VERY LONG STRING)' => str_repeat('.', 100000000),
  153.                        
  154.                         array(1),
  155.                         array('a key' => true),
  156.                         array(null => true),
  157.                        
  158.                         simplexml_load_string('<test>i have content</test>'),
  159.                        
  160.                         new StringyThing(true),
  161.                         new StringyThing('true'),
  162.                         new StringyThing('a string'),
  163.                         new CountableThing(array(1, 2, 3)),
  164.                         new CountableThing('count() returns 1 for this'),
  165.                         new StringyAndCountableThing(true, array(true)),
  166.                 ),
  167.                
  168.                 'ought to be false' => array(
  169.                         false,
  170.                         0,
  171.                         0.0,
  172.                         (float) '-0',
  173.                         '0',
  174.                         '',
  175.                         'no',
  176.                         'off',
  177.                         'OFF',
  178.                         'false',
  179.                        
  180.                         array(),
  181.                        
  182.                         // this is explicitly mentioned to be false in the manual:
  183.                         // http://www.php.net/manual/en/language.types.boolean.php#language.types.boolean.casting
  184.                         simplexml_load_string('<test></test>'),
  185.                        
  186.                         new StringyThing(false),
  187.                         new StringyThing('no'),
  188.                         new StringyThing(''),
  189.                         new CountableThing(array()),
  190.                         new StringyAndCountableThing(false, array()),
  191.                 ),
  192.                
  193.                 'iffy' => array(
  194.                         null,
  195.                         NAN,
  196.                        
  197.                         // the list of things like this could go on forever (not even taking translations into account)
  198.                         'null',
  199.                         'n',
  200.                         'unset',
  201.                         'nothing',
  202.                         'nil',
  203.                         'nope',
  204.                        
  205.                         // equivalent to an empty string in ini directives
  206.                         'none',
  207.                         'NONE',
  208.                        
  209.                         // this is not falsy in PHP (even though '0' is)
  210.                         '0.0',
  211.                        
  212.                         '0x0',
  213.                        
  214.                         ' ',
  215.                         'PHP_EOL' => PHP_EOL,
  216.                         '"\t"' => "\t",
  217.                        
  218.                         // mixed signals, should countability or string value take precedence (or should these be null)?
  219.                         new StringyAndCountableThing(false, array(true)),
  220.                         new StringyAndCountableThing('yes', array()),
  221.                        
  222.                         // in PHP4 this would have been consider falsy
  223.                         new stdClass(),
  224.                        
  225.                         // could check for a ->scalar property to handle this case
  226.                         (object) false,
  227.                        
  228.                         array(false),
  229.                         array(null),
  230.                         array('a key' => false),
  231.                         array(null => false),
  232.                        
  233.                         // give these readable keys since var_export is not helpful for anonymous functions
  234.                         'function() {}' => function() {},
  235.                         'function() { return false; }' => function() { return false; },
  236.                         'function() { return true; }' => function() { return true; },
  237.                         "function() { return 'no'; }" => function() { return 'no'; },
  238.                         "function() { return 'on'; }" => function() { return 'on'; },
  239.                         "function() { return 'something completely different'; }" => function() { return 'something completely different'; },
  240.                        
  241.                         // resources
  242.                         xml_parser_create(),
  243.                         fopen(__FILE__, 'r'),
  244.                 ),
  245.         );
  246.        
  247.        
  248.         /**
  249.          * functions to run tests with
  250.          */
  251.         // PHP's built in behavior for things like if($value)
  252.         function typecast($value) {
  253.                 return (boolean) $value;
  254.         }
  255.         function filter_var_bool($value) {
  256.                 return filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
  257.         }
  258.         // see http://us2.php.net/manual/en/filter.filters.validate.php#108218
  259.         // and https://bugs.php.net/bug.php?id=49510
  260.         function filter_var_bool_with_null_fallback($value) {
  261.                 $filtered = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
  262.                 if(is_null($filtered)) return (boolean) $value;
  263.                 else return $filtered;
  264.         }
  265.         // from http://www.php.net/manual/en/function.is-bool.php#93165
  266.         function kim_s_solution($var){
  267.                 if(is_bool($var)){
  268.                         return $var;
  269.                 } else if($var === NULL || $var === 'NULL' || $var === 'null'){
  270.                         return false;
  271.                 } else if(is_string($var)){
  272.                         $var = trim($var);
  273.                         if($var=='false'){ return false;
  274.                         } else if($var=='true'){ return true;
  275.                         } else if($var=='no'){ return false;
  276.                         } else if($var=='yes'){ return true;
  277.                         } else if($var=='off'){ return false;
  278.                         } else if($var=='on'){ return true;
  279.                         } else if($var==''){ return false;
  280.                         } else if(ctype_digit($var)){
  281.                                 if((int) $var)
  282.                                         return true;
  283.                                         else
  284.                                         return false;
  285.                         } else { return true; }
  286.                 /* NOTE: i changed these lines from the original code.  string casting results in an error for some objects, and handling floats correctly is a good idea anyway.
  287.                 } else if(ctype_digit((string) $var)){
  288.                                 if((int) $var)
  289.                 */
  290.                 } else if(is_numeric($var)){
  291.                                 if((float) $var)
  292.                 /* end of changed lines */
  293.                                         return true;
  294.                                         else
  295.                                         return false;
  296.                 } else if(is_array($var)){
  297.                         if(count($var))
  298.                                 return true;
  299.                                 else
  300.                                 return false;
  301.                 } else if(is_object($var)){
  302.                         return true;// No reason to (bool) an object, we assume OK for crazy logic
  303.                 } else {
  304.                         return true;// Whatever came though must be something,  OK for crazy logic
  305.                 }
  306.         }
  307.         function custom_solution($value) {
  308.                 // FIXME? if an object is both countable and string-castable, this will favor the count over the string value.
  309.                 //      which should take precedence (if any)?  maybe it should return null if there are mixed signals?  or true?
  310.                 if(is_array($value) || $value instanceof Countable) {
  311.                         return (boolean) count($value);
  312.                 } else if(is_string($value) || is_object($value) && method_exists($value, '__toString')) {
  313.                         $value = (string) $value;
  314.                         // see http://www.php.net/manual/en/filter.filters.validate.php#108218
  315.                         // see https://bugs.php.net/bug.php?id=49510
  316.                         $filtered = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
  317.                         if(!is_null($filtered)) {
  318.                                 return $filtered;
  319.                         } else {
  320.                                 // "none" gets special treatment to be consistent with ini file behavior.
  321.                                 // see documentation in php.ini for more information, in part it says:
  322.                                 // "An empty string can be denoted by simply not writing anything after
  323.                                 // the equal sign, or by using the None keyword".
  324.                                 if(strtolower($value) === 'none') {
  325.                                         $value = '';
  326.                                 }
  327.                                 return (boolean) $value;
  328.                         }
  329.                 } else {
  330.                         return (boolean) $value;
  331.                 }
  332.         }
  333.        
  334.        
  335.         /**
  336.          * test the various solutions
  337.          */
  338.         run_test('typecast');
  339.         run_test('filter_var_bool');
  340.         run_test('filter_var_bool_with_null_fallback');
  341.         run_test('kim_s_solution');
  342.         run_test('custom_solution');
  343. ?>
  344. </body>
  345. </html>