]> granicus.if.org Git - php/commitdiff
fix bug #55475 - implement is_a BC solution
authorStanislav Malyshev <stas@php.net>
Wed, 9 Nov 2011 05:27:45 +0000 (05:27 +0000)
committerStanislav Malyshev <stas@php.net>
Wed, 9 Nov 2011 05:27:45 +0000 (05:27 +0000)
Zend/zend_builtin_functions.c
ext/standard/tests/class_object/is_a.phpt [new file with mode: 0644]
ext/standard/tests/class_object/is_a_error_001.phpt
ext/standard/tests/class_object/is_subclass_of_error_001.phpt

index 28001070ebeabec3360ab8390998f9c2660421cc..aeacda54e208029eba7fb5353a0ee4b1ef06cc46 100644 (file)
@@ -839,13 +839,20 @@ static void is_a_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool only_subclass)
        int class_name_len;
        zend_class_entry *instance_ce;
        zend_class_entry **ce;
+       zend_bool allow_string = only_subclass;
        zend_bool retval;
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zs", &obj, &class_name, &class_name_len) == FAILURE) {
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zs|b", &obj, &class_name, &class_name_len, &allow_string) == FAILURE) {
                return;
        }
-       
-       if (Z_TYPE_P(obj) == IS_STRING) {
+       /*
+        * allow_string - is_a default is no, is_subclass_of is yes. 
+        *   if it's allowed, then the autoloader will be called if the class does not exist.
+        *   default behaviour is different, as 'is_a' used to be used to test mixed return values
+        *   and there is no easy way to deprecate this.
+        */
+
+       if (allow_string && Z_TYPE_P(obj) == IS_STRING) {
                zend_class_entry **the_ce;
                if (zend_lookup_class(Z_STRVAL_P(obj), Z_STRLEN_P(obj), &the_ce TSRMLS_CC) == FAILURE) {
                        RETURN_FALSE;
@@ -871,7 +878,7 @@ static void is_a_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool only_subclass)
 }
 
 
-/* {{{ proto bool is_subclass_of(mixed object, string class_name)
+/* {{{ proto bool is_subclass_of(mixed object_or_string, string class_name [, bool allow_string=true])
    Returns true if the object has this class as one of its parents */
 ZEND_FUNCTION(is_subclass_of)
 {
@@ -880,8 +887,8 @@ ZEND_FUNCTION(is_subclass_of)
 /* }}} */
 
 
-/* {{{ proto bool is_a(mixed object, string class_name)
-   Returns true if the object is of this class or has this class as one of its parents */
+/* {{{ proto bool is_a(mixed object_or_string, string class_name [, bool allow_string=false])
+   Returns true if the first argument is an object and is this class or has this class as one of its parents, */
 ZEND_FUNCTION(is_a)
 {
        is_a_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
diff --git a/ext/standard/tests/class_object/is_a.phpt b/ext/standard/tests/class_object/is_a.phpt
new file mode 100644 (file)
index 0000000..832d555
--- /dev/null
@@ -0,0 +1,378 @@
+--TEST--
+is_a and is_subclass_of behaviour (with and without autoload)
+--SKIPIF--
+<?php if (version_compare(zend_version(), '2.0.0-dev', '<')) die('skip ZendEngine 2 needed'); ?>
+--FILE--
+<?php
+
+interface if_a {
+       function f_a();
+}
+       
+interface if_b extends if_a {
+       function f_b();
+}
+
+class base {
+       function _is_a($sub) {
+               
+               echo "\n>>> With Defined class\n";
+               echo str_pad('is_a( OBJECT:'.get_class($this).', '.$sub.') = ', 60) . (is_a($this, $sub) ? 'yes' : 'no')."\n";
+               echo str_pad('is_a( STRING:'.get_class($this).', '.$sub.') = ', 60). (is_a(get_class($this), $sub) ? 'yes' : 'no')."\n";
+               echo str_pad('is_a( STRING:'.get_class($this).', '.$sub.', true) = ', 60). (is_a(get_class($this), $sub, true) ? 'yes' : 'no')."\n";            
+               echo str_pad('is_subclass_of( OBJECT:'.get_class($this).', '.$sub.') = ', 60).  (is_subclass_of($this, $sub) ? 'yes' : 'no')."\n";
+               echo str_pad('is_subclass_of( STRING:'.get_class($this).', '.$sub.') = ', 60). (is_subclass_of(get_class($this), $sub) ? 'yes' : 'no')."\n";
+               echo str_pad('is_subclass_of( STRING:'.get_class($this).', '.$sub.',false) = ', 60). (is_subclass_of(get_class($this), $sub , false) ? 'yes' : 'no')."\n";
+                
+               // with autoload options..
+               echo ">>> With Undefined\n";
+               echo  str_pad('is_a( STRING:undefB, '.$sub.',true) = ', 60). (is_a('undefB', $sub, true) ? 'yes' : 'no')."\n";
+               echo  str_pad('is_a( STRING:undefB, '.$sub.') = ', 60). (is_a('undefB', $sub) ? 'yes' : 'no')."\n";
+               echo  str_pad('is_subclass_of( STRING:undefB, '.$sub.',false) = ', 60). (is_subclass_of('undefB', $sub, false) ? 'yes' : 'no')."\n";
+               echo  str_pad('is_subclass_of( STRING:undefB, '.$sub.') = ', 60). (is_subclass_of('undefB', $sub) ? 'yes' : 'no')."\n";
+       }
+       function test() {
+               echo $this->_is_a('base');
+               echo $this->_is_a('derived_a');  
+               echo $this->_is_a('if_a'); 
+               echo $this->_is_a('undefA');
+               echo "\n";
+       }
+}
+
+class derived_a extends base implements if_a {
+       function f_a() {}
+}
+
+class derived_b extends base implements if_a, if_b {
+       function f_a() {}
+       function f_b() {}
+}
+
+class derived_c extends derived_a implements if_b {
+       function f_b() {}
+}
+
+class derived_d extends derived_c {
+}
+
+$t = new base();
+$t->test();
+
+$t = new derived_a();
+$t->test();
+
+eval('
+  function __autoload($name)
+  {
+      echo ">>>> In __autoload: ";
+      var_dump($name);
+  }
+');
+
+echo "NOW WITH AUTOLOAD\n\n";
+
+$t = new base();
+$t->test();
+
+$t = new derived_a();
+$t->test();
+
+$t = new derived_b();
+$t->test();
+
+
+
+
+?>
+--EXPECTF--
+>>> With Defined class
+is_a( OBJECT:base, base) =                                  yes
+is_a( STRING:base, base) =                                  no
+is_a( STRING:base, base, true) =                            yes
+is_subclass_of( OBJECT:base, base) =                        no
+is_subclass_of( STRING:base, base) =                        no
+is_subclass_of( STRING:base, base,false) =                  no
+>>> With Undefined
+is_a( STRING:undefB, base,true) =                           no
+is_a( STRING:undefB, base) =                                no
+is_subclass_of( STRING:undefB, base,false) =                no
+is_subclass_of( STRING:undefB, base) =                      no
+
+>>> With Defined class
+is_a( OBJECT:base, derived_a) =                             no
+is_a( STRING:base, derived_a) =                             no
+is_a( STRING:base, derived_a, true) =                       no
+is_subclass_of( OBJECT:base, derived_a) =                   no
+is_subclass_of( STRING:base, derived_a) =                   no
+is_subclass_of( STRING:base, derived_a,false) =             no
+>>> With Undefined
+is_a( STRING:undefB, derived_a,true) =                      no
+is_a( STRING:undefB, derived_a) =                           no
+is_subclass_of( STRING:undefB, derived_a,false) =           no
+is_subclass_of( STRING:undefB, derived_a) =                 no
+
+>>> With Defined class
+is_a( OBJECT:base, if_a) =                                  no
+is_a( STRING:base, if_a) =                                  no
+is_a( STRING:base, if_a, true) =                            no
+is_subclass_of( OBJECT:base, if_a) =                        no
+is_subclass_of( STRING:base, if_a) =                        no
+is_subclass_of( STRING:base, if_a,false) =                  no
+>>> With Undefined
+is_a( STRING:undefB, if_a,true) =                           no
+is_a( STRING:undefB, if_a) =                                no
+is_subclass_of( STRING:undefB, if_a,false) =                no
+is_subclass_of( STRING:undefB, if_a) =                      no
+
+>>> With Defined class
+is_a( OBJECT:base, undefA) =                                no
+is_a( STRING:base, undefA) =                                no
+is_a( STRING:base, undefA, true) =                          no
+is_subclass_of( OBJECT:base, undefA) =                      no
+is_subclass_of( STRING:base, undefA) =                      no
+is_subclass_of( STRING:base, undefA,false) =                no
+>>> With Undefined
+is_a( STRING:undefB, undefA,true) =                         no
+is_a( STRING:undefB, undefA) =                              no
+is_subclass_of( STRING:undefB, undefA,false) =              no
+is_subclass_of( STRING:undefB, undefA) =                    no
+
+
+>>> With Defined class
+is_a( OBJECT:derived_a, base) =                             yes
+is_a( STRING:derived_a, base) =                             no
+is_a( STRING:derived_a, base, true) =                       yes
+is_subclass_of( OBJECT:derived_a, base) =                   yes
+is_subclass_of( STRING:derived_a, base) =                   yes
+is_subclass_of( STRING:derived_a, base,false) =             no
+>>> With Undefined
+is_a( STRING:undefB, base,true) =                           no
+is_a( STRING:undefB, base) =                                no
+is_subclass_of( STRING:undefB, base,false) =                no
+is_subclass_of( STRING:undefB, base) =                      no
+
+>>> With Defined class
+is_a( OBJECT:derived_a, derived_a) =                        yes
+is_a( STRING:derived_a, derived_a) =                        no
+is_a( STRING:derived_a, derived_a, true) =                  yes
+is_subclass_of( OBJECT:derived_a, derived_a) =              no
+is_subclass_of( STRING:derived_a, derived_a) =              no
+is_subclass_of( STRING:derived_a, derived_a,false) =        no
+>>> With Undefined
+is_a( STRING:undefB, derived_a,true) =                      no
+is_a( STRING:undefB, derived_a) =                           no
+is_subclass_of( STRING:undefB, derived_a,false) =           no
+is_subclass_of( STRING:undefB, derived_a) =                 no
+
+>>> With Defined class
+is_a( OBJECT:derived_a, if_a) =                             yes
+is_a( STRING:derived_a, if_a) =                             no
+is_a( STRING:derived_a, if_a, true) =                       yes
+is_subclass_of( OBJECT:derived_a, if_a) =                   yes
+is_subclass_of( STRING:derived_a, if_a) =                   yes
+is_subclass_of( STRING:derived_a, if_a,false) =             no
+>>> With Undefined
+is_a( STRING:undefB, if_a,true) =                           no
+is_a( STRING:undefB, if_a) =                                no
+is_subclass_of( STRING:undefB, if_a,false) =                no
+is_subclass_of( STRING:undefB, if_a) =                      no
+
+>>> With Defined class
+is_a( OBJECT:derived_a, undefA) =                           no
+is_a( STRING:derived_a, undefA) =                           no
+is_a( STRING:derived_a, undefA, true) =                     no
+is_subclass_of( OBJECT:derived_a, undefA) =                 no
+is_subclass_of( STRING:derived_a, undefA) =                 no
+is_subclass_of( STRING:derived_a, undefA,false) =           no
+>>> With Undefined
+is_a( STRING:undefB, undefA,true) =                         no
+is_a( STRING:undefB, undefA) =                              no
+is_subclass_of( STRING:undefB, undefA,false) =              no
+is_subclass_of( STRING:undefB, undefA) =                    no
+
+NOW WITH AUTOLOAD
+
+
+>>> With Defined class
+is_a( OBJECT:base, base) =                                  yes
+is_a( STRING:base, base) =                                  no
+is_a( STRING:base, base, true) =                            yes
+is_subclass_of( OBJECT:base, base) =                        no
+is_subclass_of( STRING:base, base) =                        no
+is_subclass_of( STRING:base, base,false) =                  no
+>>> With Undefined
+>>>> In __autoload: string(6) "undefB"
+is_a( STRING:undefB, base,true) =                           no
+is_a( STRING:undefB, base) =                                no
+is_subclass_of( STRING:undefB, base,false) =                no
+>>>> In __autoload: string(6) "undefB"
+is_subclass_of( STRING:undefB, base) =                      no
+
+>>> With Defined class
+is_a( OBJECT:base, derived_a) =                             no
+is_a( STRING:base, derived_a) =                             no
+is_a( STRING:base, derived_a, true) =                       no
+is_subclass_of( OBJECT:base, derived_a) =                   no
+is_subclass_of( STRING:base, derived_a) =                   no
+is_subclass_of( STRING:base, derived_a,false) =             no
+>>> With Undefined
+>>>> In __autoload: string(6) "undefB"
+is_a( STRING:undefB, derived_a,true) =                      no
+is_a( STRING:undefB, derived_a) =                           no
+is_subclass_of( STRING:undefB, derived_a,false) =           no
+>>>> In __autoload: string(6) "undefB"
+is_subclass_of( STRING:undefB, derived_a) =                 no
+
+>>> With Defined class
+is_a( OBJECT:base, if_a) =                                  no
+is_a( STRING:base, if_a) =                                  no
+is_a( STRING:base, if_a, true) =                            no
+is_subclass_of( OBJECT:base, if_a) =                        no
+is_subclass_of( STRING:base, if_a) =                        no
+is_subclass_of( STRING:base, if_a,false) =                  no
+>>> With Undefined
+>>>> In __autoload: string(6) "undefB"
+is_a( STRING:undefB, if_a,true) =                           no
+is_a( STRING:undefB, if_a) =                                no
+is_subclass_of( STRING:undefB, if_a,false) =                no
+>>>> In __autoload: string(6) "undefB"
+is_subclass_of( STRING:undefB, if_a) =                      no
+
+>>> With Defined class
+is_a( OBJECT:base, undefA) =                                no
+is_a( STRING:base, undefA) =                                no
+is_a( STRING:base, undefA, true) =                          no
+is_subclass_of( OBJECT:base, undefA) =                      no
+is_subclass_of( STRING:base, undefA) =                      no
+is_subclass_of( STRING:base, undefA,false) =                no
+>>> With Undefined
+>>>> In __autoload: string(6) "undefB"
+is_a( STRING:undefB, undefA,true) =                         no
+is_a( STRING:undefB, undefA) =                              no
+is_subclass_of( STRING:undefB, undefA,false) =              no
+>>>> In __autoload: string(6) "undefB"
+is_subclass_of( STRING:undefB, undefA) =                    no
+
+
+>>> With Defined class
+is_a( OBJECT:derived_a, base) =                             yes
+is_a( STRING:derived_a, base) =                             no
+is_a( STRING:derived_a, base, true) =                       yes
+is_subclass_of( OBJECT:derived_a, base) =                   yes
+is_subclass_of( STRING:derived_a, base) =                   yes
+is_subclass_of( STRING:derived_a, base,false) =             no
+>>> With Undefined
+>>>> In __autoload: string(6) "undefB"
+is_a( STRING:undefB, base,true) =                           no
+is_a( STRING:undefB, base) =                                no
+is_subclass_of( STRING:undefB, base,false) =                no
+>>>> In __autoload: string(6) "undefB"
+is_subclass_of( STRING:undefB, base) =                      no
+
+>>> With Defined class
+is_a( OBJECT:derived_a, derived_a) =                        yes
+is_a( STRING:derived_a, derived_a) =                        no
+is_a( STRING:derived_a, derived_a, true) =                  yes
+is_subclass_of( OBJECT:derived_a, derived_a) =              no
+is_subclass_of( STRING:derived_a, derived_a) =              no
+is_subclass_of( STRING:derived_a, derived_a,false) =        no
+>>> With Undefined
+>>>> In __autoload: string(6) "undefB"
+is_a( STRING:undefB, derived_a,true) =                      no
+is_a( STRING:undefB, derived_a) =                           no
+is_subclass_of( STRING:undefB, derived_a,false) =           no
+>>>> In __autoload: string(6) "undefB"
+is_subclass_of( STRING:undefB, derived_a) =                 no
+
+>>> With Defined class
+is_a( OBJECT:derived_a, if_a) =                             yes
+is_a( STRING:derived_a, if_a) =                             no
+is_a( STRING:derived_a, if_a, true) =                       yes
+is_subclass_of( OBJECT:derived_a, if_a) =                   yes
+is_subclass_of( STRING:derived_a, if_a) =                   yes
+is_subclass_of( STRING:derived_a, if_a,false) =             no
+>>> With Undefined
+>>>> In __autoload: string(6) "undefB"
+is_a( STRING:undefB, if_a,true) =                           no
+is_a( STRING:undefB, if_a) =                                no
+is_subclass_of( STRING:undefB, if_a,false) =                no
+>>>> In __autoload: string(6) "undefB"
+is_subclass_of( STRING:undefB, if_a) =                      no
+
+>>> With Defined class
+is_a( OBJECT:derived_a, undefA) =                           no
+is_a( STRING:derived_a, undefA) =                           no
+is_a( STRING:derived_a, undefA, true) =                     no
+is_subclass_of( OBJECT:derived_a, undefA) =                 no
+is_subclass_of( STRING:derived_a, undefA) =                 no
+is_subclass_of( STRING:derived_a, undefA,false) =           no
+>>> With Undefined
+>>>> In __autoload: string(6) "undefB"
+is_a( STRING:undefB, undefA,true) =                         no
+is_a( STRING:undefB, undefA) =                              no
+is_subclass_of( STRING:undefB, undefA,false) =              no
+>>>> In __autoload: string(6) "undefB"
+is_subclass_of( STRING:undefB, undefA) =                    no
+
+
+>>> With Defined class
+is_a( OBJECT:derived_b, base) =                             yes
+is_a( STRING:derived_b, base) =                             no
+is_a( STRING:derived_b, base, true) =                       yes
+is_subclass_of( OBJECT:derived_b, base) =                   yes
+is_subclass_of( STRING:derived_b, base) =                   yes
+is_subclass_of( STRING:derived_b, base,false) =             no
+>>> With Undefined
+>>>> In __autoload: string(6) "undefB"
+is_a( STRING:undefB, base,true) =                           no
+is_a( STRING:undefB, base) =                                no
+is_subclass_of( STRING:undefB, base,false) =                no
+>>>> In __autoload: string(6) "undefB"
+is_subclass_of( STRING:undefB, base) =                      no
+
+>>> With Defined class
+is_a( OBJECT:derived_b, derived_a) =                        no
+is_a( STRING:derived_b, derived_a) =                        no
+is_a( STRING:derived_b, derived_a, true) =                  no
+is_subclass_of( OBJECT:derived_b, derived_a) =              no
+is_subclass_of( STRING:derived_b, derived_a) =              no
+is_subclass_of( STRING:derived_b, derived_a,false) =        no
+>>> With Undefined
+>>>> In __autoload: string(6) "undefB"
+is_a( STRING:undefB, derived_a,true) =                      no
+is_a( STRING:undefB, derived_a) =                           no
+is_subclass_of( STRING:undefB, derived_a,false) =           no
+>>>> In __autoload: string(6) "undefB"
+is_subclass_of( STRING:undefB, derived_a) =                 no
+
+>>> With Defined class
+is_a( OBJECT:derived_b, if_a) =                             yes
+is_a( STRING:derived_b, if_a) =                             no
+is_a( STRING:derived_b, if_a, true) =                       yes
+is_subclass_of( OBJECT:derived_b, if_a) =                   yes
+is_subclass_of( STRING:derived_b, if_a) =                   yes
+is_subclass_of( STRING:derived_b, if_a,false) =             no
+>>> With Undefined
+>>>> In __autoload: string(6) "undefB"
+is_a( STRING:undefB, if_a,true) =                           no
+is_a( STRING:undefB, if_a) =                                no
+is_subclass_of( STRING:undefB, if_a,false) =                no
+>>>> In __autoload: string(6) "undefB"
+is_subclass_of( STRING:undefB, if_a) =                      no
+
+>>> With Defined class
+is_a( OBJECT:derived_b, undefA) =                           no
+is_a( STRING:derived_b, undefA) =                           no
+is_a( STRING:derived_b, undefA, true) =                     no
+is_subclass_of( OBJECT:derived_b, undefA) =                 no
+is_subclass_of( STRING:derived_b, undefA) =                 no
+is_subclass_of( STRING:derived_b, undefA,false) =           no
+>>> With Undefined
+>>>> In __autoload: string(6) "undefB"
+is_a( STRING:undefB, undefA,true) =                         no
+is_a( STRING:undefB, undefA) =                              no
+is_subclass_of( STRING:undefB, undefA,false) =              no
+>>>> In __autoload: string(6) "undefB"
+is_subclass_of( STRING:undefB, undefA) =                    no
index 921e3a26064a67f2daef4f7a4ccff83aa13707de..6518a03c0f909bce09a80dd974ebb840cd521c06 100644 (file)
@@ -4,7 +4,7 @@ Test is_a() function : error conditions - wrong number of args
 error_reporting=E_ALL | E_STRICT | E_DEPRECATED
 --FILE--
 <?php
-/* Prototype  : proto bool is_a(object object, string class_name)
+/* Prototype  : proto bool is_a(object object, string class_name, bool allow_string)
  * Description: Returns true if the object is of this class or has this class as one of its parents 
  * Source code: Zend/zend_builtin_functions.c
  * Alias to functions: 
@@ -12,13 +12,19 @@ error_reporting=E_ALL | E_STRICT | E_DEPRECATED
 
 echo "*** Testing is_a() : error conditions ***\n";
 
-
 //Test is_a with one more than the expected number of arguments
 echo "\n-- Testing is_a() function with more than expected no. of arguments --\n";
 $object = new stdclass();
 $class_name = 'string_val';
+$allow_string = false;
 $extra_arg = 10;
-var_dump( is_a($object, $class_name, $extra_arg) );
+
+var_dump( is_a($object, $class_name, $allow_string, $object) );
+
+//Test is_a with one more than the expected number of arguments
+echo "\n-- Testing is_a() function with non-boolean in last position --\n";
+var_dump( is_a($object, $class_name, $object) );
+
 
 // Testing is_a with one less than the expected number of arguments
 echo "\n-- Testing is_a() function with less than expected no. of arguments --\n";
@@ -28,15 +34,21 @@ var_dump( is_a($object) );
 echo "Done";
 ?>
 --EXPECTF--
+
 *** Testing is_a() : error conditions ***
 
 -- Testing is_a() function with more than expected no. of arguments --
 
-Warning: is_a() expects exactly 2 parameters, 3 given in %s on line 16
+Warning: is_a() expects at most 3 parameters, 4 given in %s on line 17
+NULL
+
+-- Testing is_a() function with non-boolean in last position --
+
+Warning: is_a() expects parameter 3 to be boolean, object given in %s on line 21
 NULL
 
 -- Testing is_a() function with less than expected no. of arguments --
 
-Warning: is_a() expects exactly 2 parameters, 1 given in %s on line 21
+Warning: is_a() expects at least 2 parameters, 1 given in %s on line 27
 NULL
-Done
+Done
\ No newline at end of file
index bc657866d0f27137ba00b69e24cab642ad3139d4..987dcd47be503841273da4c5b68eff98a27cce61 100644 (file)
@@ -15,8 +15,18 @@ echo "*** Testing is_subclass_of() : error conditions ***\n";
 echo "\n-- Testing is_subclass_of() function with more than expected no. of arguments --\n";
 $object = new stdclass();
 $class_name = 'string_val';
+$allow_string = false;
 $extra_arg = 10;
-var_dump( is_subclass_of($object, $class_name, $extra_arg) );
+var_dump( is_subclass_of($object, $class_name, $allow_string, $extra_arg) );
+
+//Test is_subclass_of with invalid last argument
+echo "\n-- Testing is_subclass_of() function with more than typo style invalid 3rd argument --\n";
+var_dump( is_subclass_of($object, $class_name, $class_name) );
+
+
+//Test is_subclass_of with invalid last argument
+echo "\n-- Testing is_subclass_of() function with more than invalid 3rd argument --\n";
+var_dump( is_subclass_of($object, $class_name, $object) );
 
 // Testing is_subclass_of with one less than the expected number of arguments
 echo "\n-- Testing is_subclass_of() function with less than expected no. of arguments --\n";
@@ -30,11 +40,19 @@ echo "Done";
 
 -- Testing is_subclass_of() function with more than expected no. of arguments --
 
-Warning: is_subclass_of() expects exactly 2 parameters, 3 given in %s on line 16
+Warning: is_subclass_of() expects at most 3 parameters, 4 given in %s on line 17
+NULL
+
+-- Testing is_subclass_of() function with more than typo style invalid 3rd argument --
+bool(false)
+
+-- Testing is_subclass_of() function with more than invalid 3rd argument --
+
+Warning: is_subclass_of() expects parameter 3 to be boolean, object given in %s on line 26
 NULL
 
 -- Testing is_subclass_of() function with less than expected no. of arguments --
 
-Warning: is_subclass_of() expects exactly 2 parameters, 1 given in %s on line 21
+Warning: is_subclass_of() expects at least 2 parameters, 1 given in %s on line 31
 NULL
 Done