fork download
  1. <?php
  2. /**
  3.  * Whenever you create a function that has an array as a parameter you use a
  4.  * type-hint to make sure your parameter is of the right type.
  5.  *
  6.  * But is this a good idea?
  7.  *
  8.  * In the same way as using is_string() excludes any objects implementing a
  9.  * '__toString' method, using 'Array' as type-hint excludes objects that
  10.  * implement the Traversable interface.
  11.  *
  12.  * My suggestion would be to avoid type-hinting and check for array-ishness yourself
  13.  *
  14.  * See the code example below for an explanation.
  15.  *
  16.  * Note: The variable naming scheme used in this code is an adaption of
  17.  * Systems Hungarian which is explained at http://p...content-available-to-author-only...r.ca/VariableNamingConvention/
  18.  */
  19.  
  20. /**
  21.  * Check if a given variable can be treated as an Array
  22.  */
  23. function is_arrayish ($p_aSubject) {
  24. $bIsArray = false;
  25.  
  26. if (is_array($p_aSubject) || $p_aSubject instanceof Traversable) {
  27. $bIsArray = true;
  28. }
  29.  
  30. return $bIsArray;
  31. }
  32.  
  33.  
  34. /**
  35.  * Create an Array-ish object
  36.  */
  37. $aNumbers = ['one','two','three'];
  38. $oNumbers = new ArrayObject($aNumbers);// To save us from implementing all those ArrayAccess methods
  39.  
  40.  
  41. /**
  42.  * A function that only accepts Arrays
  43.  */
  44. function onlyAcceptArrays(array $p_aSubject) {
  45. foreach($p_aSubject as $t_sItem){
  46. echo $t_sItem . PHP_EOL;
  47. }
  48. }
  49.  
  50.  
  51. /**
  52.  * A function that does accept other Arrayish types
  53.  */
  54. function acceptAllIteratorables($p_aSubject) {
  55. if (is_arrayish($p_aSubject) === false) {
  56. throw new \InvalidArgumentException(
  57. 'Argument 1 passed to ' . __METHOD__ . ' must be of the type array or implementation of Traversable, '.
  58. (gettype($p_aSubject) === 'object'?'object of type '.get_class($p_aSubject):gettype($p_aSubject)) .
  59. ' given'
  60. );
  61. } else {
  62. foreach($p_aSubject as $t_sItem){
  63. echo $t_sItem . PHP_EOL;
  64. }
  65. }
  66. }
  67.  
  68. /**
  69.  * And now... the proof!
  70.  */
  71.  
  72. // Works
  73. acceptAllIteratorables($oNumbers);
  74. echo '----------------------------------------' . PHP_EOL;
  75.  
  76.  
  77. try {
  78. // Throws Exception
  79. acceptAllIteratorables(new stdClass());
  80. } catch(InvalidArgumentException $eInvalidArgument){
  81. echo $eInvalidArgument;
  82. }
  83. echo PHP_EOL . '----------------------------------------' . PHP_EOL;
  84.  
  85. // Triggers a fatal error
  86. onlyAcceptArrays($oNumbers);
  87.  
  88. /*EOF*/
Runtime error #stdin #stdout #stderr 0.01s 20568KB
stdin
Standard input is empty
stdout
one
two
three
----------------------------------------
exception 'InvalidArgumentException' with message 'Argument 1 passed to acceptAllIteratorables must be of the type array or implementation of Traversable, object of type stdClass given' in /home/XVcl5L/prog.php:56
Stack trace:
#0 /home/XVcl5L/prog.php(79): acceptAllIteratorables(Object(stdClass))
#1 {main}
----------------------------------------
stderr
PHP Catchable fatal error:  Argument 1 passed to onlyAcceptArrays() must be of the type array, object given, called in /home/XVcl5L/prog.php on line 86 and defined in /home/XVcl5L/prog.php on line 44