Advertisement
Guest User

Boolean Loose Casting Function Tests

a guest
Jul 15th, 2012
323
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 8.88 KB | None | 0 0
  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>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement