Skip to content

Commit 387c529

Browse files
committed
Remove Zend\Stdlib\SubClass
The main reason for this class was to work around changes in PHP between versions 5.3.3 and 5.3.7 regarding how is_subclass_of() works. In the earlier versions, it was buggy. In 5.3.7 and up, the bugs are fixed, and the solution is very fast. There are very few places in the framework where an is_subclass_of() test makes sense, and those are typically only with classes responsible for creating other classes -- factories, primarily. As such, the number of places where this will be of use is minimal, and can be maintained. The main goal is to have a consistent, performant way to do the check when required, and one which will work with case sensitive contexts. The solution by @prolic in zendframework#1807 is good; we just don't need to abstract this, particularly as we'll be able to remove this entirely in ZF3. Additionally, abstracting it gives additional dependencies for those components needing it, and in cases like autoloaders, DI, and the service manager, the extra dependency is undesirable as these should stand alone. The code has been duplicated into each class requiring the lookup (I put the check into AbstractPluginManager, as it's not unlikely other plugin managers may need this).
1 parent 8cb2703 commit 387c529

File tree

10 files changed

+178
-63
lines changed

10 files changed

+178
-63
lines changed

library/Zend/Di/Di.php

+27-4
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
namespace Zend\Di;
1212

1313
use Closure;
14-
use Zend\Stdlib\SubClass;
14+
use ReflectionClass;
1515

