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
|