logo       
Google Custom Search
    AddThis Social Bookmark Button
-->

Mock :: generate() throws fatal error with PHP5: msg#00083

Subject: Mock :: generate() throws fatal error with PHP5
Hello,

I  checked  out  the fresh version of SimpleTest from CVS and my tests
throw PHP fatal error because of the new Mock :: generate() implementation.

Here's the code which reproduces this bug(PHP 5.0.4/5.1RC1, windows):

<?php
require_once('simpletest/mock_objects.php');

class IteratorBase implements Iterator {
  function valid(){}
  function key() {}
  function current() {}
  function next() {}
  function rewind() {}
}

class Foo extends IteratorBase{}

Mock :: generate('IteratorBase'); //this one is ok
Mock :: generate('Foo');          //this one fails! Fatal error: Class MockFoo 
must implement interface Traversable as part of either Iterator or 
IteratorAggregate in Unknown on line 0

?>

I  debugged Mock :: generate() and found why it happens, the reason is
really  weird  and  it  seems  that it's PHP5 fault... I'm pretty much
confused but i'll try to explain.

$reflection->getInterfaces() at 95 line of reflection_php5.php returns
*all* interfaces which class implements even those which are inherited
with  top-most  interfaces,  e.g. it returns array(Traversable,
Iterator) for class which simply implements Iterator!

When mock is generated it implements all interfaces and fatal error is
raised,  because...er...some  non-terminal "lower-level" interfaces(in
my  case  Traversable)  should  never  be  implemented at all(are they
abstract?).  This  happens  only  for classes which are inherited from
parent classes which implement inherited interfaces(e.g. Iterator).

Here's  the  quick'n'dirty  patch which fixes this bug(sorry SF CVS is
down    and   i   can't   make   a   unified   patch).   Please   find
SimpleReflection::getInterfaces()  method  in  reflection_php5.php and
change its contents for:

        function getInterfaces() {
            $reflection = new ReflectionClass($this->_interface);
            if ($reflection->isInterface()) {
              return array($this->_interface);
            }
            $interfaces = array();
            $prev_interface = null;
            foreach ($reflection->getInterfaces() as $interface) {
              if($prev_interface && $interface->isSubClassOf($prev_interface)) {
                array_pop($interfaces);
              }
              $interfaces[] = $interface->getName();
              $prev_interface = $interface;
            }
            return $interfaces;
        }

This  patch  assumes  that  ReflectionClass :: getInterfaces() returns
*all*  interfaces  in  the order of their inheritance(e.g Traversable,
Iterator) and it removes unneccessary non-terminal interfaces.

It worked for me, maybe you can find some better solution but at least
you get the idea :)

P.S. maybe we should let know PHP cowboys?

Best regards, Pavel
--
Pavel Chtchevaev, pacha_shevaev-JGs/UdohzUI@xxxxxxxxxxxxxxxx
LIMB - http://limb-project.com
Bureau of Information Technologies - http://www.bit-creative.com



-------------------------------------------------------
SF.Net email is Sponsored by the Better Software Conference & EXPO
September 19-22, 2005 * San Francisco, CA * Development Lifecycle Practices
Agile & Plan-Driven Development * Managing Projects & Teams * Testing & QA
Security * Process Improvement & Measurement * http://www.sqe.com/bsce5sf


<Prev in Thread] Current Thread [Next in Thread>