I don’t know if the instanceof operator can be fooled the way you want (recognize the class as a subclass if it’s not), but I think I have found a solution that can satisfy your needs. If I understand your problem correctly, you just want to introduce some methods into any class with minimal changes in the whole code.
I think the best way to prepare a solution in this case is to use traits (described here ). Using attributes, you can add methods to any class without direct inheritance and rewrite methods from the base class. For the rewriting method with traits, you certainly need subclasses, but they can be created dynamically. I don’t know anything about your packaging process, but in my decision I used a special class for it. Let's look at my solution:
namespace someNameSpace; //this is one of your class that you want to wrap - it can be declare under some other namespace if you need class yourBaseClass { } //your wrapper class as a trait trait yourWrapper { } //class for wrapping any object class ObjectWrapperClass { //method for change object class (described on http://stackoverflow.com/a/3243949/4662836) protected static function objectToObject($instance, $className) { return unserialize(sprintf('O:%d:"%s"%s', strlen($className), $className, strstr(strstr(serialize($instance), '"'), ':'))); } //wrapping method //$object is a object to be wrapped //$wrapper is a full name of the wrapper trait public static function wrap($object, $wrapper) { //take some information about the object to be wrapped $reflection = new \ReflectionClass($object); $baseClass = $reflection->getShortName(); $namespace = $reflection->getNamespaceName(); //perpare the name of the new wrapped class $newClassName = "{$baseClass}Wrapped"; //if new wrapped class has not been declared before we need to do it now if (!class_exists($newClassName)) { //prepare a code of the wrapping class that inject trait $newClassCode = "namespace {$namespace} { class {$newClassName} extends {$baseClass} { use {$wrapper}; } }"; //run the prepared code eval($newClassCode); } //change the object class and return it return self::objectToObject($object, $namespace . '\\' . $newClassName); } } //lets test this solution $originalObject = new yourBaseClass(); $wrappedObject = ObjectWrapperClass::wrap($originalObject, 'yourWrapper'); if ($wrappedObject instanceof yourBaseClass) { echo 'It is working'; }
As you can see, everything happens during the packaging process.
If you have more shells, you can prepare the new wrapped class name in another way (for example, to associate it with the shell name).
zajonc
source share