1616
class Di implements DependencyInjectionInterface
1717
{
@@ -310,7 +310,7 @@ protected function handleInjectDependencies($instance, $injectionMethods, $param
310310
if ($methodParams) {
311311
foreach ($methodParams as $methodParam) {
312312
$objectToInjectClass = $this->getClass($objectToInject);
313-
if ($objectToInjectClass == $methodParam[1] || SubClass::isSubclassOf($objectToInjectClass, $methodParam[1])) {
313+
if ($objectToInjectClass == $methodParam[1] || self::isSubclassOf($objectToInjectClass, $methodParam[1])) {
314314
if ($this->resolveAndCallInjectionMethodForInstance($instance, $typeInjectionMethod, array($methodParam[0] => $objectToInject), $instanceAlias, true, $type)) {
315315
$calledMethods[$typeInjectionMethod] = true;
316316
}
@@ -583,7 +583,7 @@ protected function resolveMethodParameters($class, $method, array $callTimeUserP
583583
}
584584
$pInstanceClass = ($this->instanceManager->hasAlias($pInstance)) ?
585585
$this->instanceManager->getClassFromAlias($pInstance) : $pInstance;
586-
if ($pInstanceClass === $type || SubClass::isSubclassOf($pInstanceClass, $type)) {
586+
if ($pInstanceClass === $type || self::isSubclassOf($pInstanceClass, $type)) {
587587
$computedParams['required'][$fqParamPos] = array($pInstance, $pInstanceClass);
588588
continue 2;
589589
}
@@ -600,7 +600,7 @@ protected function resolveMethodParameters($class, $method, array $callTimeUserP
600600
}
601601
$pInstanceClass = ($this->instanceManager->hasAlias($pInstance)) ?
602602
$this->instanceManager->getClassFromAlias($pInstance) : $pInstance;
603-
if ($pInstanceClass === $type || SubClass::isSubclassOf($pInstanceClass, $type)) {
603+
if ($pInstanceClass === $type || self::isSubclassOf($pInstanceClass, $type)) {
604604
$computedParams['required'][$fqParamPos] = array($pInstance, $pInstanceClass);
605605
continue 2;
606606
}
@@ -682,4 +682,27 @@ protected function getClass($instance)
682682
return get_class($instance);
683683
}
684684

685+
/**
686+
* Checks if the object has this class as one of its parents
687+
*
688+
* @see https://bugs.php.net/bug.php?id=53727
689+
* @see https://github.com/zendframework/zf2/pull/1807
690+
*
691+
* @param string $className
692+
* @param string $type
693+
*/
694+
protected static function isSubclassOf($className, $type)
695+
{
696+
if (version_compare(PHP_VERSION, '5.3.7', '>=')) {
697+
return is_subclass_of($className, $type);
698+
}
699+
if (is_subclass_of($className, $type)) {
700+
return true;
701+
}
702+
if (!interface_exists($type)) {
703+
return false;
704+
}
705+
$r = new ReflectionClass($className);
706+
return $r->implementsInterface($type);
707+
}
685708
}

library/Zend/Form/Annotation/AnnotationBuilder.php

+25-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
namespace Zend\Form\Annotation;
1212

1313
use ArrayObject;
14+
use ReflectionClass;
1415
use Zend\Code\Annotation\AnnotationCollection;
1516
use Zend\Code\Annotation\AnnotationManager;
1617
use Zend\Code\Annotation\Parser;
@@ -22,7 +23,6 @@
2223
use Zend\Form\Exception;
2324
use Zend\Form\Factory;
2425
use Zend\Stdlib\ArrayUtils;
25-
use Zend\Stdlib\SubClass;
2626

2727
/**
2828
* Parses a class' properties for annotations in order to create a form and
@@ -329,7 +329,7 @@ protected function configureElement($annotations, $reflection, $formSpec, $filte
329329
: 'Zend\Form\Element';
330330

331331
// Compose as a fieldset or an element, based on specification type
332-
if (SubClass::isSubclassOf($type, 'Zend\Form\FieldsetInterface')) {
332+
if (self::isSubclassOf($type, 'Zend\Form\FieldsetInterface')) {
333333
if (!isset($formSpec['fieldsets'])) {
334334
$formSpec['fieldsets'] = array();
335335
}
@@ -376,4 +376,27 @@ protected function checkForExclude($annotations)
376376
return (bool) $results->last();
377377
}
378378

379+
/**
380+
* Checks if the object has this class as one of its parents
381+
*
382+
* @see https://bugs.php.net/bug.php?id=53727
383+
* @see https://github.com/zendframework/zf2/pull/1807
384+
*
385+
* @param string $className
386+
* @param string $type
387+
*/
388+
protected static function isSubclassOf($className, $type)
389+
{
390+
if (version_compare(PHP_VERSION, '5.3.7', '>=')) {
391+
return is_subclass_of($className, $type);
392+
}
393+
if (is_subclass_of($className, $type)) {
394+
return true;
395+
}
396+
if (!interface_exists($type)) {
397+
return false;
398+
}
399+
$r = new ReflectionClass($className);
400+
return $r->implementsInterface($type);
401+
}
379402
}

library/Zend/Form/Factory.php

+27-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
use Zend\InputFilter\InputFilterInterface;
1818
use Zend\Stdlib\ArrayUtils;
1919
use Zend\Stdlib\Hydrator;
20-
use Zend\Stdlib\SubClass;
2120

2221
/**
2322
* @category Zend
@@ -73,15 +72,15 @@ public function create($spec)
7372
$spec = $this->validateSpecification($spec, __METHOD__);
7473
$type = isset($spec['type']) ? $spec['type'] : 'Zend\Form\Element';
7574

76-
if (SubClass::isSubclassOf($type, 'Zend\Form\FormInterface')) {
75+
if (self::isSubclassOf($type, 'Zend\Form\FormInterface')) {
7776
return $this->createForm($spec);
7877
}
7978

80-
if (SubClass::isSubclassOf($type, 'Zend\Form\FieldsetInterface')) {
79+
if (self::isSubclassOf($type, 'Zend\Form\FieldsetInterface')) {
8180
return $this->createFieldset($spec);
8281
}
8382

84-
if (SubClass::isSubclassOf($type, 'Zend\Form\ElementInterface')) {
83+
if (self::isSubclassOf($type, 'Zend\Form\ElementInterface')) {
8584
return $this->createElement($spec);
8685
}
8786

@@ -456,4 +455,28 @@ protected function prepareAndInjectValidationGroup($spec, FormInterface $form, $
456455

457456
$form->setValidationGroup($spec);
458457
}
458+
459+
/**
460+
* Checks if the object has this class as one of its parents
461+
*
462+
* @see https://bugs.php.net/bug.php?id=53727
463+
* @see https://github.com/zendframework/zf2/pull/1807
464+
*
465+
* @param string $className
466+
* @param string $type
467+
*/
468+
protected static function isSubclassOf($className, $type)
469+
{
470+
if (version_compare(PHP_VERSION, '5.3.7', '>=')) {
471+
return is_subclass_of($className, $type);
472+
}
473+
if (is_subclass_of($className, $type)) {
474+
return true;
475+
}
476+
if (!interface_exists($type)) {
477+
return false;
478+
}
479+
$r = new ReflectionClass($className);
480+
return $r->implementsInterface($type);
481+
}
459482
}

library/Zend/InfoCard/XML/AbstractElement.php

+25-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212

1313
use DOMElement;
1414
use SimpleXMLElement;
15-
use Zend\Stdlib\SubClass;
1615

1716
/**
1817
* An abstract class representing a an XML data block
@@ -68,7 +67,7 @@ static public function convertToObject(\DOMElement $e, $classname)
6867
throw new Exception\InvalidArgumentException('Class provided for converting does not exist');
6968
}
7069

71-
if (!SubClass::isSubclassOf($classname, 'Zend\InfoCard\XML\ElementInterface')) {
70+
if (!self::isSubclassOf($classname, 'Zend\InfoCard\XML\ElementInterface')) {
7271
throw new Exception\InvalidArgumentException("DOM element must be converted to an instance of Zend_InfoCard_Xml_Element");
7372
}
7473

@@ -83,4 +82,28 @@ static public function convertToObject(\DOMElement $e, $classname)
8382

8483
return $sxe;
8584
}
85+
86+
/**
87+
* Checks if the object has this class as one of its parents
88+
*
89+
* @see https://bugs.php.net/bug.php?id=53727
90+
* @see https://github.com/zendframework/zf2/pull/1807
91+
*
92+
* @param string $className
93+
* @param string $type
94+
*/
95+
protected static function isSubclassOf($className, $type)
96+
{
97+
if (version_compare(PHP_VERSION, '5.3.7', '>=')) {
98+
return is_subclass_of($className, $type);
99+
}
100+
if (is_subclass_of($className, $type)) {
101+
return true;
102+
}
103+
if (!interface_exists($type)) {
104+
return false;
105+
}
106+
$r = new ReflectionClass($className);
107+
return $r->implementsInterface($type);
108+
}
86109
}

library/Zend/Loader/AutoloaderFactory.php

+25-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ public static function factory($options = null)
9090
}
9191

9292
require_once __DIR__ . '/../Stdlib/SubClass.php';
93-
if (!\Zend\Stdlib\SubClass::isSubclassOf($class, 'Zend\Loader\SplAutoloader')) {
93+
if (!self::isSubclassOf($class, 'Zend\Loader\SplAutoloader')) {
9494
require_once 'Exception/InvalidArgumentException.php';
9595
throw new Exception\InvalidArgumentException(
9696
sprintf('Autoloader class %s must implement Zend\\Loader\\SplAutoloader', $class)
@@ -195,4 +195,28 @@ protected static function getStandardAutoloader()
195195
static::$standardAutoloader = $loader;
196196
return static::$standardAutoloader;
197197
}
198+
199+
/**
200+
* Checks if the object has this class as one of its parents
201+
*
202+
* @see https://bugs.php.net/bug.php?id=53727
203+
* @see https://github.com/zendframework/zf2/pull/1807
204+
*
205+
* @param string $className
206+
* @param string $type
207+
*/
208+
protected static function isSubclassOf($className, $type)
209+
{
210+
if (version_compare(PHP_VERSION, '5.3.7', '>=')) {
211+
return is_subclass_of($className, $type);
212+
}
213+
if (is_subclass_of($className, $type)) {
214+
return true;
215+
}
216+
if (!interface_exists($type)) {
217+
return false;
218+
}
219+
$r = new ReflectionClass($className);
220+
return $r->implementsInterface($type);
221+
}
198222
}

library/Zend/Mvc/Router/RoutePluginManager.php

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
namespace Zend\Mvc\Router;
1212

13-
use Zend\Stdlib\SubClass;
1413
use Zend\ServiceManager\AbstractPluginManager;
1514

1615
/**
@@ -80,7 +79,7 @@ protected function createFromInvokable($canonicalName, $requestedName)
8079
));
8180
}
8281

83-
if (!SubClass::isSubclassOf($invokable, __NAMESPACE__ . '\RouteInterface')) {
82+
if (!self::isSubclassOf($invokable, __NAMESPACE__ . '\RouteInterface')) {
8483
throw new Exception\RuntimeException(sprintf(
8584
'%s: failed retrieving "%s%s" via invokable class "%s"; class does not implement %s\RouteInterface',
8685
__METHOD__,

library/Zend/ServiceManager/AbstractPluginManager.php

+23
Original file line numberDiff line numberDiff line change
@@ -180,4 +180,27 @@ protected function createFromInvokable($canonicalName, $requestedName)
180180
return $instance;
181181
}
182182

183+
/**
184+
* Checks if the object has this class as one of its parents
185+
*
186+
* @see https://bugs.php.net/bug.php?id=53727
187+
* @see https://github.com/zendframework/zf2/pull/1807
188+
*
189+
* @param string $className
190+
* @param string $type
191+
*/
192+
protected static function isSubclassOf($className, $type)
193+
{
194+
if (version_compare(PHP_VERSION, '5.3.7', '>=')) {
195+
return is_subclass_of($className, $type);
196+
}
197+
if (is_subclass_of($className, $type)) {
198+
return true;
199+
}
200+
if (!interface_exists($type)) {
201+
return false;
202+
}
203+
$r = new ReflectionClass($className);
204+
return $r->implementsInterface($type);
205+
}
183206
}

library/Zend/XmlRpc/Server.php

+25-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
use Zend\Server\AbstractServer;
1414
use Zend\Server\Definition;
1515
use Zend\Server\Reflection;
16-
use Zend\Stdlib\SubClass;
1716

1817
/**
1918
* An XML-RPC server implementation
@@ -439,7 +438,7 @@ public function getResponse()
439438
*/
440439
public function setResponseClass($class)
441440
{
442-
if (!class_exists($class) || !SubClass::isSubclassOf($class, 'Zend\XmlRpc\Response')) {
441+
if (!class_exists($class) || !self::isSubclassOf($class, 'Zend\XmlRpc\Response')) {
443442
throw new Server\Exception\InvalidArgumentException('Invalid response class');
444443

445444
}
@@ -588,4 +587,28 @@ protected function registerSystemMethods()
588587
$this->_system = $system;
589588
$this->setClass($system, 'system');
590589
}
590+
591+
/**
592+
* Checks if the object has this class as one of its parents
593+
*
594+
* @see https://bugs.php.net/bug.php?id=53727
595+
* @see https://github.com/zendframework/zf2/pull/1807
596+
*
597+
* @param string $className
598+
* @param string $type
599+
*/
600+
protected static function isSubclassOf($className, $type)
601+
{
602+
if (version_compare(PHP_VERSION, '5.3.7', '>=')) {
603+
return is_subclass_of($className, $type);
604+
}
605+
if (is_subclass_of($className, $type)) {
606+
return true;
607+
}
608+
if (!interface_exists($type)) {
609+
return false;
610+
}
611+
$r = new ReflectionClass($className);
612+
return $r->implementsInterface($type);
613+
}
591614
}

tests/Zend/Stdlib/SubClassTest.php

-30
This file was deleted.

tests/Zend/Stdlib/TestAsset/DummySubclasses.php

-16
This file was deleted.

0 commit comments

Comments
 (0)