Verzeichnisstruktur phpBB-3.3.15


Veröffentlicht
28.08.2024

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: 02.04.2025, 15:03 - 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