Verzeichnisstruktur phpBB-3.3.16


Veröffentlicht
27.04.2026

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

ClassGenerator.php

Zuletzt modifiziert: 01.05.2026, 11:27 - Dateigröße: 28.96 KiB


 0001  <?php
 0002  /**
 0003   * Zend Framework (http://framework.zend.com/)
 0004   *
 0005   * @link      http://github.com/zendframework/zf2 for the canonical source repository
 0006   * @copyright Copyright (c) 2005-2016 Zend Technologies USA Inc. (http://www.zend.com)
 0007   * @license   http://framework.zend.com/license/new-bsd New BSD License
 0008   */
 0009   
 0010  namespace Zend\Code\Generator;
 0011   
 0012  use Zend\Code\Reflection\ClassReflection;
 0013   
 0014  use function array_diff;
 0015  use function array_map;
 0016  use function array_pop;
 0017  use function array_search;
 0018  use function array_values;
 0019  use function array_walk;
 0020  use function explode;
 0021  use function get_class;
 0022  use function gettype;
 0023  use function implode;
 0024  use function in_array;
 0025  use function is_array;
 0026  use function is_scalar;
 0027  use function is_string;
 0028  use function ltrim;
 0029  use function sprintf;
 0030  use function str_replace;
 0031  use function strpos;
 0032  use function strrpos;
 0033  use function strstr;
 0034  use function strtolower;
 0035  use function substr;
 0036   
 0037  class ClassGenerator extends AbstractGenerator implements TraitUsageInterface
 0038  {
 0039      const OBJECT_TYPE = 'class';
 0040      const IMPLEMENTS_KEYWORD = 'implements';
 0041   
 0042      const FLAG_ABSTRACT = 0x01;
 0043      const FLAG_FINAL    = 0x02;
 0044   
 0045      /**
 0046       * @var FileGenerator
 0047       */
 0048      protected $containingFileGenerator;
 0049   
 0050      /**
 0051       * @var string
 0052       */
 0053      protected $namespaceName;
 0054   
 0055      /**
 0056       * @var DocBlockGenerator
 0057       */
 0058      protected $docBlock;
 0059   
 0060      /**
 0061       * @var string
 0062       */
 0063      protected $name;
 0064   
 0065      /**
 0066       * @var bool
 0067       */
 0068      protected $flags = 0x00;
 0069   
 0070      /**
 0071       * @var string
 0072       */
 0073      protected $extendedClass;
 0074   
 0075      /**
 0076       * @var array Array of string names
 0077       */
 0078      protected $implementedInterfaces = [];
 0079   
 0080      /**
 0081       * @var PropertyGenerator[] Array of properties
 0082       */
 0083      protected $properties = [];
 0084   
 0085      /**
 0086       * @var PropertyGenerator[] Array of constants
 0087       */
 0088      protected $constants = [];
 0089   
 0090      /**
 0091       * @var MethodGenerator[] Array of methods
 0092       */
 0093      protected $methods = [];
 0094   
 0095      /**
 0096       * @var TraitUsageGenerator Object to encapsulate trait usage logic
 0097       */
 0098      protected $traitUsageGenerator;
 0099   
 0100      /**
 0101       * Build a Code Generation Php Object from a Class Reflection
 0102       *
 0103       * @param  ClassReflection $classReflection
 0104       * @return self
 0105       */
 0106      public static function fromReflection(ClassReflection $classReflection)
 0107      {
 0108          $cg = new static($classReflection->getName());
 0109   
 0110          $cg->setSourceContent($cg->getSourceContent());
 0111          $cg->setSourceDirty(false);
 0112   
 0113          if ($classReflection->getDocComment() != '') {
 0114              $cg->setDocBlock(DocBlockGenerator::fromReflection($classReflection->getDocBlock()));
 0115          }
 0116   
 0117          $cg->setAbstract($classReflection->isAbstract());
 0118   
 0119          // set the namespace
 0120          if ($classReflection->inNamespace()) {
 0121              $cg->setNamespaceName($classReflection->getNamespaceName());
 0122          }
 0123   
 0124          /* @var \Zend\Code\Reflection\ClassReflection $parentClass */
 0125          $parentClass = $classReflection->getParentClass();
 0126          $interfaces  = $classReflection->getInterfaces();
 0127   
 0128          if ($parentClass) {
 0129              $cg->setExtendedClass($parentClass->getName());
 0130   
 0131              $interfaces = array_diff($interfaces, $parentClass->getInterfaces());
 0132          }
 0133   
 0134          $interfaceNames = [];
 0135          foreach ($interfaces as $interface) {
 0136              /* @var \Zend\Code\Reflection\ClassReflection $interface */
 0137              $interfaceNames[] = $interface->getName();
 0138          }
 0139   
 0140          $cg->setImplementedInterfaces($interfaceNames);
 0141   
 0142          $properties = [];
 0143   
 0144          foreach ($classReflection->getProperties() as $reflectionProperty) {
 0145              if ($reflectionProperty->getDeclaringClass()->getName() == $classReflection->getName()) {
 0146                  $properties[] = PropertyGenerator::fromReflection($reflectionProperty);
 0147              }
 0148          }
 0149   
 0150          $cg->addProperties($properties);
 0151   
 0152          $constants = [];
 0153   
 0154          foreach ($classReflection->getConstants() as $name => $value) {
 0155              $constants[] = [
 0156                  'name' => $name,
 0157                  'value' => $value,
 0158              ];
 0159          }
 0160   
 0161          $cg->addConstants($constants);
 0162   
 0163          $methods = [];
 0164   
 0165          foreach ($classReflection->getMethods() as $reflectionMethod) {
 0166              $className = $cg->getNamespaceName() ? $cg->getNamespaceName() . '\\' . $cg->getName() : $cg->getName();
 0167   
 0168              if ($reflectionMethod->getDeclaringClass()->getName() == $className) {
 0169                  $methods[] = MethodGenerator::fromReflection($reflectionMethod);
 0170              }
 0171          }
 0172   
 0173          $cg->addMethods($methods);
 0174   
 0175          return $cg;
 0176      }
 0177   
 0178      /**
 0179       * Generate from array
 0180       *
 0181       * @configkey name           string        [required] Class Name
 0182       * @configkey filegenerator  FileGenerator File generator that holds this class
 0183       * @configkey namespacename  string        The namespace for this class
 0184       * @configkey docblock       string        The docblock information
 0185       * @configkey flags          int           Flags, one of ClassGenerator::FLAG_ABSTRACT ClassGenerator::FLAG_FINAL
 0186       * @configkey extendedclass  string        Class which this class is extending
 0187       * @configkey implementedinterfaces
 0188       * @configkey properties
 0189       * @configkey methods
 0190       *
 0191       * @throws Exception\InvalidArgumentException
 0192       * @param  array $array
 0193       * @return self
 0194       */
 0195      public static function fromArray(array $array)
 0196      {
 0197          if (! isset($array['name'])) {
 0198              throw new Exception\InvalidArgumentException(
 0199                  'Class generator requires that a name is provided for this object'
 0200              );
 0201          }
 0202   
 0203          $cg = new static($array['name']);
 0204          foreach ($array as $name => $value) {
 0205              // normalize key
 0206              switch (strtolower(str_replace(['.', '-', '_'], '', $name))) {
 0207                  case 'containingfile':
 0208                      $cg->setContainingFileGenerator($value);
 0209                      break;
 0210                  case 'namespacename':
 0211                      $cg->setNamespaceName($value);
 0212                      break;
 0213                  case 'docblock':
 0214                      $docBlock = $value instanceof DocBlockGenerator ? $value : DocBlockGenerator::fromArray($value);
 0215                      $cg->setDocBlock($docBlock);
 0216                      break;
 0217                  case 'flags':
 0218                      $cg->setFlags($value);
 0219                      break;
 0220                  case 'extendedclass':
 0221                      $cg->setExtendedClass($value);
 0222                      break;
 0223                  case 'implementedinterfaces':
 0224                      $cg->setImplementedInterfaces($value);
 0225                      break;
 0226                  case 'properties':
 0227                      $cg->addProperties($value);
 0228                      break;
 0229                  case 'methods':
 0230                      $cg->addMethods($value);
 0231                      break;
 0232              }
 0233          }
 0234   
 0235          return $cg;
 0236      }
 0237   
 0238      /**
 0239       * @param  string $name
 0240       * @param  string $namespaceName
 0241       * @param  array|string $flags
 0242       * @param  string $extends
 0243       * @param  array $interfaces
 0244       * @param  array $properties
 0245       * @param  array $methods
 0246       * @param  DocBlockGenerator $docBlock
 0247       */
 0248      public function __construct(
 0249          $name = null,
 0250          $namespaceName = null,
 0251          $flags = null,
 0252          $extends = null,
 0253          $interfaces = [],
 0254          $properties = [],
 0255          $methods = [],
 0256          $docBlock = null
 0257      ) {
 0258          $this->traitUsageGenerator = new TraitUsageGenerator($this);
 0259   
 0260          if ($name !== null) {
 0261              $this->setName($name);
 0262          }
 0263          if ($namespaceName !== null) {
 0264              $this->setNamespaceName($namespaceName);
 0265          }
 0266          if ($flags !== null) {
 0267              $this->setFlags($flags);
 0268          }
 0269          if ($properties !== []) {
 0270              $this->addProperties($properties);
 0271          }
 0272          if ($extends !== null) {
 0273              $this->setExtendedClass($extends);
 0274          }
 0275          if (is_array($interfaces)) {
 0276              $this->setImplementedInterfaces($interfaces);
 0277          }
 0278          if ($methods !== []) {
 0279              $this->addMethods($methods);
 0280          }
 0281          if ($docBlock !== null) {
 0282              $this->setDocBlock($docBlock);
 0283          }
 0284      }
 0285   
 0286      /**
 0287       * @param  string $name
 0288       * @return self
 0289       */
 0290      public function setName($name)
 0291      {
 0292          if (false !== strpos($name, '\\')) {
 0293              $namespace = substr($name, 0, strrpos($name, '\\'));
 0294              $name      = substr($name, strrpos($name, '\\') + 1);
 0295              $this->setNamespaceName($namespace);
 0296          }
 0297   
 0298          $this->name = $name;
 0299          return $this;
 0300      }
 0301   
 0302      /**
 0303       * @return string
 0304       */
 0305      public function getName()
 0306      {
 0307          return $this->name;
 0308      }
 0309   
 0310      /**
 0311       * @param  string $namespaceName
 0312       * @return self
 0313       */
 0314      public function setNamespaceName($namespaceName)
 0315      {
 0316          $this->namespaceName = $namespaceName;
 0317          return $this;
 0318      }
 0319   
 0320      /**
 0321       * @return string
 0322       */
 0323      public function getNamespaceName()
 0324      {
 0325          return $this->namespaceName;
 0326      }
 0327   
 0328      /**
 0329       * @param  FileGenerator $fileGenerator
 0330       * @return self
 0331       */
 0332      public function setContainingFileGenerator(FileGenerator $fileGenerator)
 0333      {
 0334          $this->containingFileGenerator = $fileGenerator;
 0335          return $this;
 0336      }
 0337   
 0338      /**
 0339       * @return FileGenerator
 0340       */
 0341      public function getContainingFileGenerator()
 0342      {
 0343          return $this->containingFileGenerator;
 0344      }
 0345   
 0346      /**
 0347       * @param  DocBlockGenerator $docBlock
 0348       * @return self
 0349       */
 0350      public function setDocBlock(DocBlockGenerator $docBlock)
 0351      {
 0352          $this->docBlock = $docBlock;
 0353          return $this;
 0354      }
 0355   
 0356      /**
 0357       * @return DocBlockGenerator
 0358       */
 0359      public function getDocBlock()
 0360      {
 0361          return $this->docBlock;
 0362      }
 0363   
 0364      /**
 0365       * @param  array|string $flags
 0366       * @return self
 0367       */
 0368      public function setFlags($flags)
 0369      {
 0370          if (is_array($flags)) {
 0371              $flagsArray = $flags;
 0372              $flags      = 0x00;
 0373              foreach ($flagsArray as $flag) {
 0374                  $flags |= $flag;
 0375              }
 0376          }
 0377          // check that visibility is one of three
 0378          $this->flags = $flags;
 0379   
 0380          return $this;
 0381      }
 0382   
 0383      /**
 0384       * @param  string $flag
 0385       * @return self
 0386       */
 0387      public function addFlag($flag)
 0388      {
 0389          $this->setFlags($this->flags | $flag);
 0390          return $this;
 0391      }
 0392   
 0393      /**
 0394       * @param  string $flag
 0395       * @return self
 0396       */
 0397      public function removeFlag($flag)
 0398      {
 0399          $this->setFlags($this->flags & ~$flag);
 0400          return $this;
 0401      }
 0402   
 0403      /**
 0404       * @param  bool $isAbstract
 0405       * @return self
 0406       */
 0407      public function setAbstract($isAbstract)
 0408      {
 0409          return $isAbstract ? $this->addFlag(self::FLAG_ABSTRACT) : $this->removeFlag(self::FLAG_ABSTRACT);
 0410      }
 0411   
 0412      /**
 0413       * @return bool
 0414       */
 0415      public function isAbstract()
 0416      {
 0417          return (bool) ($this->flags & self::FLAG_ABSTRACT);
 0418      }
 0419   
 0420      /**
 0421       * @param  bool $isFinal
 0422       * @return self
 0423       */
 0424      public function setFinal($isFinal)
 0425      {
 0426          return $isFinal ? $this->addFlag(self::FLAG_FINAL) : $this->removeFlag(self::FLAG_FINAL);
 0427      }
 0428   
 0429      /**
 0430       * @return bool
 0431       */
 0432      public function isFinal()
 0433      {
 0434          return $this->flags & self::FLAG_FINAL;
 0435      }
 0436   
 0437      /**
 0438       * @param  string $extendedClass
 0439       * @return self
 0440       */
 0441      public function setExtendedClass($extendedClass)
 0442      {
 0443          $this->extendedClass = $extendedClass;
 0444          return $this;
 0445      }
 0446   
 0447      /**
 0448       * @return string
 0449       */
 0450      public function getExtendedClass()
 0451      {
 0452          return $this->extendedClass;
 0453      }
 0454   
 0455      /**
 0456       * @return bool
 0457       */
 0458      public function hasExtentedClass()
 0459      {
 0460          return ! empty($this->extendedClass);
 0461      }
 0462   
 0463      /**
 0464       * @return self
 0465       */
 0466      public function removeExtentedClass()
 0467      {
 0468          $this->setExtendedClass(null);
 0469          return $this;
 0470      }
 0471   
 0472      /**
 0473       * @param  array $implementedInterfaces
 0474       * @return self
 0475       */
 0476      public function setImplementedInterfaces(array $implementedInterfaces)
 0477      {
 0478          array_map(function ($implementedInterface) {
 0479              return (string) TypeGenerator::fromTypeString($implementedInterface);
 0480          }, $implementedInterfaces);
 0481   
 0482          $this->implementedInterfaces = $implementedInterfaces;
 0483          return $this;
 0484      }
 0485   
 0486      /**
 0487       * @return array
 0488       */
 0489      public function getImplementedInterfaces()
 0490      {
 0491          return $this->implementedInterfaces;
 0492      }
 0493   
 0494      /**
 0495       * @param string $implementedInterface
 0496       * @return bool
 0497       */
 0498      public function hasImplementedInterface($implementedInterface)
 0499      {
 0500          $implementedInterface = (string) TypeGenerator::fromTypeString($implementedInterface);
 0501          return in_array($implementedInterface, $this->implementedInterfaces);
 0502      }
 0503   
 0504      /**
 0505       * @param string $implementedInterface
 0506       * @return self
 0507       */
 0508      public function removeImplementedInterface($implementedInterface)
 0509      {
 0510          $implementedInterface = (string) TypeGenerator::fromTypeString($implementedInterface);
 0511          unset($this->implementedInterfaces[array_search($implementedInterface, $this->implementedInterfaces)]);
 0512          return $this;
 0513      }
 0514   
 0515      /**
 0516       * @param  string $constantName
 0517       * @return PropertyGenerator|false
 0518       */
 0519      public function getConstant($constantName)
 0520      {
 0521          if (isset($this->constants[$constantName])) {
 0522              return $this->constants[$constantName];
 0523          }
 0524   
 0525          return false;
 0526      }
 0527   
 0528      /**
 0529       * @return PropertyGenerator[] indexed by constant name
 0530       */
 0531      public function getConstants()
 0532      {
 0533          return $this->constants;
 0534      }
 0535   
 0536      /**
 0537       * @param  string $constantName
 0538       * @return self
 0539       */
 0540      public function removeConstant($constantName)
 0541      {
 0542          unset($this->constants[$constantName]);
 0543   
 0544          return $this;
 0545      }
 0546   
 0547      /**
 0548       * @param  string $constantName
 0549       * @return bool
 0550       */
 0551      public function hasConstant($constantName)
 0552      {
 0553          return isset($this->constants[$constantName]);
 0554      }
 0555   
 0556      /**
 0557       * Add constant from PropertyGenerator
 0558       *
 0559       * @param  PropertyGenerator           $constant
 0560       * @throws Exception\InvalidArgumentException
 0561       * @return self
 0562       */
 0563      public function addConstantFromGenerator(PropertyGenerator $constant)
 0564      {
 0565          $constantName = $constant->getName();
 0566   
 0567          if (isset($this->constants[$constantName])) {
 0568              throw new Exception\InvalidArgumentException(sprintf(
 0569                  'A constant by name %s already exists in this class.',
 0570                  $constantName
 0571              ));
 0572          }
 0573   
 0574          if (! $constant->isConst()) {
 0575              throw new Exception\InvalidArgumentException(sprintf(
 0576                  'The value %s is not defined as a constant.',
 0577                  $constantName
 0578              ));
 0579          }
 0580   
 0581          $this->constants[$constantName] = $constant;
 0582   
 0583          return $this;
 0584      }
 0585   
 0586      /**
 0587       * Add Constant
 0588       *
 0589       * @param  string                      $name Non-empty string
 0590       * @param  string|int|null|float|array $value Scalar
 0591       *
 0592       * @throws Exception\InvalidArgumentException
 0593       *
 0594       * @return self
 0595       */
 0596      public function addConstant($name, $value)
 0597      {
 0598          if (empty($name) || ! is_string($name)) {
 0599              throw new Exception\InvalidArgumentException(sprintf(
 0600                  '%s expects string for name',
 0601                  __METHOD__
 0602              ));
 0603          }
 0604   
 0605          $this->validateConstantValue($value);
 0606   
 0607          return $this->addConstantFromGenerator(
 0608              new PropertyGenerator($name, new PropertyValueGenerator($value), PropertyGenerator::FLAG_CONSTANT)
 0609          );
 0610      }
 0611   
 0612      /**
 0613       * @param  PropertyGenerator[]|array[] $constants
 0614       *
 0615       * @return self
 0616       */
 0617      public function addConstants(array $constants)
 0618      {
 0619          foreach ($constants as $constant) {
 0620              if ($constant instanceof PropertyGenerator) {
 0621                  $this->addPropertyFromGenerator($constant);
 0622              } else {
 0623                  if (is_array($constant)) {
 0624                      $this->addConstant(...array_values($constant));
 0625                  }
 0626              }
 0627          }
 0628   
 0629          return $this;
 0630      }
 0631   
 0632      /**
 0633       * @param  array $properties
 0634       * @return self
 0635       */
 0636      public function addProperties(array $properties)
 0637      {
 0638          foreach ($properties as $property) {
 0639              if ($property instanceof PropertyGenerator) {
 0640                  $this->addPropertyFromGenerator($property);
 0641              } else {
 0642                  if (is_string($property)) {
 0643                      $this->addProperty($property);
 0644                  } elseif (is_array($property)) {
 0645                      $this->addProperty(...array_values($property));
 0646                  }
 0647              }
 0648          }
 0649   
 0650          return $this;
 0651      }
 0652   
 0653      /**
 0654       * Add Property from scalars
 0655       *
 0656       * @param  string $name
 0657       * @param  string|array $defaultValue
 0658       * @param  int $flags
 0659       * @throws Exception\InvalidArgumentException
 0660       * @return self
 0661       */
 0662      public function addProperty($name, $defaultValue = null, $flags = PropertyGenerator::FLAG_PUBLIC)
 0663      {
 0664          if (! is_string($name)) {
 0665              throw new Exception\InvalidArgumentException(sprintf(
 0666                  '%s::%s expects string for name',
 0667                  get_class($this),
 0668                  __FUNCTION__
 0669              ));
 0670          }
 0671   
 0672          // backwards compatibility
 0673          // @todo remove this on next major version
 0674          if ($flags === PropertyGenerator::FLAG_CONSTANT) {
 0675              return $this->addConstant($name, $defaultValue);
 0676          }
 0677   
 0678          return $this->addPropertyFromGenerator(new PropertyGenerator($name, $defaultValue, $flags));
 0679      }
 0680   
 0681      /**
 0682       * Add property from PropertyGenerator
 0683       *
 0684       * @param  PropertyGenerator           $property
 0685       * @throws Exception\InvalidArgumentException
 0686       * @return self
 0687       */
 0688      public function addPropertyFromGenerator(PropertyGenerator $property)
 0689      {
 0690          $propertyName = $property->getName();
 0691   
 0692          if (isset($this->properties[$propertyName])) {
 0693              throw new Exception\InvalidArgumentException(sprintf(
 0694                  'A property by name %s already exists in this class.',
 0695                  $propertyName
 0696              ));
 0697          }
 0698   
 0699          // backwards compatibility
 0700          // @todo remove this on next major version
 0701          if ($property->isConst()) {
 0702              return $this->addConstantFromGenerator($property);
 0703          }
 0704   
 0705          $this->properties[$propertyName] = $property;
 0706          return $this;
 0707      }
 0708   
 0709      /**
 0710       * @return PropertyGenerator[]
 0711       */
 0712      public function getProperties()
 0713      {
 0714          return $this->properties;
 0715      }
 0716   
 0717      /**
 0718       * @param  string $propertyName
 0719       * @return PropertyGenerator|false
 0720       */
 0721      public function getProperty($propertyName)
 0722      {
 0723          foreach ($this->getProperties() as $property) {
 0724              if ($property->getName() == $propertyName) {
 0725                  return $property;
 0726              }
 0727          }
 0728   
 0729          return false;
 0730      }
 0731   
 0732      /**
 0733       * Add a class to "use" classes
 0734       *
 0735       * @param  string $use
 0736       * @param  string|null $useAlias
 0737       * @return self
 0738       */
 0739      public function addUse($use, $useAlias = null)
 0740      {
 0741          $this->traitUsageGenerator->addUse($use, $useAlias);
 0742          return $this;
 0743      }
 0744   
 0745      /**
 0746       * @param string $use
 0747       * @return bool
 0748       */
 0749      public function hasUse($use)
 0750      {
 0751          return $this->traitUsageGenerator->hasUse($use);
 0752      }
 0753   
 0754      /**
 0755       * @param  string $use
 0756       * @return self
 0757       */
 0758      public function removeUse($use)
 0759      {
 0760          $this->traitUsageGenerator->removeUse($use);
 0761          return $this;
 0762      }
 0763   
 0764      /**
 0765       * @param string $use
 0766       * @return bool
 0767       */
 0768      public function hasUseAlias($use)
 0769      {
 0770          return $this->traitUsageGenerator->hasUseAlias($use);
 0771      }
 0772   
 0773      /**
 0774       * @param string $use
 0775       * @return self
 0776       */
 0777      public function removeUseAlias($use)
 0778      {
 0779          $this->traitUsageGenerator->removeUseAlias($use);
 0780          return $this;
 0781      }
 0782   
 0783      /**
 0784       * Returns the "use" classes
 0785       *
 0786       * @return array
 0787       */
 0788      public function getUses()
 0789      {
 0790          return $this->traitUsageGenerator->getUses();
 0791      }
 0792   
 0793      /**
 0794       * @param  string $propertyName
 0795       * @return self
 0796       */
 0797      public function removeProperty($propertyName)
 0798      {
 0799          unset($this->properties[$propertyName]);
 0800   
 0801          return $this;
 0802      }
 0803   
 0804      /**
 0805       * @param  string $propertyName
 0806       * @return bool
 0807       */
 0808      public function hasProperty($propertyName)
 0809      {
 0810          return isset($this->properties[$propertyName]);
 0811      }
 0812   
 0813      /**
 0814       * @param  array $methods
 0815       * @return self
 0816       */
 0817      public function addMethods(array $methods)
 0818      {
 0819          foreach ($methods as $method) {
 0820              if ($method instanceof MethodGenerator) {
 0821                  $this->addMethodFromGenerator($method);
 0822              } else {
 0823                  if (is_string($method)) {
 0824                      $this->addMethod($method);
 0825                  } elseif (is_array($method)) {
 0826                      $this->addMethod(...array_values($method));
 0827                  }
 0828              }
 0829          }
 0830   
 0831          return $this;
 0832      }
 0833   
 0834      /**
 0835       * Add Method from scalars
 0836       *
 0837       * @param  string $name
 0838       * @param  array $parameters
 0839       * @param  int $flags
 0840       * @param  string $body
 0841       * @param  string $docBlock
 0842       * @throws Exception\InvalidArgumentException
 0843       * @return self
 0844       */
 0845      public function addMethod(
 0846          $name,
 0847          array $parameters = [],
 0848          $flags = MethodGenerator::FLAG_PUBLIC,
 0849          $body = null,
 0850          $docBlock = null
 0851      ) {
 0852          if (! is_string($name)) {
 0853              throw new Exception\InvalidArgumentException(sprintf(
 0854                  '%s::%s expects string for name',
 0855                  get_class($this),
 0856                  __FUNCTION__
 0857              ));
 0858          }
 0859   
 0860          return $this->addMethodFromGenerator(new MethodGenerator($name, $parameters, $flags, $body, $docBlock));
 0861      }
 0862   
 0863      /**
 0864       * Add Method from MethodGenerator
 0865       *
 0866       * @param  MethodGenerator                    $method
 0867       * @throws Exception\InvalidArgumentException
 0868       * @return self
 0869       */
 0870      public function addMethodFromGenerator(MethodGenerator $method)
 0871      {
 0872          $methodName = $method->getName();
 0873   
 0874          if ($this->hasMethod($methodName)) {
 0875              throw new Exception\InvalidArgumentException(sprintf(
 0876                  'A method by name %s already exists in this class.',
 0877                  $methodName
 0878              ));
 0879          }
 0880   
 0881          $this->methods[strtolower($methodName)] = $method;
 0882          return $this;
 0883      }
 0884   
 0885      /**
 0886       * @return MethodGenerator[]
 0887       */
 0888      public function getMethods()
 0889      {
 0890          return $this->methods;
 0891      }
 0892   
 0893      /**
 0894       * @param  string $methodName
 0895       * @return MethodGenerator|false
 0896       */
 0897      public function getMethod($methodName)
 0898      {
 0899          return $this->hasMethod($methodName) ? $this->methods[strtolower($methodName)] : false;
 0900      }
 0901   
 0902      /**
 0903       * @param  string $methodName
 0904       * @return self
 0905       */
 0906      public function removeMethod($methodName)
 0907      {
 0908          unset($this->methods[strtolower($methodName)]);
 0909   
 0910          return $this;
 0911      }
 0912   
 0913      /**
 0914       * @param  string $methodName
 0915       * @return bool
 0916       */
 0917      public function hasMethod($methodName)
 0918      {
 0919          return isset($this->methods[strtolower($methodName)]);
 0920      }
 0921   
 0922      /**
 0923       * @inheritDoc
 0924       */
 0925      public function addTrait($trait)
 0926      {
 0927          $this->traitUsageGenerator->addTrait($trait);
 0928          return $this;
 0929      }
 0930   
 0931      /**
 0932       * @inheritDoc
 0933       */
 0934      public function addTraits(array $traits)
 0935      {
 0936          $this->traitUsageGenerator->addTraits($traits);
 0937          return $this;
 0938      }
 0939   
 0940      /**
 0941       * @inheritDoc
 0942       */
 0943      public function hasTrait($traitName)
 0944      {
 0945          return $this->traitUsageGenerator->hasTrait($traitName);
 0946      }
 0947   
 0948      /**
 0949       * @inheritDoc
 0950       */
 0951      public function getTraits()
 0952      {
 0953          return $this->traitUsageGenerator->getTraits();
 0954      }
 0955   
 0956      /**
 0957       * @inheritDoc
 0958       */
 0959      public function removeTrait($traitName)
 0960      {
 0961          return $this->traitUsageGenerator->removeTrait($traitName);
 0962      }
 0963   
 0964      /**
 0965       * @inheritDoc
 0966       */
 0967      public function addTraitAlias($method, $alias, $visibility = null)
 0968      {
 0969          $this->traitUsageGenerator->addTraitAlias($method, $alias, $visibility);
 0970          return $this;
 0971      }
 0972   
 0973      /**
 0974       * @inheritDoc
 0975       */
 0976      public function getTraitAliases()
 0977      {
 0978          return $this->traitUsageGenerator->getTraitAliases();
 0979      }
 0980   
 0981      /**
 0982       * @inheritDoc
 0983       */
 0984      public function addTraitOverride($method, $traitsToReplace)
 0985      {
 0986          $this->traitUsageGenerator->addTraitOverride($method, $traitsToReplace);
 0987          return $this;
 0988      }
 0989   
 0990      /**
 0991       * @inheritDoc
 0992       */
 0993      public function removeTraitOverride($method, $overridesToRemove = null)
 0994      {
 0995          $this->traitUsageGenerator->removeTraitOverride($method, $overridesToRemove);
 0996   
 0997          return $this;
 0998      }
 0999   
 1000      /**
 1001       * @inheritDoc
 1002       */
 1003      public function getTraitOverrides()
 1004      {
 1005          return $this->traitUsageGenerator->getTraitOverrides();
 1006      }
 1007   
 1008      /**
 1009       * @return bool
 1010       */
 1011      public function isSourceDirty()
 1012      {
 1013          if (($docBlock = $this->getDocBlock()) && $docBlock->isSourceDirty()) {
 1014              return true;
 1015          }
 1016   
 1017          foreach ($this->getProperties() as $property) {
 1018              if ($property->isSourceDirty()) {
 1019                  return true;
 1020              }
 1021          }
 1022   
 1023          foreach ($this->getMethods() as $method) {
 1024              if ($method->isSourceDirty()) {
 1025                  return true;
 1026              }
 1027          }
 1028   
 1029          return parent::isSourceDirty();
 1030      }
 1031   
 1032      /**
 1033       * @inheritDoc
 1034       */
 1035      public function generate()
 1036      {
 1037          if (! $this->isSourceDirty()) {
 1038              $output = $this->getSourceContent();
 1039              if (! empty($output)) {
 1040                  return $output;
 1041              }
 1042          }
 1043   
 1044          $indent = $this->getIndentation();
 1045          $output = '';
 1046   
 1047          if (null !== ($namespace = $this->getNamespaceName())) {
 1048              $output .= 'namespace ' . $namespace . ';' . self::LINE_FEED . self::LINE_FEED;
 1049          }
 1050   
 1051          $uses = $this->getUses();
 1052   
 1053          if (! empty($uses)) {
 1054              foreach ($uses as $use) {
 1055                  $output .= 'use ' . $use . ';' . self::LINE_FEED;
 1056              }
 1057   
 1058              $output .= self::LINE_FEED;
 1059          }
 1060   
 1061          if (null !== ($docBlock = $this->getDocBlock())) {
 1062              $docBlock->setIndentation('');
 1063              $output .= $docBlock->generate();
 1064          }
 1065   
 1066          if ($this->isAbstract()) {
 1067              $output .= 'abstract ';
 1068          } elseif ($this->isFinal()) {
 1069              $output .= 'final ';
 1070          }
 1071   
 1072          $output .= static::OBJECT_TYPE . ' ' . $this->getName();
 1073   
 1074          if (! empty($this->extendedClass)) {
 1075              $output .= ' extends ' . $this->generateShortOrCompleteClassname($this->extendedClass);
 1076          }
 1077   
 1078          $implemented = $this->getImplementedInterfaces();
 1079   
 1080          if (! empty($implemented)) {
 1081              $implemented = array_map([$this, 'generateShortOrCompleteClassname'], $implemented);
 1082              $output .= ' ' . static::IMPLEMENTS_KEYWORD . ' ' . implode(', ', $implemented);
 1083          }
 1084   
 1085          $output .= self::LINE_FEED . '{' . self::LINE_FEED . self::LINE_FEED;
 1086          $output .= $this->traitUsageGenerator->generate();
 1087   
 1088          $constants = $this->getConstants();
 1089   
 1090          foreach ($constants as $constant) {
 1091              $output .= $constant->generate() . self::LINE_FEED . self::LINE_FEED;
 1092          }
 1093   
 1094          $properties = $this->getProperties();
 1095   
 1096          foreach ($properties as $property) {
 1097              $output .= $property->generate() . self::LINE_FEED . self::LINE_FEED;
 1098          }
 1099   
 1100          $methods = $this->getMethods();
 1101   
 1102          foreach ($methods as $method) {
 1103              $output .= $method->generate() . self::LINE_FEED;
 1104          }
 1105   
 1106          $output .= self::LINE_FEED . '}' . self::LINE_FEED;
 1107   
 1108          return $output;
 1109      }
 1110   
 1111      /**
 1112       * @param mixed $value
 1113       *
 1114       * @return void
 1115       *
 1116       * @throws Exception\InvalidArgumentException
 1117       */
 1118      private function validateConstantValue($value)
 1119      {
 1120          if (null === $value || is_scalar($value)) {
 1121              return;
 1122          }
 1123   
 1124          if (is_array($value)) {
 1125              array_walk($value, [$this, 'validateConstantValue']);
 1126   
 1127              return;
 1128          }
 1129   
 1130          throw new Exception\InvalidArgumentException(sprintf(
 1131              'Expected value for constant, value must be a "scalar" or "null", "%s" found',
 1132              gettype($value)
 1133          ));
 1134      }
 1135   
 1136      /**
 1137       * @param string $fqnClassName
 1138       *
 1139       * @return string
 1140       */
 1141      private function generateShortOrCompleteClassname($fqnClassName)
 1142      {
 1143          $fqnClassName = ltrim($fqnClassName, '\\');
 1144          $parts = explode('\\', $fqnClassName);
 1145          $className = array_pop($parts);
 1146          $classNamespace = implode('\\', $parts);
 1147          $currentNamespace = (string) $this->getNamespaceName();
 1148   
 1149          if ($this->hasUseAlias($fqnClassName)) {
 1150              return $this->traitUsageGenerator->getUseAlias($fqnClassName);
 1151          }
 1152          if ($this->hasUseAlias($classNamespace)) {
 1153              $namespaceAlias = $this->traitUsageGenerator->getUseAlias($classNamespace);
 1154   
 1155              return $namespaceAlias . '\\' . $className;
 1156          }
 1157          if ($this->traitUsageGenerator->isUseAlias($fqnClassName)) {
 1158              return $fqnClassName;
 1159          }
 1160          if ($this->traitUsageGenerator->isUseAlias($classNamespace)) {
 1161              return $fqnClassName;
 1162          }
 1163          if ($classNamespace === $currentNamespace || in_array($fqnClassName, $this->getUses())) {
 1164              return $className;
 1165          }
 1166   
 1167          return '\\' . $fqnClassName;
 1168      }
 1169  }
 1170