/** * Generate code to cache from class reflection. * This is a total mess, I know. Just wanted to flesh out the logic. * * @todo Refactor into a class, clean up logic, DRY it up, maybe move * some of this into Zend\Code * @param ClassReflection $r * @return string */ protected static function getCacheCode(ClassReflection $r) { $useString = ''; $usesNames = array(); if (count($uses = $r->getDeclaringFile()->getUses())) { foreach ($uses as $use) { $usesNames[$use['use']] = $use['as']; $useString .= "use {$use['use']}"; if ($use['as']) { $useString .= " as {$use['as']}"; } $useString .= ";\n"; } } $declaration = ''; if ($r->isAbstract() && !$r->isInterface()) { $declaration .= 'abstract '; } if ($r->isFinal()) { $declaration .= 'final '; } if ($r->isInterface()) { $declaration .= 'interface '; } if (!$r->isInterface()) { $declaration .= 'class '; } $declaration .= $r->getShortName(); $parentName = false; if (($parent = $r->getParentClass()) && $r->getNamespaceName()) { $parentName = array_key_exists($parent->getName(), $usesNames) ? $usesNames[$parent->getName()] ?: $parent->getShortName() : (0 === strpos($parent->getName(), $r->getNamespaceName()) ? substr($parent->getName(), strlen($r->getNamespaceName()) + 1) : '\\' . $parent->getName()); } else { if ($parent && !$r->getNamespaceName()) { $parentName = '\\' . $parent->getName(); } } if ($parentName) { $declaration .= " extends {$parentName}"; } $interfaces = array_diff($r->getInterfaceNames(), $parent ? $parent->getInterfaceNames() : array()); if (count($interfaces)) { foreach ($interfaces as $interface) { $iReflection = new ClassReflection($interface); $interfaces = array_diff($interfaces, $iReflection->getInterfaceNames()); } $declaration .= $r->isInterface() ? ' extends ' : ' implements '; $declaration .= implode(', ', array_map(function ($interface) use($usesNames, $r) { $iReflection = new ClassReflection($interface); return array_key_exists($iReflection->getName(), $usesNames) ? $usesNames[$iReflection->getName()] ?: $iReflection->getShortName() : (0 === strpos($iReflection->getName(), $r->getNamespaceName()) ? substr($iReflection->getName(), strlen($r->getNamespaceName()) + 1) : '\\' . $iReflection->getName()); }, $interfaces)); } $classContents = $r->getContents(false); $classFileDir = dirname($r->getFileName()); $classContents = trim(str_replace('__DIR__', sprintf("'%s'", $classFileDir), $classContents)); $return = "\nnamespace " . $r->getNamespaceName() . " {\n" . $useString . $declaration . "\n" . $classContents . "\n}\n"; return $return; }
/** * Build a Code Generation Php Object from a Class Reflection * * @param ClassReflection $classReflection * @return InterfaceGenerator */ public static function fromReflection(ClassReflection $classReflection) { if (!$classReflection->isInterface()) { throw new Exception\InvalidArgumentException(sprintf('Class %s is not a interface', $classReflection->getName())); } // class generator $cg = new static($classReflection->getName()); $methods = []; $cg->setSourceContent($cg->getSourceContent()); $cg->setSourceDirty(false); if ($classReflection->getDocComment() != '') { $cg->setDocBlock(DocBlockGenerator::fromReflection($classReflection->getDocBlock())); } // set the namespace if ($classReflection->inNamespace()) { $cg->setNamespaceName($classReflection->getNamespaceName()); } foreach ($classReflection->getMethods() as $reflectionMethod) { $className = $cg->getNamespaceName() ? $cg->getNamespaceName() . '\\' . $cg->getName() : $cg->getName(); if ($reflectionMethod->getDeclaringClass()->getName() == $className) { $methods[] = MethodGenerator::fromReflection($reflectionMethod); } } foreach ($classReflection->getConstants() as $name => $value) { $cg->addConstant($name, $value); } $cg->addMethods($methods); return $cg; }
/** * Determine the class type (abstract, final, interface, class) * * @param ClassReflection $reflection * @return string */ public function getClassType(ClassReflection $reflection) { $classType = ''; if ($reflection->isAbstract() && !$reflection->isInterface()) { $classType .= 'abstract '; } if ($reflection->isFinal()) { $classType .= 'final '; } if ($reflection->isInterface()) { $classType .= 'interface '; } if (!$reflection->isInterface()) { $classType .= 'class '; } return $classType; }
/** * Retrieve a class's `implements` statement * * @param ClassReflection $reflection * @return string */ public function getInterfaceStatement(ClassReflection $reflection) { $interfaceStatement = ''; $parent = $reflection->getParentClass(); $interfaces = array_diff($reflection->getInterfaceNames(), $parent ? $parent->getInterfaceNames() : array()); if (!count($interfaces)) { return $interfaceStatement; } foreach ($interfaces as $interface) { $iReflection = new ClassReflection($interface); $interfaces = array_diff($interfaces, $iReflection->getInterfaceNames()); } $interfaceStatement .= $reflection->isInterface() ? ' extends ' : ' implements '; $classUseNameService = $this->classUseNameService; $interfaceStatement .= implode(', ', array_map(function ($interface) use($classUseNameService, $reflection) { $interfaceReflection = new ClassReflection($interface); return $classUseNameService->getClassUseName($reflection, $interfaceReflection); }, $interfaces)); return $interfaceStatement; }
/** * Build the interface part * * @param array $uses * @param Reflection\ClassReflection $class * @return string */ protected function buildInterface(&$uses, Reflection\ClassReflection $class) { $code = ''; $interfaces = $class->getInterfaces(); $parentClass = $class->getParentClass(); // Normalize interfaces array to string foreach ($interfaces as &$interface) { $interfaceReflections[$interface->getName()] = $interface; $interface = $interface->getName(); } // Remove interface from parent class if ($parentClass !== false) { $parentInterfaces = $parentClass->getInterfaces(); foreach ($parentInterfaces as &$parentInterface) { $interfaceReflections[$parentInterface->getName()] = $parentInterface; $parentInterface = $parentInterface->getName(); } $interfaces = array_diff($interfaces, $parentInterfaces); } // No interfaces found? Return '' if (count($interfaces) === 0) { return $code; } // Create extend/implement keyword $code .= $class->isInterface() ? ' extends ' : ' implements '; $classNamespace = $class->getNamespaceName(); // Retrieve interfaces from the interfaces foreach ($interfaces as &$interface) { $parentInterfaces = $interfaceReflections[$interface]->getInterfaces(); foreach ($parentInterfaces as &$parentInterface) { $interfaceReflections[$parentInterface->getName()] = $parentInterface; $parentInterface = $parentInterface->getName(); } // Remove already implemented interfaces $interfaces = array_diff($interfaces, $parentInterfaces); } // define interface names foreach ($interfaces as &$interface) { // Make sure the class has already been cached $this->processClassIntoCacheFile($interfaceReflections[$interface]); // Check if the interface has been defined in the uses if (array_key_exists($interface, $uses)) { // Set the use alias or the shortname when no alias has been set $interface = empty($uses[$interface]) ? $interfaceReflections[$interface]->getShortName() : $uses[$interface]; } else { // Check if we're implementing from a subnamespace $inNamespace = strpos($interface, $classNamespace) === 0; if ($inNamespace) { $interface = substr($interface, strlen($classNamespace) + 1); } else { $interface = "\\{$interface}"; } } } $code .= implode(', ', $interfaces); return $code; }
/** * @param ClassReflection $classReflection * @param $parent * @param $usesNames * @return string */ protected function extractInterfaceStatement(ClassReflection $classReflection, $parent, $usesNames) { $parentInterfaceNames = $parent instanceof ClassReflection ? $parent->getInterfaceNames() : array(); $interfaceNames = array_diff($classReflection->getInterfaceNames(), $parentInterfaceNames); $interfaceStatement = ''; if (!count($interfaceNames)) { return $interfaceStatement; } foreach ($interfaceNames as $interface) { $iReflection = new ClassReflection($interface); $interfaceNames = array_diff($interfaceNames, $iReflection->getInterfaceNames()); } $interfaceStatement .= $classReflection->isInterface() ? ' extends ' : ' implements '; $interfaceStatement .= implode(', ', array_map(function ($interface) use($usesNames, $classReflection) { $iReflection = new ClassReflection($interface); return array_key_exists($iReflection->getName(), $usesNames) ? $usesNames[$iReflection->getName()] ?: $iReflection->getShortName() : (0 === strpos($iReflection->getName(), $classReflection->getNamespaceName()) ? substr($iReflection->getName(), strlen($classReflection->getNamespaceName()) + 1) : '\\' . $iReflection->getName()); }, $interfaceNames)); return $interfaceStatement; }
/** * * @param ClassReflection $class * @return ClassReflection[] */ private function getInterfaces(ClassReflection $class) { $classes = []; foreach ($class->getInterfaces() as $interface) { $classes = array_merge($classes, $this->getInterfaces($interface)); } if ($class->isUserDefined() && $class->isInterface() && !in_array($class->getName(), $this->seen)) { $this->seen[] = $class->getName(); $classes[] = $class; } return $classes; }