#!/usr/bin/env php
<?php
/**
 * Define global constant that marks this as PHPMD phar release.
 */
define('PHP_PMD_RELEASE', 'phar');

Phar::mapPhar( 'phpmd.phar' );

// Configure include path to use this phar
set_include_path('phar://phpmd.phar/' . PATH_SEPARATOR . get_include_path());

if (isset($argv) && realpath($argv[0]) === __FILE__) {

    // Load command line utility
    include_once 'phar://phpmd.phar/vendor/autoload.php';

    // Run command line interface
    exit(\PHPMD\TextUI\Command::main($argv));
}
__HALT_COMPILER(); ?>
Ã  ç              )   src/main/resources/rulesets/cleancode.xml\   "‚X\  	hýS¶      -   src/main/resources/rulesets/controversial.xmlà   "‚Xà  D˜¶      &   src/main/resources/rulesets/design.xmlF   "‚XF  æ¶¥«¶      *   src/main/resources/rulesets/unusedcode.xmlõ   "‚Xõ  “í‡¶      &   src/main/resources/rulesets/naming.xml0   "‚X0  >s Þ¶      (   src/main/resources/rulesets/codesize.xml—9   "‚X—9  ß
§ß¶         src/main/php/PHPMD/Parser.phpŒ!   "‚XŒ!  öÖ�X¶      #   src/main/php/PHPMD/AbstractRule.php(   "‚X(  ¡ø +¶      %   src/main/php/PHPMD/TextUI/Command.phpá   "‚Xá  ‰S9f¶      0   src/main/php/PHPMD/TextUI/CommandLineOptions.php°9   "‚X°9  Ü4/B¶         src/main/php/PHPMD/RuleSet.phpà   "‚Xà  Ð}lc¶         src/main/php/PHPMD/Report.php   "‚X  c‡ÿ¶      %   src/main/php/PHPMD/AbstractWriter.php	   "‚X	  Íá¤"¶      1   src/main/php/PHPMD/RuleClassNotFoundException.php˜	   "‚X˜	  d‚ì¶      ,   src/main/php/PHPMD/Renderer/HTMLRenderer.phpc   "‚Xc  é$µM¶      ,   src/main/php/PHPMD/Renderer/TextRenderer.php6   "‚X6  k»¤Z¶      +   src/main/php/PHPMD/Renderer/XMLRenderer.phpË   "‚XË  ù+x¢¶         src/main/php/PHPMD/Rule.php(   "‚X(  ˆÛ—¶      -   src/main/php/PHPMD/Rule/Design/LongMethod.phpŒ   "‚XŒ  ×ÐÒ3¶      7   src/main/php/PHPMD/Rule/Design/TooManyPublicMethods.phpË   "‚XË  ³U·¶      1   src/main/php/PHPMD/Rule/Design/TooManyMethods.php‡   "‚X‡  ˜†ÄÝ¶      4   src/main/php/PHPMD/Rule/Design/LongParameterList.php¸   "‚X¸  ŽŒGf¶      6   src/main/php/PHPMD/Rule/Design/WeightedMethodCount.php    "‚X   óÊ¯N¶      ,   src/main/php/PHPMD/Rule/Design/LongClass.phps   "‚Xs  `ì9o¶      3   src/main/php/PHPMD/Rule/Design/NumberOfChildren.phpc   "‚Xc  GËaý¶      :   src/main/php/PHPMD/Rule/Design/DevelopmentCodeFragment.phpž   "‚Xž  àù{¶      2   src/main/php/PHPMD/Rule/Design/NpathComplexity.php¹   "‚X¹  š3$ã¶      0   src/main/php/PHPMD/Rule/Design/TooManyFields.phpv   "‚Xv  ÉýˆÞ¶      1   src/main/php/PHPMD/Rule/Design/EvalExpression.phpÖ
   "‚XÖ
  uÝ6¹¶      1   src/main/php/PHPMD/Rule/Design/ExitExpression.phpÕ
   "‚XÕ
  ‹f(�¶      9   src/main/php/PHPMD/Rule/Design/CouplingBetweenObjects.php$   "‚X$  ¡—¬X¶      5   src/main/php/PHPMD/Rule/Design/DepthOfInheritance.php   "‚X  ^·²Ï¶      0   src/main/php/PHPMD/Rule/Design/GotoStatement.php   "‚X  ¿Àn¶      '   src/main/php/PHPMD/Rule/MethodAware.phpq   "‚Xq  òu½¶      0   src/main/php/PHPMD/Rule/CyclomaticComplexity.php}   "‚X}  ´´•¶      /   src/main/php/PHPMD/Rule/Naming/LongVariable.phpê   "‚Xê  cä^ù¶      <   src/main/php/PHPMD/Rule/Naming/ConstantNamingConventions.phpl   "‚Xl  ~Œ­§¶      F   src/main/php/PHPMD/Rule/Naming/ConstructorWithNameAsEnclosingClass.php   "‚X  6&¶      2   src/main/php/PHPMD/Rule/Naming/ShortMethodName.php–   "‚X–  «ñA§¶      7   src/main/php/PHPMD/Rule/Naming/BooleanGetMethodName.phpä   "‚Xä  xÇŸ>¶      0   src/main/php/PHPMD/Rule/Naming/ShortVariable.php    "‚X   � U¶      /   src/main/php/PHPMD/Rule/UnusedPrivateMethod.phpM   "‚XM  q)t4¶      /   src/main/php/PHPMD/Rule/UnusedLocalVariable.php-   "‚X-  Á]~c¶      1   src/main/php/PHPMD/Rule/AbstractLocalVariable.php9   "‚X9  ¦ðsÛ¶      0   src/main/php/PHPMD/Rule/ExcessivePublicCount.phpÀ   "‚XÀ  ~+…�¶      6   src/main/php/PHPMD/Rule/Controversial/Superglobals.php+   "‚X+  ?yí¶      ?   src/main/php/PHPMD/Rule/Controversial/CamelCasePropertyName.phps   "‚Xs  öÏï¶      @   src/main/php/PHPMD/Rule/Controversial/CamelCaseParameterName.php«   "‚X«  ™’N¶      =   src/main/php/PHPMD/Rule/Controversial/CamelCaseMethodName.phpª   "‚Xª  f–ü¹¶      ?   src/main/php/PHPMD/Rule/Controversial/CamelCaseVariableName.phpx   "‚Xx  ¦í¶      <   src/main/php/PHPMD/Rule/Controversial/CamelCaseClassName.php1   "‚X1  ÃX†ç¶      .   src/main/php/PHPMD/Rule/UnusedPrivateField.phpo   "‚Xo  S8¹Þ¶      *   src/main/php/PHPMD/Rule/InterfaceAware.phpw   "‚Xw  çÑ˜é¶      4   src/main/php/PHPMD/Rule/CleanCode/ElseExpression.phpì   "‚Xì  Ëu�¶      2   src/main/php/PHPMD/Rule/CleanCode/StaticAccess.php­   "‚X­  %ôhl¶      9   src/main/php/PHPMD/Rule/CleanCode/BooleanArgumentFlag.phpÙ   "‚XÙ  
‹¥`¶      )   src/main/php/PHPMD/Rule/FunctionAware.php   "‚X  žû‹¶      1   src/main/php/PHPMD/Rule/UnusedFormalParameter.phpì   "‚Xì  É…ýN¶      &   src/main/php/PHPMD/Rule/ClassAware.phpy   "‚Xy  Û`Æ¶      /   src/main/php/PHPMD/RuleSetNotFoundException.phpÖ	   "‚XÖ	  à£M¶      '   src/main/php/PHPMD/AbstractRenderer.php@   "‚X@  
Hê£¶         src/main/php/PHPMD/PHPMD.phpç   "‚Xç  áªØJ¶      $   src/main/php/PHPMD/ParserFactory.phpM   "‚XM  K™RÆ¶      )   src/main/php/PHPMD/Node/InterfaceNode.php…	   "‚X…	  „zz
¶      &   src/main/php/PHPMD/Node/MethodNode.php   "‚X  ÌnÙâ¶      %   src/main/php/PHPMD/Node/TraitNode.phpu	   "‚Xu	  ÿˆ«¶      '   src/main/php/PHPMD/Node/Annotations.phpÊ   "‚XÊ  ÄÄõÒ¶      #   src/main/php/PHPMD/Node/ASTNode.php   "‚X  �u›o¶      ,   src/main/php/PHPMD/Node/AbstractTypeNode.php¥   "‚X¥  äêF¶      0   src/main/php/PHPMD/Node/AbstractCallableNode.php�
   "‚X�
  ~¨�¶      (   src/main/php/PHPMD/Node/AbstractNode.php¹
   "‚X¹
  ô¯“¶      &   src/main/php/PHPMD/Node/Annotation.php»   "‚X»  ú:¶      %   src/main/php/PHPMD/Node/ClassNode.php¶	   "‚X¶	  á€,k¶      (   src/main/php/PHPMD/Node/FunctionNode.php-   "‚X-  ŸÑ¹k¶      5   src/main/php/PHPMD/RuleClassFileNotFoundException.phpÞ	   "‚XÞ	  mcXn¶      #   src/main/php/PHPMD/AbstractNode.phpµ    "‚Xµ   
øÃ¶      &   src/main/php/PHPMD/ProcessingError.php    "‚X   IEd¶      $   src/main/php/PHPMD/RuleViolation.phpL   "‚XL  `ip¶      *   src/main/php/PHPMD/Writer/StreamWriter.phpç   "‚Xç  >ÎÈ¶      %   src/main/php/PHPMD/RuleSetFactory.phpH   "‚XH  ¿
@¶¶      !   vendor/composer/autoload_psr4.phpß    "‚Xß   _Ý2ò¶      #   vendor/composer/autoload_static.phpz   "‚Xz  °¨Ì¶         vendor/composer/installed.json   "‚X  <é¶      %   vendor/composer/autoload_classmap.php“    "‚X“   µøb¶         vendor/composer/LICENSE3   "‚X3  û·þ¶      !   vendor/composer/autoload_real.phpâ   "‚Xâ  ³_«¶      '   vendor/composer/autoload_namespaces.phpÓ   "‚XÓ  ç|W²¶         vendor/composer/ClassLoader.phpÀ3   "‚XÀ3  y‹~Æ¶      P   vendor/symfony/filesystem/Symfony/Component/Filesystem/Exception/IOException.phpù   "‚Xù  †=é®¶      W   vendor/symfony/filesystem/Symfony/Component/Filesystem/Exception/ExceptionInterface.phpÉ   "‚XÉ  ev¼¶      E   vendor/symfony/filesystem/Symfony/Component/Filesystem/Filesystem.php»C   "‚X»C  ó¸øå¶      G   vendor/symfony/filesystem/Symfony/Component/Filesystem/phpunit.xml.dist	   "‚X	  ÞEjc¶      D   vendor/symfony/filesystem/Symfony/Component/Filesystem/composer.jsonë   "‚Xë  'ÅYs¶      >   vendor/symfony/filesystem/Symfony/Component/Filesystem/LICENSE)   "‚X)  NmòQ¶      C   vendor/symfony/filesystem/Symfony/Component/Filesystem/CHANGELOG.md6   "‚X6  ‹ÝÝ!¶      @   vendor/symfony/filesystem/Symfony/Component/Filesystem/README.md    "‚X   !]Òþ¶      ^   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/SimpleXMLElement.php�   "‚X�  Â˜Î¶      ^   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php¦(   "‚X¦(  —X€ó¶      _   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php7"   "‚X7"  ›¼1¶      c   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/GraphvizDumper.phpû%   "‚Xû%  ‡·Òù¶      d   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/DumperInterface.phpÝ   "‚XÝ  }Ú¶      [   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/Dumper.php+   "‚X+  N/ì¶      ^   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php÷¤   "‚X÷¤  /h`B¶      W   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Parameter.phpÿ   "‚Xÿ  ­‰F"¶      S   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Alias.phpü   "‚Xü  l5’‘¶      a   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/DefinitionDecorator.php«   "‚X«  —¬¼¶      \   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ScopeInterface.php   "‚X  _¤ÊJ¶      r   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/ParameterNotFoundException.phpÂ
   "‚XÂ
  ¼ø\¶      w   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/ScopeCrossingInjectionException.php¥   "‚X¥  = Ô¶      w   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/ScopeWideningInjectionException.php—   "‚X—  ¼£úz¶      p   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/InvalidArgumentException.php   "‚X  Ïß ¶      j   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/ExceptionInterface.php   "‚X  ³Ú9¶      l   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/OutOfBoundsException.phpÎ   "‚XÎ  ™{­Œ¶      h   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/RuntimeException.phpû   "‚Xû  è
+¶      {   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/ParameterCircularReferenceException.php    "‚X   ÓqB¶      p   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/ServiceNotFoundException.php½   "‚X½  ­Ì¶      f   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/LogicException.php¼   "‚X¼  l.à¶      n   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/BadMethodCallException.phpÔ   "‚XÔ  
Oö,¶      y   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/ServiceCircularReferenceException.phpó   "‚Xó  ‚ø]ý¶      n   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Exception/InactiveScopeException.phpî   "‚Xî  I_çý¶      f   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/TaggedContainerInterface.phpí   "‚Xí  ÁÂÀ¶      ^   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerBuilder.php™   "‚X™  Œ]e%¶      \   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerAware.phpi   "‚Xi  ðúuê¶      S   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Scope.phpm   "‚Xm  ö,x†¶      Z   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/phpunit.xml.distu   "‚Xu  Úúù¥¶      l   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/CompilerPassInterface.phpê   "‚Xê  Ï_9¶      l   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraph.php’   "‚X’  Ë®š¶      r   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/RemoveUnusedDefinitionsPass.phpÔ
   "‚XÔ
  ¢iÛZ¶      o   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/RemovePrivateAliasesPass.phpó   "‚Xó  ®!ä?¶      ƒ   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php6   "‚X6  b[_¸¶      r   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php0   "‚X0  üÖ{¶¶      y   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ReplaceAliasByActualDefinitionPass.phpF   "‚XF  Lž×¶      v   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/MergeExtensionConfigurationPass.php\   "‚X\  X¬¶      s   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php‹   "‚X‹  PS~¶      _   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/Compiler.phpˆ
   "‚Xˆ
  F�«°¶      s   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ResolveInvalidReferencesPass.php¬   "‚X¬  ŒiJT¶      u   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ResolveReferencesToAliasesPass.phpP   "‚XP  �õ¶      p   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraphNode.php"
   "‚X"
  \‹˜j¶      s   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/AnalyzeServiceReferencesPass.php    "‚X   •Û»Ç¶      t   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/RemoveAbstractDefinitionsPass.php'   "‚X'  ¬­U*¶      g   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/LoggingFormatter.php¼   "‚X¼  ®õú¶      a   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/PassConfig.php   "‚X  2‰bº¶      p   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraphEdge.phpí   "‚Xí  x¼7Û¶      w   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ResolveParameterPlaceHoldersPass.phpn   "‚Xn  ãôé¶      q   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/CheckReferenceValidityPass.php   "‚X  �î ²¶      c   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/RepeatedPass.php#   "‚X#  ¸0Ñ”¶      u   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php   "‚X  \vÁI¶      n   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/RepeatablePassInterface.php³   "‚X³  �éEÅ¶      r   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Compiler/CheckCircularReferencesPass.phpŸ   "‚XŸ  Qò³‹¶      W   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/composer.json   "‚X  õg›¶      l   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/NullDumper.phpò   "‚Xò  3y˜²¶      q   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/DumperInterface.phpY   "‚XY  `iÚU¶      |   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/LazyProxy/Instantiator/RealServiceInstantiator.phpn   "‚Xn  —iØ¶      z   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/LazyProxy/Instantiator/InstantiatorInterface.phpJ   "‚XJ  ¬ñçÜ¶      Q   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/LICENSE)   "‚X)  NmòQ¶      W   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Container.php>   "‚X>  ¼°Q`¶      c   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.phpº*   "‚Xº*  �Wˆ�¶      b   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php–7   "‚X–7  œOX¶      _   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/FileLoader.php-   "‚X-  UÇêa¶      u   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsdT   "‚XT  ]æxá¶      b   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/ClosureLoader.phpñ   "‚Xñ  Æ
¥¶      b   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/IniFileLoader.php   "‚X  Ó¸Bj¶      b   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Loader/PhpFileLoader.php&   "‚X&  »«OO¶      X   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Definition.phpè9   "‚Xè9  ¹>Ò´¶      V   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Variable.php7   "‚X7  $–¶      n   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/IntrospectableContainerInterface.phpB   "‚XB  ¦Bt¶      m   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ParameterBag/FrozenParameterBag.php    "‚X   ×šä¶      g   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.phpV    "‚XV   ªIÓ¯¶      p   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ParameterBag/ParameterBagInterface.php©	   "‚X©	  Ü®P8¶      V   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/CHANGELOG.md   "‚X  ,¼(Ù¶      `   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerInterface.php   "‚X  íE„?¶      w   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Extension/ConfigurationExtensionInterface.phpä   "‚Xä  ™üJ¶      q   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Extension/PrependExtensionInterface.phpM   "‚XM  C³½o¶      j   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Extension/ExtensionInterface.php   "‚X  J0bÄ¶      a   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Extension/Extension.php   "‚X  ïoŸ¶      e   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/ContainerAwareInterface.phpÊ   "‚XÊ  q8I�¶      S   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/README.mdÏ   "‚XÏ  _Q› ¶      W   vendor/symfony/dependency-injection/Symfony/Component/DependencyInjection/Reference.php5   "‚X5  y&Ã(¶      @   vendor/symfony/config/Symfony/Component/Config/Util/XmlUtils.php‰   "‚X‰  )…ƒ¢¶      g   vendor/symfony/config/Symfony/Component/Config/Exception/FileLoaderImportCircularReferenceException.phpT   "‚XT  7¡¶      T   vendor/symfony/config/Symfony/Component/Config/Exception/FileLoaderLoadException.phpõ	   "‚Xõ	  µÆW¶      T   vendor/symfony/config/Symfony/Component/Config/Definition/ConfigurationInterface.phpd   "‚Xd  *†¡’¶      I   vendor/symfony/config/Symfony/Component/Config/Definition/NumericNode.php   "‚X  x^*ê¶      J   vendor/symfony/config/Symfony/Component/Config/Definition/VariableNode.php¸	   "‚X¸	  $íÂ¶      Y   vendor/symfony/config/Symfony/Component/Config/Definition/Exception/UnsetKeyException.php   "‚X  þ¤½¿¶      e   vendor/symfony/config/Symfony/Component/Config/Definition/Exception/InvalidConfigurationException.php·   "‚X·  5-ý¶      b   vendor/symfony/config/Symfony/Component/Config/Definition/Exception/InvalidDefinitionException.phpÚ   "‚XÚ  ]F4ç¶      ]   vendor/symfony/config/Symfony/Component/Config/Definition/Exception/DuplicateKeyException.phpE   "‚XE  ø|÷¶      Q   vendor/symfony/config/Symfony/Component/Config/Definition/Exception/Exception.phpÊ   "‚XÊ  žCŠÐ¶      \   vendor/symfony/config/Symfony/Component/Config/Definition/Exception/InvalidTypeException.phpí   "‚Xí  ¾Ä@¶      c   vendor/symfony/config/Symfony/Component/Config/Definition/Exception/ForbiddenOverwriteException.phpQ   "‚XQ  ¨:2&¶      \   vendor/symfony/config/Symfony/Component/Config/Definition/Builder/VariableNodeDefinition.php¿   "‚X¿  £�S¶      Y   vendor/symfony/config/Symfony/Component/Config/Definition/Builder/NodeParentInterface.php¾   "‚X¾  Uý‘=¶      W   vendor/symfony/config/Symfony/Component/Config/Definition/Builder/ValidationBuilder.phpr   "‚Xr  Œä�Ó¶      T   vendor/symfony/config/Symfony/Component/Config/Definition/Builder/NodeDefinition.phpR   "‚XR  .!U¶      Q   vendor/symfony/config/Symfony/Component/Config/Definition/Builder/NodeBuilder.php²   "‚X²   Ô}í¶      Y   vendor/symfony/config/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.phpç9   "‚Xç9  ë"ìR¶      Q   vendor/symfony/config/Symfony/Component/Config/Definition/Builder/ExprBuilder.php   "‚X  íä¶      [   vendor/symfony/config/Symfony/Component/Config/Definition/Builder/NumericNodeDefinition.phpX   "‚XX  ~ýG‡¶      R   vendor/symfony/config/Symfony/Component/Config/Definition/Builder/MergeBuilder.phpµ   "‚Xµ  ’/_l¶      [   vendor/symfony/config/Symfony/Component/Config/Definition/Builder/IntegerNodeDefinition.php   "‚X  'nÚ­¶      [   vendor/symfony/config/Symfony/Component/Config/Definition/Builder/BooleanNodeDefinition.php±   "‚X±  P�”¶      Q   vendor/symfony/config/Symfony/Component/Config/Definition/Builder/TreeBuilder.php�   "‚X�  VÈhU¶      Y   vendor/symfony/config/Symfony/Component/Config/Definition/Builder/FloatNodeDefinition.phpù   "‚Xù  t£p¶      Z   vendor/symfony/config/Symfony/Component/Config/Definition/Builder/ScalarNodeDefinition.phpÝ   "‚XÝ  Ûmc¶      X   vendor/symfony/config/Symfony/Component/Config/Definition/Builder/EnumNodeDefinition.phpý   "‚Xý  Â~ ¶      c   vendor/symfony/config/Symfony/Component/Config/Definition/Builder/ParentNodeDefinitionInterface.php_   "‚X_  ¢3dä¶      Z   vendor/symfony/config/Symfony/Component/Config/Definition/Builder/NormalizationBuilder.phpƒ   "‚Xƒ  ¦ø®¶      Q   vendor/symfony/config/Symfony/Component/Config/Definition/PrototypedArrayNode.phpo(   "‚Xo(  œÃ¶      G   vendor/symfony/config/Symfony/Component/Config/Definition/FloatNode.phpñ   "‚Xñ  må–+¶      F   vendor/symfony/config/Symfony/Component/Config/Definition/BaseNode.phpÿ!   "‚Xÿ!  H2ÆÛ¶      H   vendor/symfony/config/Symfony/Component/Config/Definition/ScalarNode.phpq   "‚Xq  X£“¶      G   vendor/symfony/config/Symfony/Component/Config/Definition/Processor.php'   "‚X'  Uú§¶      K   vendor/symfony/config/Symfony/Component/Config/Definition/NodeInterface.php‰   "‚X‰  fJŠ¶      I   vendor/symfony/config/Symfony/Component/Config/Definition/IntegerNode.phpk   "‚Xk  –­j¶      M   vendor/symfony/config/Symfony/Component/Config/Definition/ReferenceDumper.php}   "‚X}  sÜ¶      I   vendor/symfony/config/Symfony/Component/Config/Definition/BooleanNode.php«   "‚X«  î‰¶      T   vendor/symfony/config/Symfony/Component/Config/Definition/PrototypeNodeInterface.phpw   "‚Xw  ÿ€e¶      G   vendor/symfony/config/Symfony/Component/Config/Definition/ArrayNode.phpð+   "‚Xð+  •Â<¶      F   vendor/symfony/config/Symfony/Component/Config/Definition/EnumNode.php@   "‚X@  óžÎ=¶      ?   vendor/symfony/config/Symfony/Component/Config/phpunit.xml.disth   "‚Xh  èY‹¶      G   vendor/symfony/config/Symfony/Component/Config/FileLocatorInterface.phpl   "‚Xl  ‡C3k¶      M   vendor/symfony/config/Symfony/Component/Config/Resource/ResourceInterface.phpD   "‚XD  fKºE¶      M   vendor/symfony/config/Symfony/Component/Config/Resource/DirectoryResource.phpÑ
   "‚XÑ
  š#¶      H   vendor/symfony/config/Symfony/Component/Config/Resource/FileResource.php!   "‚X!   ÐT¶      <   vendor/symfony/config/Symfony/Component/Config/composer.json   "‚X  cHÖ¶      6   vendor/symfony/config/Symfony/Component/Config/LICENSE)   "‚X)  NmòQ¶      J   vendor/symfony/config/Symfony/Component/Config/Loader/DelegatingLoader.php8   "‚X8  ;v7%¶      H   vendor/symfony/config/Symfony/Component/Config/Loader/LoaderResolver.php¡   "‚X¡  rhq¶      I   vendor/symfony/config/Symfony/Component/Config/Loader/LoaderInterface.php9   "‚X9  ö’ý4¶      Q   vendor/symfony/config/Symfony/Component/Config/Loader/LoaderResolverInterface.phpÚ   "‚XÚ  €²­Â¶      @   vendor/symfony/config/Symfony/Component/Config/Loader/Loader.phpÏ   "‚XÏ  Ü=º¶      D   vendor/symfony/config/Symfony/Component/Config/Loader/FileLoader.php8   "‚X8  ¬ð(¶      >   vendor/symfony/config/Symfony/Component/Config/ConfigCache.php¦
   "‚X¦
  }K¤Ð¶      ;   vendor/symfony/config/Symfony/Component/Config/CHANGELOG.md¨   "‚X¨  �K‚K¶      8   vendor/symfony/config/Symfony/Component/Config/README.mdú   "‚Xú  }3V¶      >   vendor/symfony/config/Symfony/Component/Config/FileLocator.php    "‚X   I½Ñ¶      "   vendor/pdepend/pdepend/Vagrantfile	   "‚X	  )\¾H¶      3   vendor/pdepend/pdepend/src/conf/phar_bootstrap.stubX	   "‚XX	  •aý[¶      &   vendor/pdepend/pdepend/src/bin/pdepend   "‚X  055M¶      *   vendor/pdepend/pdepend/src/bin/pdepend.batƒ   "‚Xƒ  ›]hæ¶      *   vendor/pdepend/pdepend/src/bin/pdepend.php`
   "‚X`
  a1ÕÉ¶      B   vendor/pdepend/pdepend/src/main/resources/schema/configuration.xsdQ   "‚XQ  3Væ‰¶      6   vendor/pdepend/pdepend/src/main/resources/services.xml   "‚X  _†(T¶      G   vendor/pdepend/pdepend/src/main/php/PDepend/Input/ExcludePathFilter.php   "‚X  ü‘q¶      >   vendor/pdepend/pdepend/src/main/php/PDepend/Input/Iterator.phpé   "‚Xé  Ô¸Öv¶      E   vendor/pdepend/pdepend/src/main/php/PDepend/Input/CompositeFilter.php=   "‚X=  
Š#¶      E   vendor/pdepend/pdepend/src/main/php/PDepend/Input/ExtensionFilter.phpú   "‚Xú  Ôd·m¶      <   vendor/pdepend/pdepend/src/main/php/PDepend/Input/Filter.php9	   "‚X9	  íÿT¯¶      =   vendor/pdepend/pdepend/src/main/php/PDepend/Util/FileUtil.php   "‚X  qš4¶      J   vendor/pdepend/pdepend/src/main/php/PDepend/Util/ConfigurationInstance.php¬
   "‚X¬
  (¥)º¶      =   vendor/pdepend/pdepend/src/main/php/PDepend/Util/MathUtil.phpµ   "‚Xµ  ÔÚA¶      B   vendor/pdepend/pdepend/src/main/php/PDepend/Util/Configuration.php(   "‚X(  [hÑj¶      @   vendor/pdepend/pdepend/src/main/php/PDepend/Util/Workarounds.php(   "‚X(  ë~¶      =   vendor/pdepend/pdepend/src/main/php/PDepend/Util/Utf8Util.phpc
   "‚Xc
  k—¾f¶      A   vendor/pdepend/pdepend/src/main/php/PDepend/Util/ImageConvert.php!   "‚X!  JÅæ¶      >   vendor/pdepend/pdepend/src/main/php/PDepend/Util/IdBuilder.php¤   "‚X¤  ó¡×¶      F   vendor/pdepend/pdepend/src/main/php/PDepend/Util/Cache/CacheDriver.phpÎ   "‚XÎ  nxB-¶      G   vendor/pdepend/pdepend/src/main/php/PDepend/Util/Cache/CacheFactory.php¸   "‚X¸  b,_
¶      Y   vendor/pdepend/pdepend/src/main/php/PDepend/Util/Cache/Driver/File/FileCacheDirectory.phpü   "‚Xü  e®†¶      `   vendor/pdepend/pdepend/src/main/php/PDepend/Util/Cache/Driver/File/FileCacheGarbageCollector.php9   "‚X9  ã¾š¶      S   vendor/pdepend/pdepend/src/main/php/PDepend/Util/Cache/Driver/MemoryCacheDriver.php[   "‚X[  §û�¼¶      Q   vendor/pdepend/pdepend/src/main/php/PDepend/Util/Cache/Driver/FileCacheDriver.phpÚ$   "‚XÚ$  ³¤ÕL¶      9   vendor/pdepend/pdepend/src/main/php/PDepend/Util/Type.phpØ:   "‚XØ:  Æ`ŠÈ¶      D   vendor/pdepend/pdepend/src/main/php/PDepend/Util/Coverage/Report.phpB	   "‚XB	  í!åÓ¶      E   vendor/pdepend/pdepend/src/main/php/PDepend/Util/Coverage/Factory.php�   "‚X�  t:ƒ¶      J   vendor/pdepend/pdepend/src/main/php/PDepend/Util/Coverage/CloverReport.php   "‚X  Nà¹û¶      8   vendor/pdepend/pdepend/src/main/php/PDepend/Util/Log.phpÑ   "‚XÑ  ºÆ"w¶      =   vendor/pdepend/pdepend/src/main/php/PDepend/TextUI/Runner.phpÿ%   "‚Xÿ%  pýÊJ¶      >   vendor/pdepend/pdepend/src/main/php/PDepend/TextUI/Command.phpK   "‚XK  ?:Î×¶      D   vendor/pdepend/pdepend/src/main/php/PDepend/TextUI/ResultPrinter.php�   "‚X�  E‰ú¶      6   vendor/pdepend/pdepend/src/main/php/PDepend/Engine.php¶M   "‚X¶M  ”ë|¶      ;   vendor/pdepend/pdepend/src/main/php/PDepend/Application.php«   "‚X«  Ád%+¶      B   vendor/pdepend/pdepend/src/main/php/PDepend/Report/Jdepend/Xml.php¿,   "‚X¿,  ]þC*¶      D   vendor/pdepend/pdepend/src/main/php/PDepend/Report/Jdepend/Chart.phpŸ   "‚XŸ  »Ø>Ã¶      D   vendor/pdepend/pdepend/src/main/php/PDepend/Report/Jdepend/chart.svgv[   "‚Xv[  ò!®m¶      I   vendor/pdepend/pdepend/src/main/php/PDepend/Report/FileAwareGenerator.phpë   "‚Xë  ’ý)ê¶      I   vendor/pdepend/pdepend/src/main/php/PDepend/Report/CodeAwareGenerator.phpL	   "‚XL	  ÷«_0¶      G   vendor/pdepend/pdepend/src/main/php/PDepend/Report/Overview/pyramid.svg¸x   "‚X¸x  Ý`'¶      G   vendor/pdepend/pdepend/src/main/php/PDepend/Report/Overview/Pyramid.phpõ*   "‚Xõ*  þ(òL¶      K   vendor/pdepend/pdepend/src/main/php/PDepend/Report/NoLogOutputException.php
   "‚X
   H�ð¶      G   vendor/pdepend/pdepend/src/main/php/PDepend/Report/Dependencies/Xml.php *   "‚X *  9E¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Report/ReportGeneratorFactory.php‡   "‚X‡  û½6;¶      B   vendor/pdepend/pdepend/src/main/php/PDepend/Report/Summary/Xml.php%6   "‚X%6  fü:2¶      F   vendor/pdepend/pdepend/src/main/php/PDepend/Report/ReportGenerator.php_   "‚X_  Ý	Ð¶      D   vendor/pdepend/pdepend/src/main/php/PDepend/DbusUI/ResultPrinter.php   "‚X  {¦”M¶      T   vendor/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/ExtensionManager.phpV   "‚XV  Z2÷’¶      Q   vendor/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/Configuration.php$   "‚X$  QZ´Z¶      `   vendor/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/Compiler/ProcessListenerPass.phpö
   "‚Xö
  
Á>Æ¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/Extension.php•   "‚X•  ¯èóD¶      T   vendor/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/PdependExtension.php»   "‚X»  Òˆ-¶      ?   vendor/pdepend/pdepend/src/main/php/PDepend/ProcessListener.phpZ   "‚XZ  ’õÆ„¶      N   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPBuilder.phpR  "‚XR Îñs?¶      T   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserGeneric.php¡   "‚X¡  >ßQ¶      V   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion54.php¯!   "‚X¯!  ó2íõ¶      U   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/AbstractPHPParser.php?  "‚X? ñ £­¶      V   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion71.php‡   "‚X‡  Íg/ê¶      V   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion70.phpAA   "‚XAA  4ZPo¶      X   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPTokenizerInternal.phpx   "‚Xx  (º§Þ¶      _   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPTokenizerHelperVersion52.phpr   "‚Xr  aMzà¶      V   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion56.phpó2   "‚Xó2  äQ	¶      V   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion55.phpŒ   "‚XŒ  È=kH¶      V   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion53.php   "‚X  Ë±-ú¶      I   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Parser/SymbolTable.php*   "‚X*  
	8¶      S   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Parser/MissingValueException.phpH   "‚XH  ‚Z5H¶      S   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Parser/InvalidStateException.phpG   "‚XG  6Zr¶      H   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Parser/TokenStack.php{   "‚X{   (Á%¶      T   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Parser/NoActiveScopeException.php®   "‚X®  ƒÖ[¤¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Parser/ParserException.phpW   "‚XW  –‘ÛÍ¶      V   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Parser/UnexpectedTokenException.phpŸ
   "‚XŸ
  �Å²¶      U   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Parser/TokenStreamEndException.php5
   "‚X5
  j¡>¶      L   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Parser/TokenException.phpd   "‚Xd  „§•¸¶      F   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Builder/Builder.php2   "‚X2  øÀw�¶      b   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Builder/BuilderContext/GlobalBuilderContext.php   "‚X  ‚4þq¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Builder/BuilderContext.phpÆ   "‚XÆ  9ñò1¶      T   vendor/pdepend/pdepend/src/main/php/PDepend/Source/ASTVisitor/AbstractASTVisitor.php½6   "‚X½6  ð
2y¶      L   vendor/pdepend/pdepend/src/main/php/PDepend/Source/ASTVisitor/ASTVisitor.phpq   "‚Xq  ËüH¶      Z   vendor/pdepend/pdepend/src/main/php/PDepend/Source/ASTVisitor/AbstractASTVisitListener.phpµ   "‚Xµ  ËþÞ¶      R   vendor/pdepend/pdepend/src/main/php/PDepend/Source/ASTVisitor/ASTVisitListener.phpí   "‚Xí  ¯ªP¶      L   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTEvalExpression.phph
   "‚Xh
  „ªã¶      H   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTInvocation.phpd   "‚Xd  BY'l¶      J   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTType.php¯6   "‚X¯6  76äQ¶      L   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitReference.phpÃ   "‚XÃ  ‹²W¶      G   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTypeArray.php%   "‚X%  ÝÀc¶      O   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitUseStatement.phpa   "‚Xa  ,¨×¶      G   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTNamespace.phpm#   "‚Xm#  !)˜Ü¶      L   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTExitExpression.phph
   "‚Xh
  ¬gf›¶      C   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClass.php™   "‚X™  ¦°i¬¶      P   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCompoundExpression.phpÚ
   "‚XÚ
  &ÚÅÝ¶      G   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArguments.php÷
   "‚X÷
  {"¶      N   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFinallyStatement.php
   "‚X
  •?Ü¶      N   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTForeachStatement.phpV
   "‚XV
  _yœ¶      F   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFunction.php   "‚X  >¥zI¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPrintExpression.phpx
   "‚Xx
  àX¼Ð¶      R   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTAssignmentExpression.php
   "‚X
  gZÃ5¶      R   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTInstanceOfExpression.phpd
   "‚Xd
   yâ¶      G   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTParameter.php~+   "‚X~+  "&0Ì¶      D   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTMethod.phpr   "‚Xr  _µÝk¶      P   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTVariableDeclarator.php   "‚X  ’ù%¶      S   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTStringIndexExpression.php�
   "‚X�
  2|[©¶      R   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArrayIndexExpression.phpí
   "‚Xí
  ¤É¶      F   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCallable.phpt   "‚Xt  åß} ¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCloneExpression.phpj
   "‚Xj
   Ãˆ˜¶      Y   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList/ArtifactFilter.php�	   "‚X�	  ú©É_¶      `   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList/PackageArtifactFilter.php	   "‚X	  ü8YÙ¶      ]   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList/NullArtifactFilter.phpÂ	   "‚XÂ	  lÅ>4¶      c   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList/CollectionArtifactFilter.phpº   "‚Xº  ÈË\�¶      J   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList.php•   "‚X•  Ì�ä'¶      P   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConstantDefinition.phpÜ
   "‚XÜ
  Ìàô?¶      R   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitAdaptationAlias.phpž   "‚Xž  <:^�¶      L   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTBreakStatement.php   "‚X  þ5Nœ¶      R   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLogicalAndExpression.phpk
   "‚Xk
  òœ³¬¶      G   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTStatement.phpI
   "‚XI
  ãvZ<¶      K   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTSelfReference.phpõ   "‚Xõ  ï«Œ¶      C   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTScope.phpI
   "‚XI
  „,‡w¶      K   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTEchoStatement.phpd
   "‚Xd
  e=�¶      F   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConstant.php

   "‚X

  ½¶¼r¶      _   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassOrInterfaceReferenceIterator.php‰   "‚X‰   xiœ¶      k   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassOrInterfaceRecursiveInheritanceException.phpˆ
   "‚Xˆ
  éýè°¶      G   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTInterface.php^   "‚X^  þœ÷ÿ¶      E   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClosure.phpp   "‚Xp  £®Ï¶      D   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTString.phpÏ   "‚XÏ  �§jû¶      T   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPreIncrementExpression.phpH
   "‚XH
  ¯«0Ô¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPropertyPostfix.phpö
   "‚Xö
  ˜í‹Ö¶      N   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTCallable.php9   "‚X9  	`,÷¶      E   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTForInit.phpÁ
   "‚XÁ
   Ì4 ¶      G   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTForUpdate.phpU   "‚XU  ¥œ¤p¶      L   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTYieldStatement.phph   "‚Xh  šBK¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCompilationUnit.phpÀ&   "‚XÀ&  Yt.>¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTElseIfStatement.php½   "‚X½  ‘¥kÂ¶      L   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTThrowStatement.phpR
   "‚XR
  Å4ƒ¶      H   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTScalarType.php.   "‚X.  4–`¶      B   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTNode.phpÚ   "‚XÚ  ÏŸ2¤¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTSwitchStatement.php3
   "‚X3
  b‰sn¶      N   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFieldDeclaration.phpÌ   "‚XÌ  ¸79<¶      P   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConstantDeclarator.phpc   "‚Xc  Z ¶      Q   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTBooleanOrExpression.php-
   "‚X-
  WËh¶      ^   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCompilationUnitNotFoundException.phpÐ	   "‚XÐ	  “³²C¶      @   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/State.php¤   "‚X¤  µƒ:U¶      F   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTVariable.php£   "‚X£  Õ…é¶      R   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLogicalXorExpression.phpk
   "‚Xk
  Þf¶      O   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTContinueStatement.php;   "‚X;  ©2Ùæ¶      L   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTListExpression.phpS
   "‚XS
  ¦fÖ¶      W   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitAdaptationPrecedence.phpI
   "‚XI
  §É<¶      L   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCastExpression.php   "‚X  jPÉ¾¶      J   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArrayElement.php”   "‚X”  pCÃ¶      L   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTAnonymousClass.phpú!   "‚Xú!  é5~¶      I   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTSwitchLabel.phpØ   "‚XØ  ä³pO¶      Q   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLogicalOrExpression.phph
   "‚Xh
  Ú/l/¶      C   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTValue.phpG   "‚XG  ºn·¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTUnaryExpression.phpÛ
   "‚XÛ
  R×Y[¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTReturnStatement.php~   "‚X~  žl»è¶      V   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTClassOrInterface.phpï+   "‚Xï+  „êdw¶      J   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTForStatement.phpJ
   "‚XJ
  ,�¯Ä¶      T   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPreDecrementExpression.phpH
   "‚XH
  V¹Zç¶      W   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTStaticVariableDeclaration.php„   "‚X„  [oÀ‚¶      R   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTBooleanAndExpression.php0
   "‚X0
  KÄB¶      O   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIncludeExpression.phpõ   "‚Xõ  †,~Æ¶      O   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPostfixExpression.php3
   "‚X3
  ¶£¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIssetExpression.php*
   "‚X*
  Ó„d¶      H   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIdentifier.phpx
   "‚Xx
  BÇâ¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIndexExpression.phpf   "‚Xf  T›¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTStaticReference.phpÇ   "‚XÇ  >‹Jê¶      C   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTrait.php   "‚X  WUÿž¶      K   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTGotoStatement.phpO
   "‚XO
  i+R<¶      J   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTNode.phpÀ0   "‚XÀ0  ¹kÓ¶      K   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTMethodPostfix.phpá
   "‚Xá
  ¸`VK¶      L   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCatchStatement.php0
   "‚X0
  $67Î¶      L   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassReference.phpß   "‚Xß  Ü^¡1¶      N   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTDeclareStatement.php¥   "‚X¥  &•�u¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConstantPostfix.phpX
   "‚XX
  ;0ž°¶      J   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTypeCallable.phpø
   "‚Xø
  1Ì¶      O   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTRequireExpression.phpõ   "‚Xõ  2q
)¶      R   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTShiftRightExpression.phpG   "‚XG  ðãq¶      N   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTArtifact.phpÓ   "‚XÓ  &ÙHš¶      L   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTWhileStatement.phpK
   "‚XK
  #%AT¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFormalParameter.php   "‚X  JÂã¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitAdaptation.php,
   "‚X,
  ýW¶      N   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFormalParameters.php÷   "‚X÷  £Ñ¶      F   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifact.phpB
   "‚XB
  ¹á¶      L   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTUnsetStatement.phpR
   "‚XR
  „½”¶      N   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTVariableVariable.phpé
   "‚Xé
  G—Î€¶      L   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTScopeStatement.phpU
   "‚XU
  Ø¥FS¶      N   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCompoundVariable.php¡
   "‚X¡
  í¾g¶      N   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTDoWhileStatement.phpm
   "‚Xm
  6aa.¶      I   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIfStatement.phpL   "‚XL  üŽ£³¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFunctionPostfix.phpÈ
   "‚XÈ
  cd0¶      R   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTAllocationExpression.phpá
   "‚Xá
  BwØª¶      [   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitMethodCollisionException.phpÿ   "‚Xÿ  ð€V¶      H   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTExpression.phpI
   "‚XI
  JµÔ¶      C   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArray.phpv   "‚Xv  tÔ4¶      F   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTProperty.phpY'   "‚XY'  ¹Û·¶      E   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTComment.phpç	   "‚Xç	  ß§©†¶      J   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTryStatement.phpL
   "‚XL
  Þyñê¶      L   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLabelStatement.phpR
   "‚XR
  hèf¶      E   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTHeredoc.php­   "‚X­  Wfd¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTParentReference.phpµ   "‚Xµ  Áìëý¶      B   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTType.php”   "‚X”  ø½'”¶      E   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLiteral.php=
   "‚X=
  Ðhz¶      Q   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTShiftLeftExpression.phpD   "‚XD  =Ü¢¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTGlobalStatement.phpU
   "‚XU
  ö«kA¶      M   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassFqnPostfix.phpê
   "‚Xê
  Þj\ë¶      W   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassOrInterfaceReference.php   "‚X  ÿ÷b|¶      S   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConditionalExpression.php“
   "‚X“
  _¬�Î¶      Q   vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTMemberPrimaryPrefix.phpx   "‚Xx  po³¶      F   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Tokenizer/Token.php   "‚X  ¥Î©2¶      G   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Tokenizer/Tokens.phpª:   "‚Xª:  ¤4PX¶      J   vendor/pdepend/pdepend/src/main/php/PDepend/Source/Tokenizer/Tokenizer.phph   "‚Xh  »n¿¶      L   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerProjectAware.phpø	   "‚Xø	  É$¾¶      Q   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CouplingAnalyzer.phpÖ2   "‚XÖ2  ã°—h¶      e   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/InheritanceStrategy.php   "‚X  ðY/›¶      c   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/CodeRankStrategyI.php	   "‚X	  
 ¶      b   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/PropertyStrategy.phpÅ   "‚XÅ  ýé�õ¶      a   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/StrategyFactory.php   "‚X  ‡½Ÿ!¶      `   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/MethodStrategy.php˜   "‚X˜  ¥•,|¶      R   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CrapIndexAnalyzer.phpê   "‚Xê  ÷º*Ä¶      X   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/ClassDependencyAnalyzer.phpÓ)   "‚XÓ)  Ÿ|ù@¶      X   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/NPathComplexityAnalyzer.php9D   "‚X9D  G’…X¶      Q   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/HalsteadAnalyzer.php“;   "‚X“;  'ªx¶      Q   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CohesionAnalyzer.phpæ   "‚Xæ  !x�_¶      T   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/InheritanceAnalyzer.php*   "‚X*  <„šR¶      ]   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CyclomaticComplexityAnalyzer.phpg6   "‚Xg6  4èNí¶      ]   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/MaintainabilityIndexAnalyzer.phpæ   "‚Xæ  º©ÅM¶      R   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/NodeCountAnalyzer.php8#   "‚X8#   Añ¢¶      S   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/ClassLevelAnalyzer.php:4   "‚X:4  æÐæ¦¶      P   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/NodeLocAnalyzer.php>:   "‚X>:  ž“4H¶      R   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/HierarchyAnalyzer.php™#   "‚X™#  :P¾¶      Q   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer.php†   "‚X†  8¬Š¶      S   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/DependencyAnalyzer.php´9   "‚X´9  ð;):¶      J   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerCacheAware.phpê	   "‚Xê	  ëF»¸¶      H   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerIterator.phpZ
   "‚XZ
  RåªF¶      @   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer.php   "‚X  ‡AŸ™¶      G   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerFactory.phpÖ   "‚XÖ  ©S¶      H   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AbstractAnalyzer.php|   "‚X|  ÆËZ¶      H   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerListener.phpª
   "‚Xª
  ÌÕEŒ¶      I   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AggregateAnalyzer.php
   "‚X
  Ð‡v)¶      I   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerNodeAware.php˜
   "‚X˜
  Äu­¶      O   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AbstractCachingAnalyzer.phpõ   "‚Xõ  æ|ÜF¶      K   vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerFilterAware.phpÿ   "‚Xÿ  ï•—¶          vendor/pdepend/pdepend/CHANGELOGûW   "‚XûW  zÐ¤z¶      $   vendor/pdepend/pdepend/composer.json+   "‚X+  Ë+N¶         vendor/pdepend/pdepend/LICENSEú   "‚Xú  8	qé¶      )   vendor/pdepend/pdepend/scripts/compare.sh    "‚X   d©ÄQ¶      /   vendor/pdepend/pdepend/scripts/php-keywords.phpœ   "‚Xœ  2çmh¶      1   vendor/pdepend/pdepend/scripts/update-version.phpí   "‚Xí  Ž�Å‚¶      '   vendor/pdepend/pdepend/build.propertiesÁ   "‚XÁ  m€ß3¶         vendor/autoload.php²    "‚X²   œQõ•¶      <?xml version="1.0"?>

<ruleset name="Clean Code Rules"
         xmlns="http://pmd.sf.net/ruleset/1.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
         xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">

    <description>
The Clean Code ruleset contains rules that enforce a clean code base. This includes rules from SOLID and object calisthenics.
    </description>

    <rule name="BooleanArgumentFlag"
          since="1.4.0"
          message="The method {0} has a boolean flag argument {1}, which is a certain sign of a Single Responsibility Principle violation."
          class="PHPMD\Rule\CleanCode\BooleanArgumentFlag"
          externalInfoUrl="http://phpmd.org/rules/cleancode.html#booleanargumentflag">
        <description>
            <![CDATA[
A boolean flag argument is a reliable indicator for a violation of
the Single Responsibility Principle (SRP). You can fix this problem
by extracting the logic in the boolean flag into its own class
or method.
            ]]>
        </description>
        <priority>1</priority>
        <properties />
        <example>
            <![CDATA[
class Foo {
    public function bar($flag = true) {
    }
}
            ]]>
        </example>
    </rule>

    <rule name="ElseExpression"
          since="1.4.0"
          message="The method {0} uses an else expression. Else is never necessary and you can simplify the code to work without else."
          class="PHPMD\Rule\CleanCode\ElseExpression"
          externalInfoUrl="http://phpmd.org/rules/cleancode.html#elseexpression">
        <description>
            <![CDATA[
An if expression with an else branch is never necessary. You can rewrite the
conditions in a way that the else is not necessary and the code becomes simpler
to read.  To achieve this use early return statements. To achieve this you may
need to split the code it several smaller methods. For very simple assignments
you could also use the ternary operations.
            ]]>
        </description>
        <priority>1</priority>
        <properties></properties>
        <example>
            <![CDATA[
class Foo
{
    public function bar($flag)
    {
        if ($flag) {
            // one branch
        } else {
            // another branch
        }
    }
}
            ]]>
        </example>
    </rule>

    <rule name="StaticAccess"
          since="1.4.0"
          message="Avoid using static access to class '{0}' in method '{1}'."
          class="PHPMD\Rule\CleanCode\StaticAccess"
          externalInfoUrl="http://phpmd.org/rules/cleancode.html#staticaccess">
        <description>
            <![CDATA[
Static access causes unexchangeable dependencies to other classes and leads to hard to test code. Avoid
using static access at all costs and instead inject dependencies through the constructor. The only
case when static access is acceptable is when used for factory methods.
            ]]>
        </description>
        <priority>1</priority>
        <properties>
            <property name="exceptions" description="Comma-separated class name list of exceptions" value=""/>
        </properties>
        <example>
            <![CDATA[
class Foo
{
    public function bar()
    {
        Bar::baz();
    }
}
            ]]>
        </example>
    </rule>
</ruleset>
<?xml version="1.0"?>

<ruleset name="Controversial Rules"
         xmlns="http://pmd.sf.net/ruleset/1.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
         xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">

    <description>
This ruleset contains a collection of controversial rules.
    </description>

    <rule name="Superglobals"
          since="0.2"
          message = "{0} accesses the super-global variable {1}."
          class="PHPMD\Rule\Controversial\Superglobals"
          externalInfoUrl="#">
        <description>
            <![CDATA[
Accessing a super-global variable directly is considered a bad practice.
These variables should be encapsulated in objects that are provided by a framework, for instance.
            ]]>
        </description>
        <priority>1</priority>
        <properties />
        <example>
            <![CDATA[
class Foo {
    public function bar() {
        $name = $_POST['foo'];
    }
}
            ]]>
        </example>
    </rule>

    <rule name="CamelCaseClassName"
          since="0.2"
          message = "The class {0} is not named in CamelCase."
          class="PHPMD\Rule\Controversial\CamelCaseClassName"
          externalInfoUrl="#">
        <description>
            <![CDATA[
It is considered best practice to use the CamelCase notation to name classes.
            ]]>
        </description>
        <priority>1</priority>
        <properties />
        <example>
            <![CDATA[
class class_name {
}
            ]]>
        </example>
    </rule>

    <rule name="CamelCasePropertyName"
          since="0.2"
          message = "The property {0} is not named in camelCase."
          class="PHPMD\Rule\Controversial\CamelCasePropertyName"
          externalInfoUrl="#">
        <description>
            <![CDATA[
It is considered best practice to use the camelCase notation to name attributes.
            ]]>
        </description>
        <priority>1</priority>
        <properties>
            <property name="allow-underscore"
                      description="Allow an optional, single underscore at the beginning."
                      value="false" />
            <property name="allow-underscore-test"
                      description="Is it allowed to have underscores in test method names."
                      value="false" />
        </properties>
        <example>
            <![CDATA[
class ClassName {
    protected $property_name;
}
            ]]>
        </example>
    </rule>

    <rule name="CamelCaseMethodName"
          since="0.2"
          message = "The method {0} is not named in camelCase."
          class="PHPMD\Rule\Controversial\CamelCaseMethodName"
          externalInfoUrl="#">
        <description>
            <![CDATA[
It is considered best practice to use the camelCase notation to name methods.
            ]]>
        </description>
        <priority>1</priority>
        <properties>
            <property name="allow-underscore"
                      description="Allow an optional, single underscore at the beginning."
                      value="false" />
            <property name="allow-underscore-test"
                      description="Is it allowed to have underscores in test method names."
                      value="false" />
        </properties>
        <example>
            <![CDATA[
class ClassName {
    public function get_name() {
    }
}
            ]]>
        </example>
    </rule>

    <rule name="CamelCaseParameterName"
          since="0.2"
          message = "The parameter {0} is not named in camelCase."
          class="PHPMD\Rule\Controversial\CamelCaseParameterName"
          externalInfoUrl="#">
        <description>
            <![CDATA[
It is considered best practice to use the camelCase notation to name parameters.
            ]]>
        </description>
        <priority>1</priority>
        <properties />
        <example>
            <![CDATA[
class ClassName {
    public function doSomething($user_name) {
    }
}
            ]]>
        </example>
    </rule>

    <rule name="CamelCaseVariableName"
          since="0.2"
          message = "The variable {0} is not named in camelCase."
          class="PHPMD\Rule\Controversial\CamelCaseVariableName"
          externalInfoUrl="#">
        <description>
            <![CDATA[
It is considered best practice to use the camelCase notation to name variables.
            ]]>
        </description>
        <priority>1</priority>
        <properties />
        <example>
            <![CDATA[
class ClassName {
    public function doSomething() {
        $data_module = new DataModule();
    }
}
            ]]>
        </example>
    </rule>
</ruleset>
<?xml version="1.0"?>

<ruleset name="Design Rules"
         xmlns="http://pmd.sf.net/ruleset/1.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
         xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">

    <description>
The Design Ruleset contains a collection of rules that find software design related problems.
    </description>

    <rule name="ExitExpression"
          since="0.2"
          message = "The {0} {1}() contains an exit expression."
          class="PHPMD\Rule\Design\ExitExpression"
          externalInfoUrl="http://phpmd.org/rules/design.html#exitexpression">
        <description>
            <![CDATA[
An exit-expression within regular code is untestable and therefore it should
be avoided. Consider to move the exit-expression into some kind of startup
script where an error/exception code is returned to the calling environment.
            ]]>
        </description>
        <priority>1</priority>
        <properties />
        <example>
            <![CDATA[
class Foo {
    public function bar($param)  {
        if ($param === 42) {
            exit(23);
        }
    }
}
            ]]>
        </example>
    </rule>

    <rule name="EvalExpression"
          since="0.2"
          message = "The {0} {1}() contains an eval expression."
          class="PHPMD\Rule\Design\EvalExpression"
          externalInfoUrl="http://phpmd.org/rules/design.html#evalexpression">
        <description>
            <![CDATA[
An eval-expression is untestable, a security risk and bad practice. Therefore
it should be avoided. Consider to replace the eval-expression with regular
code.
            ]]>
        </description>
        <priority>1</priority>
        <properties />
        <example>
            <![CDATA[
class Foo {
    public function bar($param)  {
        if ($param === 42) {
            eval('$param = 23;');
        }
    }
}
            ]]>
        </example>
    </rule>

    <rule name="GotoStatement"
          since="1.1.0"
          message="The {0} {1}() utilizes a goto statement."
          class="PHPMD\Rule\Design\GotoStatement"
          externalInfoUrl="http://phpmd.org/rules/design.html#gotostatement">
        <description>
            <![CDATA[
Goto makes code harder to read and it is nearly impossible to understand the
control flow of an application that uses this language construct. Therefore it
should be avoided. Consider to replace Goto with regular control structures and
separate methods/function, which are easier to read.
            ]]>
        </description>
        <priority>1</priority>
        <properties />
        <example>
            <![CDATA[
class Foo {
    public function bar($param)  {
        A:
        if ($param === 42) {
            goto X;
        }
        Y:
        if (time() % 42 === 23) {
            goto Z;
        }
        X:
        if (time() % 23 === 42) {
            goto Y;
        }
        Z:
        return 42;
    }
}
            ]]>
        </example>
    </rule>

    <rule name="NumberOfChildren"
          since="0.2"
          message = "The {0} {1} has {2} children. Consider to rebalance this class hierarchy to keep number of children under {3}."
          class="PHPMD\Rule\Design\NumberOfChildren"
          externalInfoUrl="http://phpmd.org/rules/design.html#numberofchildren">
        <description>
            <![CDATA[
A class with an excessive number of children is an indicator for an unbalanced
class hierarchy. You should consider to refactor this class hierarchy.
            ]]>
        </description>
        <priority>2</priority>
        <properties>
            <property name="minimum" value="15" description="Maximum number of acceptable child classes." />
        </properties>
        <example />
    </rule>

    <rule name="DepthOfInheritance"
          since="0.2"
          message = "The {0} {1} has {2} parents. Consider to reduce the depth of this class hierarchy to under {3}."
          class="PHPMD\Rule\Design\DepthOfInheritance"
          externalInfoUrl="http://phpmd.org/rules/design.html#depthofinheritance">
        <description>
            <![CDATA[
A class with many parents is an indicator for an unbalanced and wrong class
hierarchy. You should consider to refactor this class hierarchy.
            ]]>
        </description>
        <priority>2</priority>
        <properties>
            <property name="minimum" value="6" description="Maximum number of acceptable parent classes." />
        </properties>
        <example />
    </rule>

    <rule name="CouplingBetweenObjects"
          since="1.1.0"
          message="The class {0} has a coupling between objects value of {1}. Consider to reduce the number of dependencies under {2}."
          class="PHPMD\Rule\Design\CouplingBetweenObjects"
          externalInfoUrl="http://phpmd.org/rules/design.html#couplingbetweenobjects">
        <description>
            <![CDATA[
A class with too many dependencies has negative impacts on several quality
aspects of a class. This includes quality criteria like stability,
maintainability and understandability
            ]]>
        </description>
        <priority>2</priority>
        <properties>
            <property name="minimum" value="13" description="Maximum number of acceptable dependencies." />
        </properties>
        <example>
            <![CDATA[
class Foo {
    /**
     * @var \foo\bar\X
     */
    private $x = null;

    /**
     * @var \foo\bar\Y
     */
    private $y = null;

    /**
     * @var \foo\bar\Z
     */
    private $z = null;

    public function setFoo(\Foo $foo) {}
    public function setBar(\Bar $bar) {}
    public function setBaz(\Baz $baz) {}

    /**
     * @return \SplObjectStorage
     * @throws \OutOfRangeException
     * @throws \InvalidArgumentException
     * @throws \ErrorException
     */
    public function process(\Iterator $it) {}

    // ...
}
            ]]>
        </example>
    </rule>

    <rule name="DevelopmentCodeFragment"
          since="2.3.0"
          message="The {0} {1}() calls the typical debug function {2}() which is mostly only used during development."
          class="PHPMD\Rule\Design\DevelopmentCodeFragment"
          externalInfoUrl="http://phpmd.org/rules/design.html#developmentcodefragment">
        <description>
            <![CDATA[
Functions like var_dump(), print_r() etc. are normally only used during development
and therefore such calls in production code are a good indicator that they were
just forgotten.
            ]]>
        </description>
        <priority>2</priority>
        <properties>
            <property name="unwanted-functions" value="var_dump,print_r,debug_zval_dump,debug_print_backtrace" description="Comma separated list of suspect function images." />
        </properties>
        <example>
            <![CDATA[
class SuspectCode {

    public function doSomething(array $items)
    {
        foreach ($items as $i => $item) {
            // â€¦

            if ('qafoo' == $item) var_dump($i);

            // â€¦
        }
    }
}
            ]]>
        </example>
    </rule>
</ruleset>
<?xml version="1.0"?>

<ruleset name="Unused Code Rules"
         xmlns="http://pmd.sf.net/ruleset/1.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
         xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
    <description>
The Unused Code Ruleset contains a collection of rules that find unused code.
    </description>

    <rule name="UnusedPrivateField"
          since="0.2"
          message="Avoid unused private fields such as '{0}'."
          class="PHPMD\Rule\UnusedPrivateField"
          externalInfoUrl="http://phpmd.org/rules/unusedcode.html#unusedprivatefield">
        <description>
Detects when a private field is declared and/or assigned a value, but not used.
        </description>
        <priority>3</priority>
        <example>
<![CDATA[
class Something
{
    private static $FOO = 2; // Unused
    private $i = 5; // Unused
    private $j = 6;
    public function addOne()
    {
        return $this->j++;
    }
}
]]>
        </example>
    </rule>

    <rule name="UnusedLocalVariable"
          since="0.2"
          message="Avoid unused local variables such as '{0}'."
          class="PHPMD\Rule\UnusedLocalVariable"
          externalInfoUrl="http://phpmd.org/rules/unusedcode.html#unusedlocalvariable">
        <description>
Detects when a local variable is declared and/or assigned, but not used.
        </description>
        <priority>3</priority>
        <properties>
            <property
                    name="allow-unused-foreach-variables"
                    description="Allow unused variables in foreach language constructs."
                    value="false" />
        </properties>
        <example>
<![CDATA[
class Foo {
    public function doSomething()
    {
        $i = 5; // Unused
    }
}
]]>
        </example>
    </rule>

    <rule name="UnusedPrivateMethod"
          since="0.2"
          message="Avoid unused private methods such as '{0}'."
          class="PHPMD\Rule\UnusedPrivateMethod"
          externalInfoUrl="http://phpmd.org/rules/unusedcode.html#unusedprivatemethod">
        <description>
Unused Private Method detects when a private method is declared but is unused.
        </description>
        <priority>3</priority>
        <example>
<![CDATA[
class Something
{
    private function foo() {} // unused
}
]]>
        </example>
    </rule>

    <rule name="UnusedFormalParameter"
          since="0.2"
          message="Avoid unused parameters such as '{0}'."
          class="PHPMD\Rule\UnusedFormalParameter"
          externalInfoUrl="http://phpmd.org/rules/unusedcode.html#unusedformalparameter">
        <description>
Avoid passing parameters to methods or constructors and then not using those parameters.
        </description>
        <priority>3</priority>
        <example>
<![CDATA[
class Foo
{
    private function bar($howdy)
    {
        // $howdy is not used
    }
}
]]>
        </example>
    </rule>

</ruleset>
<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="Naming Rules"
         xmlns="http://pmd.sf.net/ruleset/1.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
         xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">
    <description>
The Naming Ruleset contains a collection of rules about names - too long, too short, and so forth.
    </description>

    <rule name="ShortVariable"
          since="0.2"
          message="Avoid variables with short names like {0}. Configured minimum length is {1}."
          class="PHPMD\Rule\Naming\ShortVariable"
          externalInfoUrl="http://phpmd.org/rules/naming.html#shortvariable">
        <description>
Detects when a field, local, or parameter has a very short name.
        </description>
        <priority>3</priority>
        <properties>
            <property name="minimum" description="Minimum length for a variable, property or parameter name" value="3"/>
            <property name="exceptions" description="Comma-separated list of exceptions" value=""/>
        </properties>
        <example>
            <![CDATA[
class Something {
    private $q = 15; // VIOLATION - Field
    public static function main( array $as ) { // VIOLATION - Formal
        $r = 20 + $this->q; // VIOLATION - Local
        for (int $i = 0; $i < 10; $i++) { // Not a Violation (inside FOR)
            $r += $this->q;
        }
    }
}
            ]]>
        </example>
    </rule>

    <rule name="LongVariable"
          since="0.2"
          message="Avoid excessively long variable names like {0}. Keep variable name length under {1}."
          class="PHPMD\Rule\Naming\LongVariable"
          externalInfoUrl="http://phpmd.org/rules/naming.html#longvariable">
        <description>
Detects when a field, formal or local variable is declared with a long name.
        </description>
        <priority>3</priority>
        <properties>
            <property name="maximum" description="The variable length reporting threshold" value="20"/>
        </properties>
        <example>
            <![CDATA[
class Something {
    protected $reallyLongIntName = -3; // VIOLATION - Field
    public static function main( array $argumentsList[] ) { // VIOLATION - Formal
        $otherReallyLongName = -5; // VIOLATION - Local
        for ($interestingIntIndex = 0; // VIOLATION - For
             $interestingIntIndex < 10;
             $interestingIntIndex++ ) {
        }
    }
}
]]>
        </example>
    </rule>

    <rule name="ShortMethodName"
          since="0.2"
          message="Avoid using short method names like {0}::{1}(). The configured minimum method name length is {2}."
          class="PHPMD\Rule\Naming\ShortMethodName"
          externalInfoUrl="http://phpmd.org/rules/naming.html#shortmethodname">
        <description>
Detects when very short method names are used.
        </description>
        <priority>3</priority>
        <properties>
            <property name="minimum" description="Minimum length for a method or function name" value="3"/>
            <property name="exceptions" description="Comma-separated list of exceptions" value=""/>
        </properties>
        <example>
            <![CDATA[
class ShortMethod {
    public function a( $index ) { // Violation
    }
}
            ]]>
        </example>
    </rule>

    <rule name="ConstructorWithNameAsEnclosingClass"
          since="0.2"
          message="Classes should not have a constructor method with the same name as the class"
          class="PHPMD\Rule\Naming\ConstructorWithNameAsEnclosingClass"
          externalInfoUrl="http://phpmd.org/rules/naming.html#constructorwithnameasenclosingclass">
        <description>
A constructor method should not have the same name as the enclosing class, consider
to use the PHP 5 __construct method.
        </description>
        <priority>3</priority>
        <example>
            <![CDATA[
class MyClass {
     // this is bad because it is PHP 4 style
    public function MyClass() {}
    // this is good because it is a PHP 5 constructor
    public function __construct() {}
}
    ]]>
        </example>
    </rule>

    <rule name="ConstantNamingConventions"
          since="0.2"
          message="Constant {0} should be defined in uppercase"
          class="PHPMD\Rule\Naming\ConstantNamingConventions"
          externalInfoUrl="http://phpmd.org/rules/naming.html#constantnamingconventions">
        <description>
Class/Interface constant names should always be defined in uppercase.
        </description>
        <priority>4</priority>
        <properties />
        <example>
            <![CDATA[
class Foo {
    const MY_NUM = 0; // ok
    const myTest = ""; // fail
}
            ]]>
        </example>
    </rule>

    <rule name="BooleanGetMethodName"
          since="0.2"
          message="The '{0}()' method which returns a boolean should be named 'is...()' or 'has...()'"
          class="PHPMD\Rule\Naming\BooleanGetMethodName"
          externalInfoUrl="http://phpmd.org/rules/naming.html#booleangetmethodname">
        <description>
Looks for methods named 'getX()' with 'boolean' as the return type. The convention
is to name these methods 'isX()' or 'hasX()'.
        </description>
        <priority>4</priority>
        <properties>
            <property name="checkParameterizedMethods" value="false" description="Applies only to methods without parameter when set to true" />
        </properties>
        <example>
            <![CDATA[
class Foo {
    /**
     * @return boolean
     */
    public function getFoo() {} // bad
    /**
     * @return bool
     */
    public function isFoo(); // ok
    /**
     * @return boolean
     */
    public function getFoo($bar); // ok, unless checkParameterizedMethods=true
}
            ]]>
        </example>
    </rule>

<!--

    <rule name="VariableNamingConventions"
    since="1.2"
    message="{0} variable {1} should begin with {2}"
    class="net.sourceforge.pmd.rules.VariableNamingConventions"
          externalInfoUrl="http://pmd.sourceforge.net/rules/naming.html#VariableNamingConventions">
        <description>
A variable naming conventions rule - customize this to your liking.  Currently, it
 checks for final variables that should be fully capitalized and non-final variables
 that should not include underscores.
        </description>
        <priority>1</priority>
        <properties>
            <property name="staticPrefix" description="A prefix for static variables" value=""/>
            <property name="staticSuffix" description="A suffix for static variables" value=""/>
            <property name="memberPrefix" description="A prefix for member variables" value=""/>
            <property name="memberSuffix" description="A suffix for member variables" value=""/>
        </properties>
        <example>
<![CDATA[
public class Foo {
 public static final int MY_NUM = 0;
 public String myTest = "";
 DataModule dmTest = new DataModule();
}
]]>
        </example>
    </rule>

    <rule name="MethodNamingConventions"
    			  since="1.2"
              message="Method name does not begin with a lower case character."
              class="net.sourceforge.pmd.rules.MethodNamingConventions"
          externalInfoUrl="http://pmd.sourceforge.net/rules/naming.html#MethodNamingConventions">
          <description>
Method names should always begin with a lower case character, and should not contain underscores.
          </description>
          <priority>1</priority>
          <example>
<![CDATA[
public class Foo {
 public void fooStuff() {
 }
}
]]>
          </example>
        </rule>

    <rule name="ClassNamingConventions"
    		 since="1.2"
          message="Class names should begin with an uppercase character"
          class="net.sourceforge.pmd.rules.ClassNamingConventions"
          externalInfoUrl="http://pmd.sourceforge.net/rules/naming.html#ClassNamingConventions">
      <description>
Class names should always begin with an upper case character.
      </description>
      <priority>1</priority>
      <example>
<![CDATA[
public class Foo {}
]]>
      </example>
    </rule>

    <rule name="AbstractNaming"
    		 since="1.4"
          message="Abstract classes should be named 'AbstractXXX'"
          class="net.sourceforge.pmd.rules.XPathRule"
          externalInfoUrl="http://pmd.sourceforge.net/rules/naming.html#AbstractNaming">
       <description>
Abstract classes should be named 'AbstractXXX'.
       </description>
        <priority>3</priority>
        <properties>
            <property name="xpath">
                <value>
                    <![CDATA[
//ClassOrInterfaceDeclaration
 [@Abstract='true' and @Interface='false']
 [not (starts-with(@Image,'Abstract'))]
                    ]]>
                </value>
            </property>
        </properties>
       <example>
<![CDATA[
public abstract class Foo { // should be AbstractFoo
}
]]>
       </example>
    </rule>

    <rule name="AvoidFieldNameMatchingTypeName"
    		 since="3.0"
          message="It is somewhat confusing to have a field name matching the declaring class name"
          class="net.sourceforge.pmd.rules.AvoidFieldNameMatchingTypeName"
          externalInfoUrl="http://pmd.sourceforge.net/rules/naming.html#AvoidFieldNameMatchingTypeName">
      <description>
It is somewhat confusing to have a field name matching the declaring class name.
This probably means that type and or field names could be more precise.
      </description>
        <priority>3</priority>
      <example>
<![CDATA[
public class Foo extends Bar {
 // There's probably a better name for foo
 int foo;
}
]]>
      </example>
    </rule>

    <rule name="AvoidFieldNameMatchingMethodName"
    		 since="3.0"
          message="It is somewhat confusing to have a field name with the same name as a method"
          class="net.sourceforge.pmd.rules.AvoidFieldNameMatchingMethodName"
          externalInfoUrl="http://pmd.sourceforge.net/rules/naming.html#AvoidFieldNameMatchingMethodName">
      <description>
It is somewhat confusing to have a field name with the same name as a method.
While this is totally legal, having information (field) and actions (method) is
not clear naming.
      </description>
        <priority>3</priority>
      <example>
<![CDATA[
public class Foo {
	Object bar;
	// bar is data or an action or both?
	void bar() {
	}
}
]]>
      </example>
    </rule>

    <rule name="NoPackage"
        since="3.3"
        message="All classes and interfaces must belong to a named package"
        class="net.sourceforge.pmd.rules.XPathRule"
          externalInfoUrl="http://pmd.sourceforge.net/rules/naming.html#NoPackage">
    <description>
Detects when a class or interface does not have a package definition.
    </description>
    <priority>3</priority>
      <properties>
          <property name="xpath" pluginname="true">
              <value>
                  <![CDATA[
//ClassOrInterfaceDeclaration[count(preceding::PackageDeclaration) = 0]
                  ]]>
              </value>
          </property>
      </properties>
    <example>
<![CDATA[
// no package declaration
public class ClassInDefaultPackage {
}
]]>
    </example>
  </rule>

    <rule name="MisleadingVariableName"
          since="3.4"
          message="Avoid naming non-fields with the prefix 'm_'"
          class="net.sourceforge.pmd.rules.XPathRule"
          externalInfoUrl="http://pmd.sourceforge.net/rules/naming.html#MisleadingVariableName">
      <description>
Detects when a non-field has a name starting with 'm_'.  This usually
indicates a field and thus is confusing.
      </description>
      <priority>3</priority>
        <properties>
            <property name="xpath" pluginname="true">
                <value>
                    <![CDATA[
//VariableDeclaratorId
[starts-with(@Image, 'm_')]
[not (../../../FieldDeclaration)]
                    ]]>
                </value>
            </property>
        </properties>
      <example>
  <![CDATA[
  public class Foo {
    private int m_foo; // OK
    public void bar(String m_baz) {  // Bad
      int m_boz = 42; // Bad
    }
  }
  ]]>
      </example>
    </rule>

-->

</ruleset>
<?xml version="1.0" encoding="UTF-8" ?>

<ruleset name="Code Size Rules"
         xmlns="http://pmd.sf.net/ruleset/1.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
         xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd">

    <description>
The Code Size Ruleset contains a collection of rules that find code size related problems.
    </description>

    <rule name="CyclomaticComplexity"
          since="0.1"
          message = "The {0} {1}() has a Cyclomatic Complexity of {2}. The configured cyclomatic complexity threshold is {3}."
          class="PHPMD\Rule\CyclomaticComplexity"
          externalInfoUrl="http://phpmd.org/rules/codesize.html#cyclomaticcomplexity">
        <description>
            <![CDATA[
Complexity is determined by the number of decision points in a method plus one for the
method entry. The decision points are 'if', 'while', 'for', and 'case labels'. Generally,
1-4 is low complexity, 5-7 indicates moderate complexity, 8-10 is high complexity,
 and 11+ is very high complexity.
            ]]>
        </description>
        <priority>3</priority>
        <properties>
            <property name="reportLevel" description="The Cyclomatic Complexity reporting threshold"  value="10"/>
            <property name="showClassesComplexity"
                      description="Indicate if class average violation should be added to the report"
                      value="true"/>
            <property name="showMethodsComplexity"
                      description="Indicate if class average violation should be added to the report"
                      value="true"/>
        </properties>
        <example>
            <![CDATA[
// Cyclomatic Complexity = 11
class Foo {
1   public function example() {
2       if ($a == $b) {
3           if ($a1 == $b1) {
                fiddle();
4           } elseif ($a2 == $b2) {
                fiddle();
            } else {
                fiddle();
            }
5       } elseif ($c == $d) {
6           while ($c == $d) {
                fiddle();
            }
7        } elseif ($e == $f) {
8           for ($n = 0; $n < $h; $n++) {
                fiddle();
            }
        } else {
            switch ($z) {
9               case 1:
                    fiddle();
                    break;
10              case 2:
                    fiddle();
                    break;
11              case 3:
                    fiddle();
                    break;
                default:
                    fiddle();
                    break;
            }
        }
    }
}
            ]]>
        </example>
    </rule>


    <rule name="NPathComplexity"
          since="0.1"
          message="The {0} {1}() has an NPath complexity of {2}. The configured NPath complexity threshold is {3}."
          class="PHPMD\Rule\Design\NpathComplexity"
          externalInfoUrl="http://phpmd.org/rules/codesize.html#npathcomplexity">
        <description>
The NPath complexity of a method is the number of acyclic execution paths through that method.
A threshold of 200 is generally considered the point where measures should be taken to reduce complexity.
        </description>
        <priority>3</priority>
        <properties>
            <property name="minimum" description="The npath reporting threshold" value="200"/>
        </properties>
        <example>
            <![CDATA[
class Foo {
    function bar() {
        // lots of complicated code
    }
}
            ]]>
        </example>
    </rule>


    <rule name="ExcessiveMethodLength"
          since="0.1"
          message="The {0} {1}() has {2} lines of code. Current threshold is set to {3}. Avoid really long methods."
          class="PHPMD\Rule\Design\LongMethod"
          externalInfoUrl="http://phpmd.org/rules/codesize.html#excessivemethodlength">
        <description>
Violations of this rule usually indicate that the method is doing
too much. Try to reduce the method size by creating helper methods and removing any copy/pasted code.
        </description>
        <priority>3</priority>
        <properties>
            <property name="minimum" description="The method size reporting threshold" value="100"/>
            <property name="ignore-whitespace" description="Count whitespace in reporting threshold" value="false"/>
        </properties>
        <example>
            <![CDATA[
class Foo {
    public function doSomething() {
        print("Hello world!" . PHP_EOL);
        print("Hello world!" . PHP_EOL);
        // 98 copies omitted for brevity.
    }
}
            ]]>
        </example>
    </rule>

    <rule name="ExcessiveClassLength"
 	  since="0.1"
          message="The class {0} has {1} lines of code. Current threshold is {2}. Avoid really long classes."
          class="PHPMD\Rule\Design\LongClass"
          externalInfoUrl="http://phpmd.org/rules/codesize.html#excessiveclasslength">
        <description>
Long Class files are indications that the class may be trying to
do too much. Try to break it down, and reduce the size to something
manageable.
        </description>
        <priority>3</priority>
        <properties>
            <property name="minimum" description="The class size reporting threshold"  value="1000"/>
            <property name="ignore-whitespace" description="Count whitespace in reporting threshold" value="false"/>
        </properties>
        <example>
            <![CDATA[
class Foo {
  public function bar() {
    // 1000 lines of code
  }
}
            ]]>
        </example>
    </rule>


    <rule name="ExcessiveParameterList"
          since="0.1"
          message="The {0} {1} has {2} parameters. Consider reducing the number of parameters to less than {3}."
          class="PHPMD\Rule\Design\LongParameterList"
          externalInfoUrl="http://phpmd.org/rules/codesize.html#excessiveparameterlist">
        <description>
Long parameter lists can indicate that a new object should be created to
wrap the numerous parameters.  Basically, try to group the parameters together.
        </description>
        <priority>3</priority>
        <properties>
            <property name="minimum" description="The parameter count reporting threshold" value="10"/>
        </properties>
        <example>
            <![CDATA[
class Foo {
    public function addData(
        $p0, $p1, $p2, $p3, $p4, $p5,
        $p5, $p6, $p7, $p8, $p9, $p10) {
    }
}
            ]]>
        </example>

    </rule>

    <rule name="ExcessivePublicCount"
          since="0.1"
          message="The {0} {1} has {2} public methods and attributes. Consider reducing the number of public items to less than {3}."
          class="PHPMD\Rule\ExcessivePublicCount"
          externalInfoUrl="http://phpmd.org/rules/codesize.html#excessivepubliccount">
        <description>
A large number of public methods and attributes declared in a class can indicate
the class may need to be broken up as increased effort will be required to
thoroughly test it.
        </description>
        <priority>3</priority>
        <properties>
            <property name="minimum" description="The public item reporting threshold" value="45"/>
        </properties>
        <example>
            <![CDATA[
public class Foo {
    public $value;
    public $something;
    public $var;
    // [... more more public attributes ...]

    public function doWork() {}
    public function doMoreWork() {}
    public function doWorkAgain() {}
    // [... more more public methods ...]
}
    ]]>
        </example>
    </rule>

    <rule name="TooManyFields"
          since="0.1"
          message="The {0} {1} has {2} fields. Consider redesigning {1} to keep the number of fields under {3}."
          class="PHPMD\Rule\Design\TooManyFields"
          externalInfoUrl="http://phpmd.org/rules/codesize.html#toomanyfields">
        <description>
Classes that have too many fields could be redesigned to have fewer fields,
possibly through some nested object grouping of some of the information. For
example, a class with city/state/zip fields could instead have one Address
field.
        </description>
        <priority>3</priority>
        <properties>
            <property name="maxfields" description="The field count reporting threshold " value="15"/>
        </properties>
        <example>
            <![CDATA[
class Person {
   protected $one;
   private $two;
   private $three;
   [... many more fields ...]
}
            ]]>
        </example>
    </rule>
<!--
<rule name="NcssMethodCount" message="The method {0}() has an NCSS line count of {1}"
   since="3.9"
   class="net.sourceforge.pmd.rules.codesize.NcssMethodCount"
   externalInfoUrl="http://pmd.sourceforge.net/rules/codesize.html#NcssMethodCount">
    <description>
This rule uses the NCSS (Non Commenting Source Statements) algorithm to determine the number of lines
of code for a given method. NCSS ignores comments, and counts actual statements. Using this algorithm,
lines of code that are split are counted as one.
    </description>
    <priority>3</priority>
    <properties>
        <property name="minimum" description="The method NCSS count reporting threshold" value="100"/>
    </properties>
   <example>
<![CDATA[
public class Foo extends Bar {
 public int methd() {
     super.methd();





 //this method only has 1 NCSS lines
      return 1;
 }
}
]]>
   </example>
   </rule>

<rule name="NcssTypeCount" message="The type has an NCSS line count of {0}"
   since="3.9"
   class="net.sourceforge.pmd.rules.codesize.NcssTypeCount"
   externalInfoUrl="http://pmd.sourceforge.net/rules/codesize.html#NcssTypeCount">
    <description>
This rule uses the NCSS (Non Commenting Source Statements) algorithm to determine the number of lines
of code for a given type. NCSS ignores comments, and counts actual statements. Using this algorithm,
lines of code that are split are counted as one.
    </description>
    <priority>3</priority>
    <properties>
        <property name="minimum" description="The type NCSS count reporting threshold" value="1500"/>
    </properties>
   <example>
<![CDATA[
public class Foo extends Bar {
 public Foo() {
 //this class only has 6 NCSS lines
     super();





      super.foo();
 }
}
]]>
   </example></rule>

<rule name="NcssConstructorCount" message="The constructor with {0} parameters has an NCSS line count of {1}"
   since="3.9"
   class="net.sourceforge.pmd.rules.codesize.NcssConstructorCount"
   externalInfoUrl="http://pmd.sourceforge.net/rules/codesize.html#NcssConstructorCount">
    <description>
This rule uses the NCSS (Non Commenting Source Statements) algorithm to determine the number of lines
of code for a given constructor. NCSS ignores comments, and counts actual statements. Using this algorithm,
lines of code that are split are counted as one.
    </description>
    <priority>3</priority>
    <properties>
        <property name="minimum" description="The constructor NCSS count reporting threshold" value="100"/>
    </properties>
   <example>
<![CDATA[
public class Foo extends Bar {
 public Foo() {
     super();





 //this constructor only has 1 NCSS lines
      super.foo();
 }
}
]]>
   </example>
</rule>
 -->

    <rule name="TooManyMethods"
          since="0.1"
          class="PHPMD\Rule\Design\TooManyMethods"
          message="The {0} {1} has {2} non-getter- and setter-methods. Consider refactoring {1} to keep number of methods under {3}."
          externalInfoUrl="http://phpmd.org/rules/codesize.html#toomanymethods">
        <description>
            <![CDATA[
A class with too many methods is probably a good suspect for refactoring, in
order to reduce its complexity and find a way to have more fine grained objects.

By default it ignores methods starting with 'get' or 'set'.

The default was changed from 10 to 25 in PHPMD 2.3.
            ]]>
        </description>
        <priority>3</priority>
        <properties>
            <property name="maxmethods" description="The method count reporting threshold" value="25"/>
            <property name="ignorepattern" description="Ignore methods matching this regex" value="(^(set|get))i"/>
        </properties>
    </rule>

    <rule name="TooManyPublicMethods"
          since="0.1"
          class="PHPMD\Rule\Design\TooManyPublicMethods"
          message="The {0} {1} has {2} public methods. Consider refactoring {1} to keep number of public methods under {3}."
          externalInfoUrl="http://phpmd.org/rules/codesize.html#toomanypublicmethods">
        <description>
            <![CDATA[
A class with too many public methods is probably a good suspect for refactoring, in
order to reduce its complexity and find a way to have more fine grained objects.

By default it ignores methods starting with 'get' or 'set'.
            ]]>
        </description>
        <priority>3</priority>
        <properties>
            <property name="maxmethods" description="The method count reporting threshold" value="10"/>
            <property name="ignorepattern" description="Ignore methods matching this regex" value="(^(set|get))i"/>
        </properties>
    </rule>

    <rule name="ExcessiveClassComplexity"
          since="0.2.5"
          class="PHPMD\Rule\Design\WeightedMethodCount"
          message="The class {0} has an overall complexity of {1} which is very high. The configured complexity threshold is {2}."
          externalInfoUrl="http://phpmd.org/rules/codesize.html#excessiveclasscomplexity">
        <description>
            <![CDATA[
The Weighted Method Count (WMC) of a class is a good indicator of how much time
and effort is required to modify and maintain this class. The WMC metric is defined
as the sum of complexities of all methods declared in a class. A large number of
methods also means that this class has a greater potential impact on derived classes.
            ]]>
        </description>
        <priority>3</priority>
        <properties>
            <property name="maximum" description="The maximum WMC tolerable for a class." value="50"/>
        </properties>
        <example>
            <![CDATA[
class Foo {
    public function bar() {
        if ($a == $b)  {
            if ($a1 == $b1) {
                fiddle();
            } elseif ($a2 == $b2) {
                fiddle();
            } else {
            }
        }
    }
    public function baz() {
        if ($a == $b) {
            if ($a1 == $b1) {
                fiddle();
            } elseif ($a2 == $b2) {
                fiddle();
            } else {
            }
        }
    }
    // Several other complex methods
}
            ]]>
        </example>
    </rule>
</ruleset>
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD;

use PDepend\Engine;
use PDepend\Report\CodeAwareGenerator;
use PDepend\Source\ASTVisitor\AbstractASTVisitor;
use PDepend\Metrics\Analyzer;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTArtifactList;
use PHPMD\Node\ClassNode;
use PHPMD\Node\FunctionNode;
use PHPMD\Node\InterfaceNode;
use PHPMD\Node\MethodNode;

/**
 * Simple wrapper around the php depend engine.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Parser extends AbstractASTVisitor implements CodeAwareGenerator
{
    /**
     * The analysing rule-set instance.
     *
     * @var \PHPMD\RuleSet[]
     */
    private $ruleSets = array();

    /**
     * The metric containing analyzer instances.
     *
     * @var \PDepend\Metrics\AnalyzerNodeAware[]
     */
    private $analyzers = array();

    /**
     * The raw PDepend code nodes.
     *
     * @var \PDepend\Source\AST\ASTArtifactList
     */
    private $artifacts = null;

    /**
     * The violation report used by this PDepend adapter.
     *
     * @var \PHPMD\Report
     */
    private $report = null;

    /**
     * The wrapped PDepend Engine instance.
     *
     * @var \PDepend\Engine
     */
    private $pdepend = null;

    /**
     * Constructs a new parser adapter instance.
     *
     * @param \PDepend\Engine $pdepend The context php depend instance.
     */
    public function __construct(Engine $pdepend)
    {
        $this->pdepend = $pdepend;
    }

    /**
     * Parses the projects source and reports all detected errors and violations.
     *
     * @param \PHPMD\Report $report
     * @return void
     */
    public function parse(Report $report)
    {
        $this->setReport($report);

        $this->pdepend->addReportGenerator($this);
        $this->pdepend->analyze();

        foreach ($this->pdepend->getExceptions() as $exception) {
            $report->addError(new ProcessingError($exception->getMessage()));
        }
    }

    /**
     * Adds a new analysis rule-set to this adapter.
     *
     * @param \PHPMD\RuleSet $ruleSet
     * @return void
     */
    public function addRuleSet(RuleSet $ruleSet)
    {
        $this->ruleSets[] = $ruleSet;
    }

    /**
     * Sets the violation report used by the rule-set.
     *
     * @param \PHPMD\Report $report
     * @return void
     */
    public function setReport(Report $report)
    {
        $this->report = $report;
    }

    /**
     * Adds an analyzer to log. If this logger accepts the given analyzer it
     * with return <b>true</b>, otherwise the return value is <b>false</b>.
     *
     * @param \PDepend\Metrics\Analyzer $analyzer The analyzer to log.
     *
     * @return boolean
     */
    public function log(Analyzer $analyzer)
    {
        $this->analyzers[] = $analyzer;
    }

    /**
     * Closes the logger process and writes the output file.
     *
     * @return void
     * @throws \PDepend\Report\NoLogOutputException If the no log target exists.
     */
    public function close()
    {
        // Set max nesting level, because we may get really deep data structures
        ini_set('xdebug.max_nesting_level', 8192);

        foreach ($this->artifacts as $node) {
            $node->accept($this);
        }
    }

    /**
     * Returns an <b>array</b> with accepted analyzer types. These types can be
     * concrete analyzer classes or one of the descriptive analyzer interfaces.
     *
     * @return array(string)
     */
    public function getAcceptedAnalyzers()
    {
        return array(
            'pdepend.analyzer.cyclomatic_complexity',
            'pdepend.analyzer.node_loc',
            'pdepend.analyzer.npath_complexity',
            'pdepend.analyzer.inheritance',
            'pdepend.analyzer.node_count',
            'pdepend.analyzer.hierarchy',
            'pdepend.analyzer.crap_index',
            'pdepend.analyzer.code_rank',
            'pdepend.analyzer.coupling',
            'pdepend.analyzer.class_level',
            'pdepend.analyzer.cohesion',
        );
    }

    /**
     * Visits a class node.
     *
     * @param \PDepend\Source\AST\ASTClass $node
     * @return void
     */
    public function visitClass(ASTClass $node)
    {
        if (!$node->isUserDefined()) {
            return;
        }

        $this->apply(new ClassNode($node));
        parent::visitClass($node);
    }

    /**
     * Visits a function node.
     *
     * @param \PDepend\Source\AST\ASTFunction $node
     * @return void
     */
    public function visitFunction(ASTFunction $node)
    {
        if ($node->getCompilationUnit()->getFileName() === null) {
            return;
        }

        $this->apply(new FunctionNode($node));
    }

    /**
     * Visits an interface node.
     *
     * @param \PDepend\Source\AST\ASTInterface $node
     * @return void
     */
    public function visitInterface(ASTInterface $node)
    {
        if (!$node->isUserDefined()) {
            return;
        }

        $this->apply(new InterfaceNode($node));
        parent::visitInterface($node);
    }

    /**
     * Visits a method node.
     *
     * @param \PDepend\Source\AST\ASTMethod $node
     * @return void
     */
    public function visitMethod(ASTMethod $node)
    {
        if ($node->getCompilationUnit()->getFileName() === null) {
            return;
        }

        $this->apply(new MethodNode($node));
    }

    /**
     * Sets the context code nodes.
     *
     * @param \PDepend\Source\AST\ASTArtifactList $artifacts
     * @return void
     */
    public function setArtifacts(ASTArtifactList $artifacts)
    {
        $this->artifacts = $artifacts;
    }

    /**
     * Applies all rule-sets to the given <b>$node</b> instance.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    private function apply(AbstractNode $node)
    {
        $this->collectMetrics($node);
        foreach ($this->ruleSets as $ruleSet) {
            $ruleSet->setReport($this->report);
            $ruleSet->apply($node);
        }
    }

    /**
     * Collects the collected metrics for the given node and adds them to the
     * <b>$node</b>.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    private function collectMetrics(AbstractNode $node)
    {
        $metrics = array();

        $pdepend = $node->getNode();
        foreach ($this->analyzers as $analyzer) {
            $metrics = array_merge($metrics, $analyzer->getNodeMetrics($pdepend));
        }
        $node->setMetrics($metrics);
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD;

/**
 * This is the abstract base class for pmd rules.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 *
 * @SuppressWarnings(PHPMD)
 */
abstract class AbstractRule implements Rule
{
    /**
     * The name for this rule instance.
     *
     * @var string $_name
     */
    private $name = '';

    /**
     * The violation message text for this rule.
     *
     * @var string
     */
    private $message = '';

    /**
     * The version since when this rule is available.
     *
     * @var string
     */
    private $since = null;

    /**
     * An url will external information for this rule.
     *
     * @var string
     */
    private $externalInfoUrl = '';

    /**
     * An optional description for this rule.
     *
     * @var string
     */
    private $description = '';

    /**
     * A list of code examples for this rule.
     *
     * @var array(string)
     */
    private $examples = array();

    /**
     * The name of the parent rule-set instance.
     *
     * @var string
     */
    private $ruleSetName = '';

    /**
     * The priority of this rule.
     *
     * @var integer
     */
    private $priority = self::LOWEST_PRIORITY;

    /**
     * Configuration properties for this rule instance.
     *
     * @var array(string=>string)
     */
    private $properties = array();

    /**
     * The report for object for this rule.
     *
     * @var \PHPMD\Report
     */
    private $report = null;

    /**
     * Returns the name for this rule instance.
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Sets the name for this rule instance.
     *
     * @param string $name The rule name.
     *
     * @return void
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * Returns the version since when this rule is available or <b>null</b>.
     *
     * @return string
     */
    public function getSince()
    {
        return $this->since;
    }

    /**
     * Sets the version since when this rule is available.
     *
     * @param string $since The version number.
     *
     * @return void
     */
    public function setSince($since)
    {
        $this->since = $since;
    }

    /**
     * Returns the violation message text for this rule.
     *
     * @return string
     */
    public function getMessage()
    {
        return $this->message;
    }

    /**
     * Sets the violation message text for this rule.
     *
     * @param string $message The violation message
     *
     * @return void
     */
    public function setMessage($message)
    {
        $this->message = $message;
    }

    /**
     * Returns an url will external information for this rule.
     *
     * @return string
     */
    public function getExternalInfoUrl()
    {
        return $this->externalInfoUrl;
    }

    /**
     * Sets an url will external information for this rule.
     *
     * @param string $externalInfoUrl The info url.
     *
     * @return void
     */
    public function setExternalInfoUrl($externalInfoUrl)
    {
        $this->externalInfoUrl = $externalInfoUrl;
    }

    /**
     * Returns the description text for this rule instance.
     *
     * @return string
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * Sets the description text for this rule instance.
     *
     * @param string $description The description text.
     *
     * @return void
     */
    public function setDescription($description)
    {
        $this->description = $description;
    }

    /**
     * Returns a list of examples for this rule.
     *
     * @return array(string)
     */
    public function getExamples()
    {
        return $this->examples;
    }

    /**
     * Adds a code example for this rule.
     *
     * @param string $example The code example.
     *
     * @return void
     */
    public function addExample($example)
    {
        $this->examples[] = $example;
    }

    /**
     * Returns the priority of this rule.
     *
     * @return integer
     */
    public function getPriority()
    {
        return $this->priority;
    }

    /**
     * Set the priority of this rule.
     *
     * @param integer $priority The rule priority
     *
     * @return void
     */
    public function setPriority($priority)
    {
        $this->priority = $priority;
    }

    /**
     * Returns the name of the parent rule-set instance.
     *
     * @return string
     */
    public function getRuleSetName()
    {
        return $this->ruleSetName;
    }

    /**
     * Sets the name of the parent rule set instance.
     *
     * @param string $ruleSetName The rule-set name.
     *
     * @return void
     */
    public function setRuleSetName($ruleSetName)
    {
        $this->ruleSetName = $ruleSetName;
    }

    /**
     * Returns the violation report for this rule.
     *
     * @return \PHPMD\Report
     */
    public function getReport()
    {
        return $this->report;
    }

    /**
     * Sets the violation report for this rule.
     *
     * @param \PHPMD\Report $report
     * @return void
     */
    public function setReport(Report $report)
    {
        $this->report = $report;
    }

    /**
     * Adds a configuration property to this rule instance.
     *
     * @param string $name
     * @param string $value
     * @return void
     */
    public function addProperty($name, $value)
    {
        $this->properties[$name] = $value;
    }

    /**
     * Returns the value of a configured property as a boolean or throws an
     * exception when no property with <b>$name</b> exists.
     *
     * @param string $name
     * @return boolean
     * @throws \OutOfBoundsException When no property for <b>$name</b> exists.
     */
    public function getBooleanProperty($name)
    {
        if (isset($this->properties[$name])) {
            return in_array($this->properties[$name], array('true', 'on', 1));
        }
        throw new \OutOfBoundsException('Property "' . $name . '" does not exist.');
    }

    /**
     * Returns the value of a configured property as an integer or throws an
     * exception when no property with <b>$name</b> exists.
     *
     * @param string $name
     * @return integer
     * @throws \OutOfBoundsException When no property for <b>$name</b> exists.
     */
    public function getIntProperty($name)
    {
        if (isset($this->properties[$name])) {
            return (int) $this->properties[$name];
        }
        throw new \OutOfBoundsException('Property "' . $name . '" does not exist.');
    }


    /**
     * Returns the raw string value of a configured property or throws an
     * exception when no property with <b>$name</b> exists.
     *
     * @param string $name
     * @return string
     * @throws \OutOfBoundsException When no property for <b>$name</b> exists.
     */
    public function getStringProperty($name)
    {
        if (isset($this->properties[$name])) {
            return $this->properties[$name];
        }
        throw new \OutOfBoundsException('Property "' . $name . '" does not exist.');

    }

    /**
     * This method adds a violation to all reports for this violation type and
     * for the given <b>$node</b> instance.
     *
     * @param \PHPMD\AbstractNode $node
     * @param array $args
     * @param mixed $metric
     * @return void
     */
    protected function addViolation(
        AbstractNode $node,
        array $args = array(),
        $metric = null
    ) {
        $search  = array();
        $replace = array();
        foreach ($args as $index => $value) {
            $search[]  = '{' . $index . '}';
            $replace[] = $value;
        }

        $message = str_replace($search, $replace, $this->message);

        $ruleViolation = new RuleViolation($this, $node, $message, $metric);
        $this->report->addRuleViolation($ruleViolation);
    }

    /**
     * This method should implement the violation analysis algorithm of concrete
     * rule implementations. All extending classes must implement this method.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    abstract public function apply(AbstractNode $node);
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\TextUI;

use PHPMD\PHPMD;
use PHPMD\RuleSetFactory;
use PHPMD\Writer\StreamWriter;

/**
 * This class provides a command line interface for PHPMD
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Command
{
    /**
     * Exit codes used by the phpmd command line tool.
     */
    const EXIT_SUCCESS   = 0,
          EXIT_EXCEPTION = 1,
          EXIT_VIOLATION = 2;

    /**
     * This method creates a PHPMD instance and configures this object based
     * on the user's input, then it starts the source analysis.
     *
     * The return value of this method can be used as an exit code. A value
     * equal to <b>EXIT_SUCCESS</b> means that no violations or errors were
     * found in the analyzed code. Otherwise this method will return a value
     * equal to <b>EXIT_VIOLATION</b>.
     *
     * The use of flag <b>--ignore-violations-on-exit</b> will result to a
     * <b>EXIT_SUCCESS</b> even if any violation is found.
     *
     * @param \PHPMD\TextUI\CommandLineOptions $opts
     * @param \PHPMD\RuleSetFactory $ruleSetFactory
     * @return integer
     */
    public function run(CommandLineOptions $opts, RuleSetFactory $ruleSetFactory)
    {
        if ($opts->hasVersion()) {
            fwrite(STDOUT, sprintf('PHPMD %s', $this->getVersion()) . PHP_EOL);
            return self::EXIT_SUCCESS;
        }

        // Create a report stream
        $stream = $opts->getReportFile() ? fopen($opts->getReportFile(), 'wb') : STDOUT;

        // Create renderer and configure output
        $renderer = $opts->createRenderer();
        $renderer->setWriter(new StreamWriter($stream));

        $renderers = array($renderer);

        foreach ($opts->getReportFiles() as $reportFormat => $reportFile) {
            $reportRenderer = $opts->createRenderer($reportFormat);
            $reportRenderer->setWriter(new StreamWriter(fopen($reportFile, 'wb')));

            $renderers[] = $reportRenderer;
        }

        // Configure a rule set factory
        $ruleSetFactory->setMinimumPriority($opts->getMinimumPriority());
        if ($opts->hasStrict()) {
            $ruleSetFactory->setStrict();
        }

        $phpmd = new PHPMD();
        $phpmd->setOptions(
            array_filter(
                array(
                    'coverage' => $opts->getCoverageReport()
                )
            )
        );

        $extensions = $opts->getExtensions();
        if ($extensions !== null) {
            $phpmd->setFileExtensions(explode(',', $extensions));
        }

        $ignore = $opts->getIgnore();
        if ($ignore !== null) {
            $phpmd->setIgnorePattern(explode(',', $ignore));
        }

        $phpmd->processFiles(
            $opts->getInputPath(),
            $opts->getRuleSets(),
            $renderers,
            $ruleSetFactory
        );

        if ($phpmd->hasViolations() && !$opts->ignoreViolationsOnExit()) {
            return self::EXIT_VIOLATION;
        }
        return self::EXIT_SUCCESS;
    }

    /**
     * Returns the current version number.
     *
     * @return string
     */
    private function getVersion()
    {
        $build = __DIR__ . '/../../../../../build.properties';

        $version = '2.6.0';
        if (file_exists($build)) {
            $data = @parse_ini_file($build);
            $version = $data['project.version'];
        }
        return $version;
    }

    /**
     * The main method that can be used by a calling shell script, the return
     * value can be used as exit code.
     *
     * @param array $args The raw command line arguments array.
     *
     * @return integer
     */
    public static function main(array $args)
    {
        try {
            $ruleSetFactory = new RuleSetFactory();
            $options = new CommandLineOptions($args, $ruleSetFactory->listAvailableRuleSets());
            $command = new Command();

            $exitCode = $command->run($options, $ruleSetFactory);
        } catch (\Exception $e) {
            fwrite(STDERR, $e->getMessage() . PHP_EOL);
            $exitCode = self::EXIT_EXCEPTION;
        }
        return $exitCode;
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\TextUI;

use PHPMD\Renderer\HTMLRenderer;
use PHPMD\Renderer\TextRenderer;
use PHPMD\Renderer\XMLRenderer;
use PHPMD\Rule;

/**
 * This is a helper class that collects the specified cli arguments and puts them
 * into accessible properties.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class CommandLineOptions
{
    /**
     * Error code for invalid input
     */
    const INPUT_ERROR = 23;

    /**
     * The minimum rule priority.
     *
     * @var integer
     */
    protected $minimumPriority = Rule::LOWEST_PRIORITY;

    /**
     * A php source code filename or directory.
     *
     * @var string
     */
    protected $inputPath;

    /**
     * The specified report format.
     *
     * @var string
     */
    protected $reportFormat;

    /**
     * An optional filename for the generated report.
     *
     * @var string
     */
    protected $reportFile;

    /**
     * Additional report files.
     *
     * @var array
     */
    protected $reportFiles = array();

    /**
     * A ruleset filename or a comma-separated string of ruleset filenames.
     *
     * @var string
     */
    protected $ruleSets;

    /**
     * File name of a PHPUnit code coverage report.
     *
     * @var string
     */
    protected $coverageReport;

    /**
     * A string of comma-separated extensions for valid php source code filenames.
     *
     * @var string
     */
    protected $extensions;

    /**
     * A string of comma-separated pattern that is used to exclude directories.
     *
     * @var string
     */
    protected $ignore;

    /**
     * Should the shell show the current phpmd version?
     *
     * @var boolean
     */
    protected $version = false;

    /**
     * Should PHPMD run in strict mode?
     *
     * @var boolean
     * @since 1.2.0
     */
    protected $strict = false;

    /**
     * Should PHPMD exit without error code even if violation is found?
     *
     * @var boolean
     */
    protected $ignoreViolationsOnExit = false;

    /**
     * List of available rule-sets.
     *
     * @var array(string)
     */
    protected $availableRuleSets = array();

    /**
     * Constructs a new command line options instance.
     *
     * @param array $args
     * @param array $availableRuleSets
     * @throws \InvalidArgumentException
     */
    public function __construct(array $args, array $availableRuleSets = array())
    {
        // Remove current file name
        array_shift($args);

        $this->availableRuleSets = $availableRuleSets;

        $arguments = array();
        while (($arg = array_shift($args)) !== null) {
            switch ($arg) {
                case '--minimumpriority':
                    $this->minimumPriority = (int) array_shift($args);
                    break;
                case '--reportfile':
                    $this->reportFile = array_shift($args);
                    break;
                case '--inputfile':
                    array_unshift($arguments, $this->readInputFile(array_shift($args)));
                    break;
                case '--coverage':
                    $this->coverageReport = array_shift($args);
                    break;
                case '--extensions':
                    $this->logDeprecated('extensions', 'suffixes');
                    /* Deprecated: We use the suffixes option now */
                case '--suffixes':
                    $this->extensions = array_shift($args);
                    break;
                case '--ignore':
                    $this->logDeprecated('ignore', 'exclude');
                    /* Deprecated: We use the exclude option now */
                case '--exclude':
                    $this->ignore = array_shift($args);
                    break;
                case '--version':
                    $this->version = true;
                    return;
                case '--strict':
                    $this->strict = true;
                    break;
                case '--ignore-violations-on-exit':
                    $this->ignoreViolationsOnExit = true;
                    break;
                case '--reportfile-html':
                case '--reportfile-text':
                case '--reportfile-xml':
                    preg_match('(^\-\-reportfile\-(xml|html|text)$)', $arg, $match);
                    $this->reportFiles[$match[1]] = array_shift($args);
                    break;
                default:
                    $arguments[] = $arg;
                    break;
            }
        }

        if (count($arguments) < 3) {
            throw new \InvalidArgumentException($this->usage(), self::INPUT_ERROR);
        }

        $this->inputPath    = (string) array_shift($arguments);
        $this->reportFormat = (string) array_shift($arguments);
        $this->ruleSets     = (string) array_shift($arguments);
    }

    /**
     * Returns a php source code filename or directory.
     *
     * @return string
     */
    public function getInputPath()
    {
        return $this->inputPath;
    }

    /**
     * Returns the specified report format.
     *
     * @return string
     */
    public function getReportFormat()
    {
        return $this->reportFormat;
    }

    /**
     * Returns the output filename for a generated report or <b>null</b> when
     * the report should be displayed in STDOUT.
     *
     * @return string
     */
    public function getReportFile()
    {
        return $this->reportFile;
    }

    /**
     * Returns a hash with report files specified for different renderers. The
     * key represents the report format and the value the report file location.
     *
     * @return array
     */
    public function getReportFiles()
    {
        return $this->reportFiles;
    }

    /**
     * Returns a ruleset filename or a comma-separated string of ruleset
     *
     * @return string
     */
    public function getRuleSets()
    {
        return $this->ruleSets;
    }

    /**
     * Returns the minimum rule priority.
     *
     * @return integer
     */
    public function getMinimumPriority()
    {
        return $this->minimumPriority;
    }

    /**
     * Returns the file name of a supplied code coverage report or <b>NULL</b>
     * if the user has not supplied the --coverage option.
     *
     * @return string
     */
    public function getCoverageReport()
    {
        return $this->coverageReport;
    }

    /**
     * Returns a string of comma-separated extensions for valid php source code
     * filenames or <b>null</b> when this argument was not set.
     *
     * @return string
     */
    public function getExtensions()
    {
        return $this->extensions;
    }

    /**
     * Returns  string of comma-separated pattern that is used to exclude
     * directories or <b>null</b> when this argument was not set.
     *
     * @return string
     */
    public function getIgnore()
    {
        return $this->ignore;
    }

    /**
     * Was the <b>--version</b> passed to PHPMD's command line interface?
     *
     * @return boolean
     */
    public function hasVersion()
    {
        return $this->version;
    }

    /**
     * Was the <b>--strict</b> option passed to PHPMD's command line interface?
     *
     * @return boolean
     * @since 1.2.0
     */
    public function hasStrict()
    {
        return $this->strict;
    }

    /**
     * Was the <b>--ignore-violations-on-exit</b> passed to PHPMD's command line interface?
     *
     * @return boolean
     */
    public function ignoreViolationsOnExit()
    {
        return $this->ignoreViolationsOnExit;
    }

    /**
     * Creates a report renderer instance based on the user's command line
     * argument.
     *
     * Valid renderers are:
     * <ul>
     *   <li>xml</li>
     *   <li>html</li>
     *   <li>text</li>
     * </ul>
     *
     * @param string $reportFormat
     * @return \PHPMD\AbstractRenderer
     * @throws \InvalidArgumentException When the specified renderer does not exist.
     */
    public function createRenderer($reportFormat = null)
    {
        $reportFormat = $reportFormat ?: $this->reportFormat;

        switch ($reportFormat) {
            case 'xml':
                return $this->createXmlRenderer();
            case 'html':
                return $this->createHtmlRenderer();
            case 'text':
                return $this->createTextRenderer();
            default:
                return $this->createCustomRenderer();
        }
    }

    /**
     * @return \PHPMD\Renderer\XMLRenderer
     */
    protected function createXmlRenderer()
    {
        return new XMLRenderer();
    }

    /**
     * @return \PHPMD\Renderer\XMLRenderer
     */
    protected function createTextRenderer()
    {
        return new TextRenderer();
    }

    /**
     * @return \PHPMD\Renderer\HTMLRenderer
     */
    protected function createHtmlRenderer()
    {
        return new HTMLRenderer();
    }

    /**
     * @return \PHPMD\AbstractRenderer
     * @throws \InvalidArgumentException
     */
    protected function createCustomRenderer()
    {
        if ('' === $this->reportFormat) {
            throw new \InvalidArgumentException(
                'Can\'t create report with empty format.',
                self::INPUT_ERROR
            );
        }

        if (class_exists($this->reportFormat)) {
            return new $this->reportFormat();
        }

        // Try to load a custom renderer
        $fileName = strtr($this->reportFormat, '_\\', '//') . '.php';

        $fileHandle = @fopen($fileName, 'r', true);
        if (is_resource($fileHandle) === false) {
            throw new \InvalidArgumentException(
                sprintf(
                    'Can\'t find the custom report class: %s',
                    $this->reportFormat
                ),
                self::INPUT_ERROR
            );
        }
        @fclose($fileHandle);

        include_once $fileName;

        return new $this->reportFormat();
    }

    /**
     * Returns usage information for the PHPMD command line interface.
     *
     * @return string
     */
    public function usage()
    {
        return 'Mandatory arguments:' . \PHP_EOL .
               '1) A php source code filename or directory. Can be a comma-' .
               'separated string' . \PHP_EOL .
               '2) A report format' . \PHP_EOL .
               '3) A ruleset filename or a comma-separated string of ruleset' .
               'filenames' . \PHP_EOL . \PHP_EOL .
               'Available formats: xml, text, html.' . \PHP_EOL .
               'Available rulesets: ' . implode(', ', $this->availableRuleSets) . '.' . \PHP_EOL . \PHP_EOL .
               'Optional arguments that may be put after the mandatory arguments:' .
               \PHP_EOL .
               '--minimumpriority: rule priority threshold; rules with lower ' .
               'priority than this will not be used' . \PHP_EOL .
               '--reportfile: send report output to a file; default to STDOUT' .
               \PHP_EOL .
               '--suffixes: comma-separated string of valid source code ' .
               'filename extensions, e.g. php,phtml' . \PHP_EOL .
               '--exclude: comma-separated string of patterns that are used to ' .
               'ignore directories' . \PHP_EOL .
                '--strict: also report those nodes with a @SuppressWarnings ' .
               'annotation' . \PHP_EOL .
                '--ignore-violations-on-exit: will exit with a zero code, ' .
                'even if any violations are found' . \PHP_EOL;
    }

    /**
     * Logs a deprecated option to the current user interface.
     *
     * @param string $deprecatedName
     * @param string $newName
     * @return void
     */
    protected function logDeprecated($deprecatedName, $newName)
    {
        $message = sprintf(
            'The --%s option is deprecated, please use --%s instead.',
            $deprecatedName,
            $newName
        );

        fwrite(STDERR, $message . PHP_EOL . PHP_EOL);
    }

    /**
     * This method takes the given input file, reads the newline separated paths
     * from that file and creates a comma separated string of the file paths. If
     * the given <b>$inputFile</b> not exists, this method will throw an
     * exception.
     *
     * @param string $inputFile Specified input file name.
     * @return string
     * @throws \InvalidArgumentException If the specified input file does not exist.
     * @since 1.1.0
     */
    protected function readInputFile($inputFile)
    {
        if (file_exists($inputFile)) {
            return join(',', array_map('trim', file($inputFile)));
        }
        throw new \InvalidArgumentException("Input file '{$inputFile}' not exists.");
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD;

/**
 * This class is a collection of concrete source analysis rules.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class RuleSet implements \IteratorAggregate
{
    /**
     * Should this rule set force the strict mode.
     *
     * @var boolean
     * @since 1.2.0
     */
    private $strict = false;

    /**
     * The name of the file where this set is specified.
     *
     * @var string
     */
    private $fileName = '';

    /**
     * The name of this rule-set.
     *
     * @var string
     */
    private $name = '';

    /**
     * An optional description for this rule-set.
     *
     * @var string
     */
    private $description = '';

    /**
     * The violation report used by the rule-set.
     *
     * @var \PHPMD\Report
     */
    private $report;

    /**
     * Mapping between marker interfaces and concrete context code node classes.
     *
     * @var array(string=>string)
     */
    private $applyTo = array(
        'PHPMD\\Rule\\ClassAware'     => 'PHPMD\\Node\\ClassNode',
        'PHPMD\\Rule\\FunctionAware'  => 'PHPMD\\Node\\FunctionNode',
        'PHPMD\\Rule\\InterfaceAware' => 'PHPMD\\Node\\InterfaceNode',
        'PHPMD\\Rule\\MethodAware'    => 'PHPMD\\Node\\MethodNode',
    );

    /**
     * Mapping of rules that apply to a concrete code node type.
     *
     * @var array(string=>array)
     */
    private $rules = array(
        'PHPMD\\Node\\ClassNode'     =>  array(),
        'PHPMD\\Node\\FunctionNode'  =>  array(),
        'PHPMD\\Node\\InterfaceNode' =>  array(),
        'PHPMD\\Node\\MethodNode'    =>  array(),
    );

    /**
     * Returns the file name where the definition of this rule-set comes from.
     *
     * @return string
     */
    public function getFileName()
    {
        return $this->fileName;
    }

    /**
     * Sets the file name where the definition of this rule-set comes from.
     *
     * @param string $fileName The file name.
     *
     * @return void
     */
    public function setFileName($fileName)
    {
        $this->fileName = $fileName;
    }

    /**
     * Returns the name of this rule-set.
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Sets the name of this rule-set.
     *
     * @param string $name The name of this rule-set.
     *
     * @return void
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * Returns the description text for this rule-set instance.
     *
     * @return string
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * Sets the description text for this rule-set instance.
     *
     * @param string $description The description text.
     *
     * @return void
     */
    public function setDescription($description)
    {
        $this->description = $description;
    }

    /**
     * Activates the strict mode for this rule set instance.
     *
     * @return void
     * @since 1.2.0
     */
    public function setStrict()
    {
        $this->strict = true;
    }

    /**
     * Returns the violation report used by the rule-set.
     *
     * @return \PHPMD\Report
     */
    public function getReport()
    {
        return $this->report;
    }

    /**
     * Sets the violation report used by the rule-set.
     *
     * @param \PHPMD\Report $report
     * @return void
     */
    public function setReport(Report $report)
    {
        $this->report = $report;
    }

    /**
     * This method returns a rule by its name or <b>null</b> if it doesn't exist.
     *
     * @param string $name
     * @return \PHPMD\Rule
     */
    public function getRuleByName($name)
    {
        foreach ($this->getRules() as $rule) {
            if ($rule->getName() === $name) {
                return $rule;
            }
        }
        return null;
    }

    /**
     * This method returns an iterator will all rules that belong to this
     * rule-set.
     *
     * @return \Iterator
     */
    public function getRules()
    {
        $result = array();
        foreach ($this->rules as $rules) {
            foreach ($rules as $rule) {
                if (in_array($rule, $result, true) === false) {
                    $result[] = $rule;
                }
            }
        }

        return new \ArrayIterator($result);
    }

    /**
     * Adds a new rule to this rule-set.
     *
     * @param \PHPMD\Rule $rule
     * @return void
     */
    public function addRule(Rule $rule)
    {
        foreach ($this->applyTo as $applyTo => $type) {
            if ($rule instanceof $applyTo) {
                $this->rules[$type][] = $rule;
            }
        }
    }

    /**
     * Applies all registered rules that match against the concrete node type.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        // Current node type
        $className = get_class($node);

        // Check for valid node type
        if (!isset($this->rules[$className])) {
            return;
        }

        // Apply all rules to this node
        foreach ($this->rules[$className] as $rule) {
            if ($node->hasSuppressWarningsAnnotationFor($rule) && !$this->strict) {
                continue;
            }
            $rule->setReport($this->report);
            $rule->apply($node);
        }
    }

    /**
     * Returns an iterator with all rules that are part of this rule-set.
     *
     * @return \Iterator
     */
    public function getIterator()
    {
        return $this->getRules();
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD;

/**
 * The report class collects all found violations and further information about
 * a PHPMD run.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Report
{
    /**
     * List of rule violations detected in the analyzed source code.
     *
     * @var array
     */
    private $ruleViolations = array();

    /**
     * The start time for this report.
     *
     * @var float
     */
    private $startTime = 0.0;

    /**
     * The end time for this report.
     *
     * @var float
     */
    private $endTime = 0.0;

    /**
     * Errors that occurred while parsing the source.
     *
     * @var array
     * @since 1.2.1
     */
    private $errors = array();

    /**
     * Adds a rule violation to this report.
     *
     * @param \PHPMD\RuleViolation $violation
     * @return void
     */
    public function addRuleViolation(RuleViolation $violation)
    {
        $fileName = $violation->getFileName();
        if (!isset($this->ruleViolations[$fileName])) {
            $this->ruleViolations[$fileName] = array();
        }

        $beginLine = $violation->getBeginLine();
        if (!isset($this->ruleViolations[$fileName][$beginLine])) {
            $this->ruleViolations[$fileName][$beginLine] = array();
        }

        $this->ruleViolations[$fileName][$beginLine][] = $violation;
    }

    /**
     * Returns <b>true</b> when this report does not contain any errors.
     *
     * @return boolean
     * @since 0.2.5
     */
    public function isEmpty()
    {
        return (count($this->ruleViolations) === 0);
    }

    /**
     * Returns an iterator with all occurred rule violations.
     *
     * @return \PHPMD\RuleViolation[]
     */
    public function getRuleViolations()
    {
        // First sort by file name
        ksort($this->ruleViolations);

        $violations = array();
        foreach ($this->ruleViolations as $violationInLine) {
            // Second sort is by line number
            ksort($violationInLine);

            foreach ($violationInLine as $violation) {
                $violations = array_merge($violations, $violation);
            }
        }

        return new \ArrayIterator($violations);
    }

    /**
     * Adds a processing error that occurred while parsing the source.
     *
     * @param \PHPMD\ProcessingError $error
     * @return void
     * @since 1.2.1
     */
    public function addError(ProcessingError $error)
    {
        $this->errors[] = $error;
    }

    /**
     * Returns <b>true</b> when the report contains at least one processing
     * error. Otherwise this method will return <b>false</b>.
     *
     * @return boolean
     * @since 1.2.1
     */
    public function hasErrors()
    {
        return count($this->errors) > 0;
    }

    /**
     * Returns an iterator with all {@link \PHPMD\ProcessingError} that were
     * added to this report.
     *
     * @return \Iterator
     * @since 1.2.1
     */
    public function getErrors()
    {
        return new \ArrayIterator($this->errors);
    }

    /**
     * Starts the time tracking of this report instance.
     *
     * @return void
     */
    public function start()
    {
        $this->startTime = microtime(true) * 1000.0;
    }

    /**
     * Stops the time tracking of this report instance.
     *
     * @return void
     */
    public function end()
    {
        $this->endTime = microtime(true) * 1000.0;
    }

    /**
     * Returns the total time elapsed for the source analysis.
     *
     * @return float
     */
    public function getElapsedTimeInMillis()
    {
        return round($this->endTime - $this->startTime);
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD;

/**
 * This is abstract base class for an output writer.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
abstract class AbstractWriter
{
    /**
     * Writes a data string to the concrete output.
     *
     * @param string $data
     * @return void
     */
    abstract public function write($data);
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD;

/**
 * When a configured rule class does not exist.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class RuleClassNotFoundException extends \RuntimeException
{
    /**
     * Constructs a new class not found exception.
     *
     * @param <type> $className The configured but not found ruke class name.
     */
    public function __construct($className)
    {
        parent::__construct('Cannot find rule class: ' . $className);
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Renderer;

use PHPMD\AbstractRenderer;
use PHPMD\Report;

/**
 * This renderer output a simple html file with all found violations and suspect
 * software artifacts.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class HTMLRenderer extends AbstractRenderer
{
    /**
     * This method will be called on all renderers before the engine starts the
     * real report processing.
     *
     * @return void
     */
    public function start()
    {
        $writer = $this->getWriter();

        $writer->write('<html><head><title>PHPMD</title></head><body>');
        $writer->write(PHP_EOL);
        $writer->write('<center><h1>PHPMD report</h1></center>');
        $writer->write('<center><h2>Problems found</h2></center>');
        $writer->write(PHP_EOL);
        $writer->write('<table align="center" cellspacing="0" cellpadding="3">');
        $writer->write('<tr>');
        $writer->write('<th>#</th><th>File</th><th>Line</th><th>Problem</th>');
        $writer->write('</tr>');
        $writer->write(PHP_EOL);
    }

    /**
     * This method will be called when the engine has finished the source analysis
     * phase.
     *
     * @param \PHPMD\Report $report
     * @return void
     */
    public function renderReport(Report $report)
    {
        $index = 0;

        $writer = $this->getWriter();
        foreach ($report->getRuleViolations() as $violation) {
            $writer->write('<tr');
            if (++$index % 2 === 1) {
                $writer->write(' bgcolor="lightgrey"');
            }
            $writer->write('>');
            $writer->write(PHP_EOL);

            $writer->write('<td align="center">');
            $writer->write($index);
            $writer->write('</td>');
            $writer->write(PHP_EOL);

            $writer->write('<td>');
            $writer->write(htmlentities($violation->getFileName()));
            $writer->write('</td>');
            $writer->write(PHP_EOL);

            $writer->write('<td align="center" width="5%">');
            $writer->write($violation->getBeginLine());
            $writer->write('</td>');
            $writer->write(PHP_EOL);

            $writer->write('<td>');
            if ($violation->getRule()->getExternalInfoUrl()) {
                $writer->write('<a href="');
                $writer->write($violation->getRule()->getExternalInfoUrl());
                $writer->write('">');
            }

            $writer->write(htmlentities($violation->getDescription()));
            if ($violation->getRule()->getExternalInfoUrl()) {
                $writer->write('</a>');
            }

            $writer->write('</td>');
            $writer->write(PHP_EOL);

            $writer->write('</tr>');
            $writer->write(PHP_EOL);
        }

        $writer->write('</table>');

        $this->glomProcessingErrors($report);
    }

    /**
     * This method will be called the engine has finished the report processing
     * for all registered renderers.
     *
     * @return void
     */
    public function end()
    {
        $writer = $this->getWriter();
        $writer->write('</body></html>');
    }

    /**
     * This method will render a html table with occurred processing errors.
     *
     * @param \PHPMD\Report $report
     * @return void
     * @since 1.2.1
     */
    private function glomProcessingErrors(Report $report)
    {
        if (false === $report->hasErrors()) {
            return;
        }

        $writer = $this->getWriter();

        $writer->write('<hr />');
        $writer->write('<center><h3>Processing errors</h3></center>');
        $writer->write('<table align="center" cellspacing="0" cellpadding="3">');
        $writer->write('<tr><th>File</th><th>Problem</th></tr>');

        $index = 0;
        foreach ($report->getErrors() as $error) {
            $writer->write('<tr');
            if (++$index % 2 === 1) {
                $writer->write(' bgcolor="lightgrey"');
            }
            $writer->write('>');
            $writer->write('<td>' . $error->getFile() . '</td>');
            $writer->write('<td>' . htmlentities($error->getMessage()) . '</td>');
            $writer->write('</tr>' . PHP_EOL);
        }

        $writer->write('</table>');
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Renderer;

use PHPMD\AbstractRenderer;
use PHPMD\Report;

/**
 * This renderer output a textual log with all found violations and suspect
 * software artifacts.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class TextRenderer extends AbstractRenderer
{

    /**
     * This method will be called when the engine has finished the source analysis
     * phase.
     *
     * @param \PHPMD\Report $report
     * @return void
     */
    public function renderReport(Report $report)
    {
        $writer = $this->getWriter();

        foreach ($report->getRuleViolations() as $violation) {
            $writer->write($violation->getFileName());
            $writer->write(':');
            $writer->write($violation->getBeginLine());
            $writer->write("\t");
            $writer->write($violation->getDescription());
            $writer->write(PHP_EOL);
        }

        foreach ($report->getErrors() as $error) {
            $writer->write($error->getFile());
            $writer->write("\t-\t");
            $writer->write($error->getMessage());
            $writer->write(PHP_EOL);
        }
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Renderer;

use PHPMD\AbstractRenderer;
use PHPMD\PHPMD;
use PHPMD\Report;

/**
 * This class will render a Java-PMD compatible xml-report.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class XMLRenderer extends AbstractRenderer
{
    /**
     * Temporary property that holds the name of the last rendered file, it is
     * used to detect the next processed file.
     *
     * @var string
     */
    private $fileName = null;

    /**
     * This method will be called on all renderers before the engine starts the
     * real report processing.
     *
     * @return void
     */
    public function start()
    {
        $this->getWriter()->write('<?xml version="1.0" encoding="UTF-8" ?>');
        $this->getWriter()->write(PHP_EOL);
    }

    /**
     * This method will be called when the engine has finished the source analysis
     * phase.
     *
     * @param \PHPMD\Report $report
     * @return void
     */
    public function renderReport(Report $report)
    {
        $writer = $this->getWriter();
        $writer->write('<pmd version="' . PHPMD::VERSION . '" ');
        $writer->write('timestamp="' . date('c') . '">');
        $writer->write(PHP_EOL);

        foreach ($report->getRuleViolations() as $violation) {
            $fileName = $violation->getFileName();
            
            if ($this->fileName !== $fileName) {
                // Not first file
                if ($this->fileName !== null) {
                    $writer->write('  </file>' . PHP_EOL);
                }
                // Store current file name
                $this->fileName = $fileName;

                $writer->write('  <file name="' . $fileName . '">' . PHP_EOL);
            }

            $rule = $violation->getRule();

            $writer->write('    <violation');
            $writer->write(' beginline="' . $violation->getBeginLine() . '"');
            $writer->write(' endline="' . $violation->getEndLine() . '"');
            $writer->write(' rule="' . $rule->getName() . '"');
            $writer->write(' ruleset="' . $rule->getRuleSetName() . '"');
            
            $this->maybeAdd('package', $violation->getNamespaceName());
            $this->maybeAdd('externalInfoUrl', $rule->getExternalInfoUrl());
            $this->maybeAdd('function', $violation->getFunctionName());
            $this->maybeAdd('class', $violation->getClassName());
            $this->maybeAdd('method', $violation->getMethodName());
            //$this->_maybeAdd('variable', $violation->getVariableName());

            $writer->write(' priority="' . $rule->getPriority() . '"');
            $writer->write('>' . PHP_EOL);
            $writer->write('      ' . $violation->getDescription() . PHP_EOL);
            $writer->write('    </violation>' . PHP_EOL);
        }

        // Last file and at least one violation
        if ($this->fileName !== null) {
            $writer->write('  </file>' . PHP_EOL);
        }

        foreach ($report->getErrors() as $error) {
            $writer->write('  <error filename="');
            $writer->write($error->getFile());
            $writer->write('" msg="');
            $writer->write(htmlspecialchars($error->getMessage()));
            $writer->write('" />' . PHP_EOL);
        }

        $writer->write('</pmd>' . PHP_EOL);
    }

    /**
     * This method will write a xml attribute named <b>$attr</b> to the output
     * when the given <b>$value</b> is not an empty string and is not <b>null</b>.
     *
     * @param string $attr  The xml attribute name.
     * @param string $value The attribute value.
     *
     * @return void
     */
    private function maybeAdd($attr, $value)
    {
        if ($value === null || trim($value) === '') {
            return;
        }
        $this->getWriter()->write(' ' . $attr . '="' . $value . '"');
    }
}
<?php
/**
 * This file is part of PHPMD.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD;

/**
 * Base interface for a PHPMD rule.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since     1.1.0
 */
interface Rule
{
    /**
     * The default lowest rule priority.
     */
    const LOWEST_PRIORITY = 5;

    /**
     * Returns the name for this rule instance.
     *
     * @return string
     */
    public function getName();

    /**
     * Sets the name for this rule instance.
     *
     * @param string $name
     * @return void
     */
    public function setName($name);

    /**
     * Returns the version since when this rule is available or <b>null</b>.
     *
     * @return string
     */
    public function getSince();

    /**
     * Sets the version since when this rule is available.
     *
     * @param string $since
     * @return void
     */
    public function setSince($since);

    /**
     * Returns the violation message text for this rule.
     *
     * @return string
     */
    public function getMessage();

    /**
     * Sets the violation message text for this rule.
     *
     * @param string $message
     * @return void
     */
    public function setMessage($message);

    /**
     * Returns an url will external information for this rule.
     *
     * @return string
     */
    public function getExternalInfoUrl();

    /**
     * Sets an url will external information for this rule.
     *
     * @param string $externalInfoUrl
     * @return void
     */
    public function setExternalInfoUrl($externalInfoUrl);

    /**
     * Returns the description text for this rule instance.
     *
     * @return string
     */
    public function getDescription();

    /**
     * Sets the description text for this rule instance.
     *
     * @param string $description
     * @return void
     */
    public function setDescription($description);

    /**
     * Returns a list of examples for this rule.
     *
     * @return array
     */
    public function getExamples();

    /**
     * Adds a code example for this rule.
     *
     * @param string $example
     * @return void
     */
    public function addExample($example);

    /**
     * Returns the priority of this rule.
     *
     * @return integer
     */
    public function getPriority();

    /**
     * Set the priority of this rule.
     *
     * @param integer $priority
     * @return void
     */
    public function setPriority($priority);

    /**
     * Returns the name of the parent rule-set instance.
     *
     * @return string
     */
    public function getRuleSetName();

    /**
     * Sets the name of the parent rule set instance.
     *
     * @param string $ruleSetName
     * @return void
     */
    public function setRuleSetName($ruleSetName);

    /**
     * Returns the violation report for this rule.
     *
     * @return \PHPMD\Report
     */
    public function getReport();

    /**
     * Sets the violation report for this rule.
     *
     * @param \PHPMD\Report $report
     * @return void
     */
    public function setReport(\PHPMD\Report $report);

    /**
     * Adds a configuration property to this rule instance.
     *
     * @param string $name
     * @param string $value
     * @return void
     */
    public function addProperty($name, $value);

    /**
     * Returns the value of a configured property as a boolean or throws an
     * exception when no property with <b>$name</b> exists.
     *
     * @param string $name
     * @return boolean
     * @throws \OutOfBoundsException When no property for <b>$name</b> exists.
     */
    public function getBooleanProperty($name);

    /**
     * Returns the value of a configured property as an integer or throws an
     * exception when no property with <b>$name</b> exists.
     *
     * @param string $name
     * @return integer
     * @throws \OutOfBoundsException When no property for <b>$name</b> exists.
     */
    public function getIntProperty($name);

    /**
     * This method should implement the violation analysis algorithm of concrete
     * rule implementations. All extending classes must implement this method.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node);
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\Design;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;

/**
 * This rule will detect to long methods, those methods are unreadable and in
 * many cases the result of copy and paste coding.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class LongMethod extends AbstractRule implements FunctionAware, MethodAware
{
    /**
     * This method checks the lines of code length for the given function or
     * methode node against a configured threshold.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $threshold = $this->getIntProperty('minimum');

        $loc = -1;
        if ($this->getBooleanProperty('ignore-whitespace')) {
            $loc = $node->getMetric('eloc');
        }
        if (-1 === $loc) {
            $loc = $node->getMetric('loc');
        }

        if ($loc < $threshold) {
            return;
        }

        $this->addViolation(
            $node,
            array(
                $node->getType(),
                $node->getName(),
                $loc,
                $threshold
            )
        );
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\Design;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Node\AbstractTypeNode;
use PHPMD\Rule\ClassAware;

/**
 * This rule class will detect all classes with too much public methods.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class TooManyPublicMethods extends AbstractRule implements ClassAware
{
    /**
     * Regular expression that filters all methods that are ignored by this rule.
     *
     * @var string
     */
    private $ignoreRegexp;

    /**
     * This method checks the number of public methods with in a given class and checks
     * this number against a configured threshold.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $this->ignoreRegexp = $this->getStringProperty('ignorepattern');

        $threshold = $this->getIntProperty('maxmethods');
        if ($node->getMetric('npm') <= $threshold) {
            return;
        }
        $nom = $this->countMethods($node);
        if ($nom <= $threshold) {
            return;
        }
        $this->addViolation(
            $node,
            array(
                $node->getType(),
                $node->getName(),
                $nom,
                $threshold
            )
        );
    }

    /**
     * Counts public methods within the given class/interface node.
     *
     * @param \PHPMD\Node\AbstractTypeNode $node
     * @return integer
     */
    private function countMethods(AbstractTypeNode $node)
    {
        $count = 0;
        foreach ($node->getMethods() as $method) {
            if ($method->getNode()->isPublic() && preg_match($this->ignoreRegexp, $method->getName()) === 0) {
                ++$count;
            }
        }
        return $count;
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\Design;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Node\AbstractTypeNode;
use PHPMD\Rule\ClassAware;

/**
 * This rule class will detect all classes with too much methods.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class TooManyMethods extends AbstractRule implements ClassAware
{
    /**
     * Regular expression that filters all methods that are ignored by this rule.
     *
     * @var string
     */
    private $ignoreRegexp;

    /**
     * This method checks the number of methods with in a given class and checks
     * this number against a configured threshold.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $this->ignoreRegexp = $this->getStringProperty('ignorepattern');

        $threshold = $this->getIntProperty('maxmethods');
        if ($node->getMetric('nom') <= $threshold) {
            return;
        }
        $nom = $this->countMethods($node);
        if ($nom <= $threshold) {
            return;
        }
        $this->addViolation(
            $node,
            array(
                $node->getType(),
                $node->getName(),
                $nom,
                $threshold
            )
        );
    }

    /**
     * Counts all methods within the given class/interface node.
     *
     * @param \PHPMD\Node\AbstractTypeNode $node
     * @return integer
     */
    private function countMethods(AbstractTypeNode $node)
    {
        $count = 0;
        foreach ($node->getMethodNames() as $name) {
            if (preg_match($this->ignoreRegexp, $name) === 0) {
                ++$count;
            }
        }
        return $count;
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\Design;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;

/**
 * This rule class checks for excessive long function and method parameter lists.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class LongParameterList extends AbstractRule implements FunctionAware, MethodAware
{
    /**
     * This method checks the number of arguments for the given function or method
     * node against a configured threshold.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $threshold = $this->getIntProperty('minimum');
        $count = $node->getParameterCount();
        if ($count < $threshold) {
            return;
        }

        $this->addViolation(
            $node,
            array(
                $node->getType(),
                $node->getName(),
                $count,
                $threshold
            )
        );
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since      0.2.5
 */

namespace PHPMD\Rule\Design;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;

/**
 * This rule checks a given class against a configured weighted method count
 * threshold.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since      0.2.5
 */
class WeightedMethodCount extends AbstractRule implements ClassAware
{
    /**
     * This method checks the weighted method count for the given class against
     * a configured threshold.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $threshold = $this->getIntProperty('maximum');
        $actual    = $node->getMetric('wmc');

        if ($actual >= $threshold) {
            $this->addViolation($node, array($node->getName(), $actual, $threshold));
        }
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\Design;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;

/**
 * This rule class will detect excessive long classes.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class LongClass extends AbstractRule implements ClassAware
{
    /**
     * This method checks the length of the given class node against a configured
     * threshold.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $threshold = $this->getIntProperty('minimum');

        $loc = -1;
        if ($this->getBooleanProperty('ignore-whitespace')) {
            $loc = $node->getMetric('eloc');
        }
        if (-1 === $loc) {
            $loc = $node->getMetric('loc');
        }

        if ($loc < $threshold) {
            return;
        }

        $this->addViolation($node, array($node->getName(), $loc, $threshold));
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\Design;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;

/**
 * This rule will detect class that have to much direct child classes.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class NumberOfChildren extends AbstractRule implements ClassAware
{
    /**
     * This method checks the number of classes derived from the given class
     * node.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $nocc = $node->getMetric('nocc');
        $threshold = $this->getIntProperty('minimum');
        if ($nocc >= $threshold) {
            $this->addViolation(
                $node,
                array(
                    $node->getType(),
                    $node->getName(),
                    $nocc,
                    $threshold
                )
            );
        }
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\Design;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Node\MethodNode;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;

/**
 * This rule class detects possible development code fragments that were left
 * into the code.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @see https://github.com/phpmd/phpmd/issues/265
 * @since 2.3.0
 */
class DevelopmentCodeFragment extends AbstractRule implements MethodAware, FunctionAware
{
    /**
     * This method checks if a given function or method contains an eval-expression
     * and emits a rule violation when it exists.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        foreach ($node->findChildrenOfType('FunctionPostfix') as $postfix) {
            $image = strtolower($postfix->getImage());
            if (false === in_array($image, $this->getSuspectImages())) {
                continue;
            }

            $image = $node->getImage();
            if ($node instanceof MethodNode) {
                $image = sprintf('%s::%s', $node->getParentName(), $node->getImage());
            }

            $this->addViolation($postfix, array($node->getType(), $image, $postfix->getImage()));
        }
    }

    /**
     * Returns an array with function images that are normally only used during
     * development.
     *
     * @return array
     */
    private function getSuspectImages()
    {
        return array_map(
            'strtolower',
            array_map(
                'trim',
                explode(
                    ',',
                    $this->getStringProperty('unwanted-functions')
                )
            )
        );
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\Design;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;

/**
 * This rule will check the NPath-complexity of a method or function against the
 * configured threshold.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class NpathComplexity extends AbstractRule implements FunctionAware, MethodAware
{
    /**
     * This method checks the acyclic complexity for the given node against a
     * configured threshold.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $threshold = $this->getIntProperty('minimum');
        $npath = $node->getMetric('npath');
        if ($npath < $threshold) {
            return;
        }

        $this->addViolation(
            $node,
            array(
                $node->getType(),
                $node->getName(),
                $npath,
                $threshold
            )
        );
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\Design;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;

/**
 * This rule class will detect all classes with too much fields.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class TooManyFields extends AbstractRule implements ClassAware
{
    /**
     * This method checks the number of methods with in a given class and checks
     * this number against a configured threshold.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $threshold = $this->getIntProperty('maxfields');
        $vars = $node->getMetric('vars');
        if ($vars <= $threshold) {
            return;
        }
        $this->addViolation(
            $node,
            array(
                $node->getType(),
                $node->getName(),
                $vars,
                $threshold
            )
        );
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\Design;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;

/**
 * This rule class detects the usage of PHP's eval-expression.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class EvalExpression extends AbstractRule implements MethodAware, FunctionAware
{
    /**
     * This method checks if a given function or method contains an eval-expression
     * and emits a rule violation when it exists.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        foreach ($node->findChildrenOfType('EvalExpression') as $eval) {
            $this->addViolation($eval, array($node->getType(), $node->getName()));
        }
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\Design;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;

/**
 * This rule class detects the usage of PHP's exit statement.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ExitExpression extends AbstractRule implements MethodAware, FunctionAware
{
    /**
     * This method checks if a given function or method contains an exit-expression
     * and emits a rule violation when it exists.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        foreach ($node->findChildrenOfType('ExitExpression') as $exit) {
            $this->addViolation($exit, array($node->getType(), $node->getName()));
        }
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since      1.1.0
 */

namespace PHPMD\Rule\Design;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;

/**
 * This rule class detects violations of Coupling Between Objects metric.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since      1.1.0
 */
class CouplingBetweenObjects extends AbstractRule implements ClassAware
{
    /**
     * This method should implement the violation analysis algorithm of concrete
     * rule implementations. All extending classes must implement this method.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $cbo = $node->getMetric('cbo');
        if ($cbo >= ($threshold = $this->getIntProperty('minimum'))) {
            $this->addViolation($node, array($node->getName(), $cbo, $threshold));
        }
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\Design;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;

/**
 * This rule will detect classes that are to deep in the inheritance tree.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class DepthOfInheritance extends AbstractRule implements ClassAware
{
    /**
     * This method checks the number of parents for the given class
     * node.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        try {
            $threshold = $this->getIntProperty('maximum');
            $comparision = 1;
        } catch (\OutOfBoundsException $e) {
            $threshold = $this->getIntProperty('minimum');
            $comparision = 2;
        }
        
        $dit = $node->getMetric('dit');
        if (($comparision === 1 && $dit > $threshold) ||
            ($comparision === 2 && $dit >= $threshold)
        ) {
            $this->addViolation(
                $node,
                array(
                    $node->getType(),
                    $node->getName(),
                    $dit,
                    $threshold
                )
            );
        }
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since      1.1.0
 */

namespace PHPMD\Rule\Design;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;

/**
 * This rule class detects the usage of PHP's goto statement.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since      1.1.0
 */
class GotoStatement extends AbstractRule implements MethodAware, FunctionAware
{
    /**
     * This method should implement the violation analysis algorithm of concrete
     * rule implementations. All extending classes must implement this method.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        foreach ($node->findChildrenOfType('GotoStatement') as $goto) {
            $this->addViolation($goto, array($node->getType(), $node->getName()));
        }
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule;

/**
 * This interface marks a rule implementation as method aware,
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface MethodAware
{
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;

/**
 * This rule checks a given method or function against the configured cyclomatic
 * complexity threshold.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class CyclomaticComplexity extends AbstractRule implements FunctionAware, MethodAware
{
    /**
     * This method checks the cyclomatic complexity for the given node against
     * a configured threshold.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $threshold = $this->getIntProperty('reportLevel');
        $ccn = $node->getMetric('ccn2');
        if ($ccn < $threshold) {
            return;
        }

        $this->addViolation(
            $node,
            array(
                $node->getType(),
                $node->getName(),
                $ccn,
                $threshold
            )
        );
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\Naming;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;

/**
 * This rule class will detect variables, parameters and properties with really
 * long names.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class LongVariable extends AbstractRule implements ClassAware, MethodAware, FunctionAware
{
    /**
     * Temporary map holding variables that were already processed in the
     * current context.
     *
     * @var array(string=>boolean)
     */
    private $processedVariables = array();

    /**
     * Extracts all variable and variable declarator nodes from the given node
     * and checks the variable name length against the configured maximum
     * length.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $this->resetProcessed();

        if ($node->getType() === 'class') {
            $fields = $node->findChildrenOfType('FieldDeclaration');
            foreach ($fields as $field) {
                if ($field->isPrivate()) {
                    continue;
                }

                $declarators = $field->findChildrenOfType('VariableDeclarator');
                foreach ($declarators as $declarator) {
                    $this->checkNodeImage($declarator);
                }
            }
        } else {
            $declarators = $node->findChildrenOfType('VariableDeclarator');
            foreach ($declarators as $declarator) {
                $this->checkNodeImage($declarator);
            }

            $variables = $node->findChildrenOfType('Variable');
            foreach ($variables as $variable) {
                $this->checkNodeImage($variable);
            }
        }

        $this->resetProcessed();
    }

    /**
     * Checks if the variable name of the given node is smaller/equal to the
     * configured threshold.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    protected function checkNodeImage(AbstractNode $node)
    {
        if ($this->isNotProcessed($node)) {
            $this->addProcessed($node);
            $this->checkMaximumLength($node);
        }
    }

    /**
     * Template method that performs the real node image check.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    protected function checkMaximumLength(AbstractNode $node)
    {
        $threshold = $this->getIntProperty('maximum');
        if ($threshold >= strlen($node->getImage()) - 1) {
            return;
        }
        if ($this->isNameAllowedInContext($node)) {
            return;
        }
        $this->addViolation($node, array($node->getImage(), $threshold));
    }

    /**
     * Checks if a short name is acceptable in the current context. For the
     * moment the only context is a static member.
     *
     * @param \PHPMD\AbstractNode $node
     * @return boolean
     */
    private function isNameAllowedInContext(AbstractNode $node)
    {
        return $this->isChildOf($node, 'MemberPrimaryPrefix');
    }

    /**
     * Checks if the given node is a direct or indirect child of a node with
     * the given type.
     *
     * @param \PHPMD\AbstractNode $node
     * @param string $type
     * @return boolean
     */
    private function isChildOf(AbstractNode $node, $type)
    {
        $parent = $node->getParent();
        while (is_object($parent)) {
            if ($parent->isInstanceOf($type)) {
                return true;
            }
            $parent = $parent->getParent();
        }
        return false;
    }

    /**
     * Resets the already processed nodes.
     *
     * @return void
     */
    protected function resetProcessed()
    {
        $this->processedVariables = array();
    }

    /**
     * Flags the given node as already processed.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    protected function addProcessed(AbstractNode $node)
    {
        $this->processedVariables[$node->getImage()] = true;
    }

    /**
     * Checks if the given node was already processed.
     *
     * @param \PHPMD\AbstractNode $node
     * @return boolean
     */
    protected function isNotProcessed(AbstractNode $node)
    {
        return !isset($this->processedVariables[$node->getImage()]);
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license    http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\Naming;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;
use PHPMD\Rule\InterfaceAware;

/**
 * This rule detects class/interface constants that do not follow the upper
 * case convention.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ConstantNamingConventions extends AbstractRule implements ClassAware, InterfaceAware
{
    /**
     * Extracts all constant declarations from the given node and tests that
     * the image only contains upper case characters.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        foreach ($node->findChildrenOfType('ConstantDeclarator') as $declarator) {
            if ($declarator->getImage() !== strtoupper($declarator->getImage())) {
                $this->addViolation($declarator, array($declarator->getImage()));
            }
        }
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license    http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\Naming;

use PDepend\Source\AST\ASTTrait;
use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Node\InterfaceNode;
use PHPMD\Rule\MethodAware;

/**
 * This rule class will detect methods that define a php4 style constructor
 * method while has the same name as the enclosing class.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ConstructorWithNameAsEnclosingClass extends AbstractRule implements MethodAware
{
    /**
     * Is method has the same name as the enclosing class
     * (php4 style constructor).
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        if ($node->getNode()->getParent() instanceof ASTTrait) {
            return;
        }
        if (strcasecmp($node->getName(), $node->getParentName()) !== 0) {
            return;
        }
        if ($node->getParentType() instanceof InterfaceNode) {
            return;
        }
        if ($node->getNamespaceName() !== '+global') {
            return;
        }

        $this->addViolation($node);
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\Naming;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;

/**
 * This rule class will detect methods and functions with very short names.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ShortMethodName extends AbstractRule implements MethodAware, FunctionAware
{
    /**
     * Extracts all variable and variable declarator nodes from the given node
     * and checks the variable name length against the configured minimum
     * length.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $threshold = $this->getIntProperty('minimum');
        if ($threshold <= strlen($node->getName())) {
            return;
        }

        $exceptions = $this->getExceptionsList();

        if (in_array($node->getName(), $exceptions)) {
            return;
        }

        $this->addViolation(
            $node,
            array(
                $node->getParentName(),
                $node->getName(),
                $threshold
            )
        );
    }

    /**
     * Gets array of exceptions from property
     *
     * @return array
     */
    private function getExceptionsList()
    {
        try {
            $exceptions = $this->getStringProperty('exceptions');
        } catch (\OutOfBoundsException $e) {
            $exceptions = '';
        }

        return explode(',', $exceptions);
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license    http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\Naming;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Node\MethodNode;
use PHPMD\Rule\MethodAware;

/**
 * This rule tests that a method which returns a boolean value does not start
 * with <b>get</b> or <b>_get</b> for a getter.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license    http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class BooleanGetMethodName extends AbstractRule implements MethodAware
{
    /**
     * Extracts all variable and variable declarator nodes from the given node
     * and checks the variable name length against the configured minimum
     * length.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        if ($this->isBooleanGetMethod($node)) {
            $this->addViolation($node, array($node->getImage()));
        }
    }

    /**
     * Tests if the given method matches all criteria to be an invalid
     * boolean get method.
     *
     * @param \PHPMD\Node\MethodNode $node
     * @return boolean
     */
    private function isBooleanGetMethod(MethodNode $node)
    {
        return $this->isGetterMethodName($node)
                && $this->isReturnTypeBoolean($node)
                && $this->isParameterizedOrIgnored($node);
    }

    /**
     * Tests if the given method starts with <b>get</b> or <b>_get</b>.
     *
     * @param \PHPMD\Node\MethodNode $node
     * @return boolean
     */
    private function isGetterMethodName(MethodNode $node)
    {
        return (preg_match('(^_?get)i', $node->getImage()) > 0);
    }

    /**
     * Tests if the given method is declared with return type boolean.
     *
     * @param \PHPMD\Node\MethodNode $node
     * @return boolean
     */
    private function isReturnTypeBoolean(MethodNode $node)
    {
        $comment = $node->getDocComment();
        return (preg_match('(\*\s*@return\s+bool(ean)?\s)i', $comment) > 0);
    }

    /**
     * Tests if the property <b>$checkParameterizedMethods</b> is set to <b>true</b>
     * or has no parameters.
     *
     * @param \PHPMD\Node\MethodNode $node
     * @return boolean
     */
    private function isParameterizedOrIgnored(MethodNode $node)
    {
        if ($this->getBooleanProperty('checkParameterizedMethods')) {
            return $node->getParameterCount() === 0;
        }
        return true;
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\Naming;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;

/**
 * This rule class will detect variables, parameters and properties with short
 * names.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ShortVariable extends AbstractRule implements ClassAware, MethodAware, FunctionAware
{
    /**
     * Temporary map holding variables that were already processed in the
     * current context.
     *
     * @var array(string=>boolean)
     */
    private $processedVariables = array();

    /**
     * Extracts all variable and variable declarator nodes from the given node
     * and checks the variable name length against the configured minimum
     * length.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $this->resetProcessed();

        if ($node->getType() === 'class') {
            $fields = $node->findChildrenOfType('FieldDeclaration');
            foreach ($fields as $field) {
                $declarators = $field->findChildrenOfType('VariableDeclarator');
                foreach ($declarators as $declarator) {
                    $this->checkNodeImage($declarator);
                }
            }
        } else {
            $declarators = $node->findChildrenOfType('VariableDeclarator');
            foreach ($declarators as $declarator) {
                $this->checkNodeImage($declarator);
            }

            $variables = $node->findChildrenOfType('Variable');
            foreach ($variables as $variable) {
                $this->checkNodeImage($variable);
            }
        }

        $this->resetProcessed();
    }

    /**
     * Checks if the variable name of the given node is greater/equal to the
     * configured threshold or if the given node is an allowed context.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    protected function checkNodeImage(AbstractNode $node)
    {
        if ($this->isNotProcessed($node)) {
            $this->addProcessed($node);
            $this->checkMinimumLength($node);
        }
    }

    /**
     * Template method that performs the real node image check.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    protected function checkMinimumLength(AbstractNode $node)
    {
        $threshold = $this->getIntProperty('minimum');

        if ($threshold <= strlen($node->getImage()) - 1) {
            return;
        }

        if ($this->isNameAllowedInContext($node)) {
            return;
        }

        $exceptions = $this->getExceptionsList();

        if (in_array(substr($node->getImage(), 1), $exceptions)) {
            return;
        }

        $this->addViolation($node, array($node->getImage(), $threshold));
    }

    /**
     * Gets array of exceptions from property
     *
     * @return array
     */
    private function getExceptionsList()
    {
        try {
            $exceptions = $this->getStringProperty('exceptions');
        } catch (\OutOfBoundsException $e) {
            $exceptions = '';
        }

        return explode(',', $exceptions);
    }

    /**
     * Checks if a short name is acceptable in the current context. For the
     * moment these contexts are the init section of a for-loop and short
     * variable names in catch-statements.
     *
     * @param \PHPMD\AbstractNode $node
     * @return boolean
     */
    private function isNameAllowedInContext(AbstractNode $node)
    {
        return $this->isChildOf($node, 'CatchStatement')
                || $this->isChildOf($node, 'ForInit')
                || $this->isChildOf($node, 'ForeachStatement')
                || $this->isChildOf($node, 'MemberPrimaryPrefix');
    }

    /**
     * Checks if the given node is a direct or indirect child of a node with
     * the given type.
     *
     * @param \PHPMD\AbstractNode $node
     * @param string $type
     * @return boolean
     */
    private function isChildOf(AbstractNode $node, $type)
    {
        $parent = $node->getParent();
        while (is_object($parent)) {
            if ($parent->isInstanceOf($type)) {
                return true;
            }
            $parent = $parent->getParent();
        }
        return false;
    }

    /**
     * Resets the already processed nodes.
     *
     * @return void
     */
    protected function resetProcessed()
    {
        $this->processedVariables = array();
    }

    /**
     * Flags the given node as already processed.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    protected function addProcessed(AbstractNode $node)
    {
        $this->processedVariables[$node->getImage()] = true;
    }

    /**
     * Checks if the given node was already processed.
     *
     * @param \PHPMD\AbstractNode $node
     * @return boolean
     */
    protected function isNotProcessed(AbstractNode $node)
    {
        return !isset($this->processedVariables[$node->getImage()]);
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Node\ASTNode;
use PHPMD\Node\ClassNode;
use PHPMD\Node\MethodNode;

/**
 * This rule collects all private methods in a class that aren't used in any
 * method of the analyzed class.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class UnusedPrivateMethod extends AbstractRule implements ClassAware
{
    /**
     * This method checks that all private class methods are at least accessed
     * by one method.
     *
     * @param \PHPMD\AbstractNode $class
     * @return void
     */
    public function apply(AbstractNode $class)
    {
        foreach ($this->collectUnusedPrivateMethods($class) as $node) {
            $this->addViolation($node, array($node->getImage()));
        }
    }

    /**
     * This method collects all methods in the given class that are declared
     * as private and are not used in the same class' context.
     *
     * @param \PHPMD\Node\ClassNode $class
     * @return \PHPMD\AbstractNode[]
     */
    private function collectUnusedPrivateMethods(ClassNode $class)
    {
        $methods = $this->collectPrivateMethods($class);
        return $this->removeUsedMethods($class, $methods);
    }

    /**
     * Collects all private methods declared in the given class node.
     *
     * @param \PHPMD\Node\ClassNode $class
     * @return \PHPMD\AbstractNode[]
     */
    private function collectPrivateMethods(ClassNode $class)
    {
        $methods = array();
        foreach ($class->getMethods() as $method) {
            if ($this->acceptMethod($class, $method)) {
                $methods[strtolower($method->getImage())] = $method;
            }
        }
        return $methods;
    }

    /**
     * Returns <b>true</b> when the given method should be used for this rule's
     * analysis.
     *
     * @param \PHPMD\Node\ClassNode $class
     * @param \PHPMD\Node\MethodNode $method
     * @return boolean
     */
    private function acceptMethod(ClassNode $class, MethodNode $method)
    {
        return (
            $method->isPrivate() &&
            false === $method->hasSuppressWarningsAnnotationFor($this) &&
            strcasecmp($method->getImage(), $class->getImage()) !== 0 &&
            strcasecmp($method->getImage(), '__construct') !== 0 &&
            strcasecmp($method->getImage(), '__destruct') !== 0 &&
            strcasecmp($method->getImage(), '__clone') !== 0
        );
    }

    /**
     * This method removes all used methods from the given methods array.
     *
     * @param \PHPMD\Node\ClassNode $class
     * @param \PHPMD\Node\MethodNode[] $methods
     * @return \PHPMD\AbstractNode[]
     */
    private function removeUsedMethods(ClassNode $class, array $methods)
    {
        foreach ($class->findChildrenOfType('MethodPostfix') as $postfix) {
            if ($this->isClassScope($class, $postfix)) {
                unset($methods[strtolower($postfix->getImage())]);
            }
        }
        return $methods;
    }

    /**
     * This method checks that the given method postfix is accessed on an
     * instance or static reference to the given class.
     *
     * @param \PHPMD\Node\ClassNode $class
     * @param \PHPMD\Node\ASTNode $postfix
     * @return boolean
     */
    private function isClassScope(ClassNode $class, ASTNode $postfix)
    {
        $owner = $postfix->getParent()->getChild(0);
        return (
        $owner->isInstanceOf('MethodPostfix') ||
            $owner->isInstanceOf('SelfReference') ||
            $owner->isInstanceOf('StaticReference') ||
            strcasecmp($owner->getImage(), '$this') === 0 ||
            strcasecmp($owner->getImage(), $class->getImage()) === 0
        );
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule;

use PHPMD\AbstractNode;
use PHPMD\Node\AbstractCallableNode;
use PHPMD\Node\ASTNode;

/**
 * This rule collects all local variables within a given function or method
 * that are not used by any code in the analyzed source artifact.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class UnusedLocalVariable extends AbstractLocalVariable implements FunctionAware, MethodAware
{
    /**
     * Found variable images within a single method or function.
     *
     * @var array(string)
     */
    private $images = array();

    /**
     * This method checks that all local variables within the given function or
     * method are used at least one time.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $this->images = array();

        $this->collectVariables($node);
        $this->removeParameters($node);

        foreach ($this->images as $nodes) {
            if (count($nodes) === 1) {
                $this->doCheckNodeImage($nodes[0]);
            }
        }
    }

    /**
     * This method removes all variables from the <b>$_images</b> property that
     * are also found in the formal parameters of the given method or/and
     * function node.
     *
     * @param \PHPMD\Node\AbstractCallableNode $node
     * @return void
     */
    private function removeParameters(AbstractCallableNode $node)
    {
        // Get formal parameter container
        $parameters = $node->getFirstChildOfType('FormalParameters');

        // Now get all declarators in the formal parameters container
        $declarators = $parameters->findChildrenOfType('VariableDeclarator');

        foreach ($declarators as $declarator) {
            unset($this->images[$declarator->getImage()]);
        }
    }

    /**
     * This method collects all local variable instances from the given
     * method/function node and stores their image in the <b>$_images</b>
     * property.
     *
     *
     * @param \PHPMD\Node\AbstractCallableNode $node
     * @return void
     */
    private function collectVariables(AbstractCallableNode $node)
    {
        foreach ($node->findChildrenOfType('Variable') as $variable) {
            if ($this->isLocal($variable)) {
                $this->collectVariable($variable);
            }
        }
        foreach ($node->findChildrenOfType('VariableDeclarator') as $variable) {
            $this->collectVariable($variable);
        }
        foreach ($node->findChildrenOfType('FunctionPostfix') as $func) {
            if ($this->isFunctionNameEndingWith($func, 'compact')) {
                foreach ($func->findChildrenOfType('Literal') as $literal) {
                    $this->collectLiteral($literal);
                }
            }
        }
    }

    /**
     * Stores the given variable node in an internal list of found variables.
     *
     * @param \PHPMD\Node\ASTNode $node
     * @return void
     */
    private function collectVariable(ASTNode $node)
    {
        if (!isset($this->images[$node->getImage()])) {
            $this->images[$node->getImage()] = array();
        }
        $this->images[$node->getImage()][] = $node;
    }

    /**
     * Stores the given literal node in an internal list of found variables.
     *
     * @param \PHPMD\Node\ASTNode $node
     * @return void
     */
    private function collectLiteral(ASTNode $node)
    {
        $variable = '$' . trim($node->getImage(), '\'');
        if (!isset($this->images[$variable])) {
            $this->images[$variable] = array();
        }
        $this->images[$variable][] = $node;
    }

    /**
     * Template method that performs the real node image check.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    protected function doCheckNodeImage(AbstractNode $node)
    {
        if ($this->isNameAllowedInContext($node)) {
            return;
        }
        if ($this->isUnusedForeachVariableAllowed($node)) {
            return;
        }
        $this->addViolation($node, array($node->getImage()));
    }

    /**
     * Checks if a short name is acceptable in the current context. For the
     * moment these contexts are the init section of a for-loop and short
     * variable names in catch-statements.
     *
     * @param \PHPMD\AbstractNode $node
     * @return boolean
     */
    private function isNameAllowedInContext(AbstractNode $node)
    {
        return $this->isChildOf($node, 'CatchStatement');
    }

    /**
     * Checks if an unused foreach variable (key or variable) is allowed.
     *
     * If it's not a foreach variable, it returns always false.
     *
     * @param \PHPMD\Node\ASTNode $variable The variable to check.
     * @return bool True if allowed, else false.
     */
    private function isUnusedForeachVariableAllowed(ASTNode $variable)
    {
        $isForeachVariable = $this->isChildOf($variable, 'ForeachStatement');
        if (!$isForeachVariable) {
            return false;
        }

        return $this->getBooleanProperty('allow-unused-foreach-variables');
    }

    /**
     * Checks if the given node is a direct or indirect child of a node with
     * the given type.
     *
     * @param \PHPMD\AbstractNode $node
     * @param string $type
     * @return boolean
     */
    private function isChildOf(AbstractNode $node, $type)
    {
        $parent = $node->getParent();
        
        return $parent->isInstanceOf($type);
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since      0.2.6
 */

namespace PHPMD\Rule;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Node\ASTNode;

/**
 * Base class for rules that rely on local variables.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since     0.2.6
 */
abstract class AbstractLocalVariable extends AbstractRule
{
    /**
     * PHP super globals that are available in all php scopes, so that they
     * can never be unused local variables.
     *
     * @var array(string=>boolean)
     */
    private static $superGlobals = array(
        '$argc'                => true,
        '$argv'                => true,
        '$_COOKIE'             => true,
        '$_ENV'                => true,
        '$_FILES'              => true,
        '$_GET'                => true,
        '$_POST'               => true,
        '$_REQUEST'            => true,
        '$_SERVER'             => true,
        '$_SESSION'            => true,
        '$GLOBALS'             => true,
        '$HTTP_RAW_POST_DATA'  => true,
    );

    /**
     * Tests if the given variable node represents a local variable or if it is
     * a static object property or something similar.
     *
     * @param \PHPMD\Node\ASTNode $variable The variable to check.
     * @return boolean
     */
    protected function isLocal(ASTNode $variable)
    {
        return (false === $variable->isThis()
            && $this->isNotSuperGlobal($variable)
            && $this->isRegularVariable($variable)
        );
    }

    /**
     * Tests if the given variable represents one of the PHP super globals
     * that are available in scopes.
     *
     * @param \PHPMD\AbstractNode $variable
     * @return boolean
     */
    protected function isNotSuperGlobal(AbstractNode $variable)
    {
        return !isset(self::$superGlobals[$variable->getImage()]);
    }

    /**
     * Tests if the given variable node is a regular variable an not property
     * or method postfix.
     *
     * @param \PHPMD\Node\ASTNode $variable
     * @return boolean
     */
    protected function isRegularVariable(ASTNode $variable)
    {
        $node   = $this->stripWrappedIndexExpression($variable);
        $parent = $node->getParent();

        if ($parent->isInstanceOf('PropertyPostfix')) {
            $primaryPrefix = $parent->getParent();
            if ($primaryPrefix->getParent()->isInstanceOf('MemberPrimaryPrefix')) {
                return !$primaryPrefix->getParent()->isStatic();
            }
            return ($parent->getChild(0)->getNode() !== $node->getNode()
                || !$primaryPrefix->isStatic()
            );
        }
        return true;
    }

    /**
     * Removes all index expressions that are wrapped around the given node
     * instance.
     *
     * @param \PHPMD\Node\ASTNode $node
     * @return \PHPMD\Node\ASTNode
     */
    protected function stripWrappedIndexExpression(ASTNode $node)
    {
        if (false === $this->isWrappedByIndexExpression($node)) {
            return $node;
        }

        $parent = $node->getParent();
        if ($parent->getChild(0)->getNode() === $node->getNode()) {
            return $this->stripWrappedIndexExpression($parent);
        }
        return $node;
    }

    /**
     * Tests if the given variable node os part of an index expression.
     *
     * @param \PHPMD\Node\ASTNode $node
     * @return boolean
     */
    protected function isWrappedByIndexExpression(ASTNode $node)
    {
        return ($node->getParent()->isInstanceOf('ArrayIndexExpression')
            || $node->getParent()->isInstanceOf('StringIndexExpression')
        );
    }

    /**
     * PHP is case insensitive so we should compare function names case
     * insensitive.
     *
     * @param \PHPMD\AbstractNode $node
     * @param string $name
     * @return boolean
     */
    protected function isFunctionNameEqual(AbstractNode $node, $name)
    {
        return (0 === strcasecmp(trim($node->getImage(), '\\'), $name));
    }

    /**
     * AST puts namespace prefix to global functions called from a namespace.
     * This method checks if the last part of function fully qualified name is equal to $name
     *
     * @param \PHPMD\AbstractNode $node
     * @param string $name
     * @return boolean
     */
    protected function isFunctionNameEndingWith(AbstractNode $node, $name)
    {
        $parts = explode('\\', trim($node->getImage(), '\\'));

        return (0 === strcasecmp(array_pop($parts), $name));
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;

/**
 * This rule checks the number of public methods and fields in a given class.
 * Then it compares the number of public members against a configured threshold.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ExcessivePublicCount extends AbstractRule implements ClassAware
{
    /**
     * This method checks the number of public fields and methods in the given
     * class and checks that value against a configured threshold.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $threshold = $this->getIntProperty('minimum');
        $cis = $node->getMetric('cis');
        if ($cis < $threshold) {
            return;
        }
        $this->addViolation(
            $node,
            array(
                $node->getType(),
                $node->getName(),
                $cis,
                $threshold
            )
        );
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since      1.1.0
 */

namespace PHPMD\Rule\Controversial;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;

/**
 * This rule class detects the usage of superglobals.
 *
 * @author     Francis Besset <francis.besset@gmail.com>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since      1.1.0
 */
class Superglobals extends AbstractRule implements MethodAware, FunctionAware
{
    protected $superglobals = array(
        '$GLOBALS',
        '$_SERVER',  '$HTTP_SERVER_VARS',
        '$_GET',     '$HTTP_GET_VARS',
        '$_POST',    '$HTTP_POST_VARS',
        '$_FILES',   '$HTTP_POST_FILES',
        '$_COOKIE',  '$HTTP_COOKIE_VARS',
        '$_SESSION', '$HTTP_SESSION_VARS',
        '$_REQUEST',
        '$_ENV',     '$HTTP_ENV_VARS',
    );

    /**
     * This method checks if a superglobal is used
     * and emits a rule violation.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        foreach ($node->findChildrenOfType('Variable') as $variable) {
            if (in_array($variable->getImage(), $this->superglobals)) {
                $this->addViolation(
                    $node,
                    array(
                        $node->getName(),
                        $variable->getImage()
                    )
                );
            }
        }
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since      1.1.0
 */

namespace PHPMD\Rule\Controversial;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;

/**
 * This rule class detects properties not named in camelCase.
 *
 * @author     Francis Besset <francis.besset@gmail.com>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since      1.1.0
 */
class CamelCasePropertyName extends AbstractRule implements ClassAware
{
    /**
     * This method checks if a property is not named in camelCase
     * and emits a rule violation.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $allowUnderscore = $this->getBooleanProperty('allow-underscore');

        $pattern = '/^\$[a-zA-Z][a-zA-Z0-9]*$/';
        if ($allowUnderscore == true) {
            $pattern = '/^\$[_]?[a-zA-Z][a-zA-Z0-9]*$/';
        }

        foreach ($node->getProperties() as $property) {
            $propertyName = $property->getName();

            if (!preg_match($pattern, $propertyName)) {
                $this->addViolation(
                    $node,
                    array(
                        $propertyName,
                    )
                );
            }
        }
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since      1.1.0
 */

namespace PHPMD\Rule\Controversial;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;

/**
 * This rule class detects parameters not named in camelCase.
 *
 * @author     Francis Besset <francis.besset@gmail.com>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since      1.1.0
 */
class CamelCaseParameterName extends AbstractRule implements MethodAware, FunctionAware
{
    /**
     * This method checks if a parameter is not named in camelCase
     * and emits a rule violation.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        foreach ($node->getParameters() as $parameter) {
            if (!preg_match('/^\$[a-z][a-zA-Z0-9]*$/', $parameter->getName())) {
                $this->addViolation(
                    $node,
                    array(
                        $parameter->getName(),
                    )
                );
            }
        }
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since      1.1.0
 */

namespace PHPMD\Rule\Controversial;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\MethodAware;

/**
 * This rule class detects methods not named in camelCase.
 *
 * @author    Francis Besset <francis.besset@gmail.com>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since     1.1.0
 */
class CamelCaseMethodName extends AbstractRule implements MethodAware
{
    protected $ignoredMethods = array(
        '__construct',
        '__destruct',
        '__set',
        '__get',
        '__call',
        '__callStatic',
        '__isset',
        '__unset',
        '__sleep',
        '__wakeup',
        '__toString',
        '__invoke',
        '__set_state',
        '__clone',
        '__debugInfo',
    );

    /**
     * This method checks if a method is not named in camelCase
     * and emits a rule violation.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $methodName = $node->getName();
        if (!in_array($methodName, $this->ignoredMethods)) {
            if (!$this->isValid($methodName)) {
                $this->addViolation(
                    $node,
                    array(
                        $methodName,
                    )
                );
            }
        }
    }

    private function isValid($methodName)
    {
        if ($this->getBooleanProperty('allow-underscore-test') && strpos($methodName, 'test') === 0) {
            return preg_match('/^test[a-zA-Z0-9]*([_][a-z][a-zA-Z0-9]*)?$/', $methodName);
        }

        if ($this->getBooleanProperty('allow-underscore')) {
            return preg_match('/^[_]?[a-z][a-zA-Z0-9]*$/', $methodName);
        }

        return preg_match('/^[a-z][a-zA-Z0-9]*$/', $methodName);
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since      1.1.0
 */

namespace PHPMD\Rule\Controversial;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;

/**
 * This rule class detects variables not named in camelCase.
 *
 * @author     Francis Besset <francis.besset@gmail.com>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since      1.1.0
 */
class CamelCaseVariableName extends AbstractRule implements MethodAware, FunctionAware
{
    /**
     * @var array
     */
    private $exceptions = array(
        '$php_errormsg',
        '$http_response_header',
        '$GLOBALS',
        '$_SERVER',
        '$_GET',
        '$_POST',
        '$_FILES',
        '$_COOKIE',
        '$_SESSION',
        '$_REQUEST',
        '$_ENV',
    );

    /**
     * This method checks if a variable is not named in camelCase
     * and emits a rule violation.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        foreach ($node->findChildrenOfType('Variable') as $variable) {
            $image = $variable->getImage();

            if (in_array($image, $this->exceptions)) {
                continue;
            }

            if (preg_match('/^\$[a-z][a-zA-Z0-9]*$/', $image)) {
                continue;
            }

            if ($variable->getParent()->isInstanceOf('PropertyPostfix')) {
                continue;
            }

            $this->addViolation($node, array($image));
        }
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since      1.1.0
 */

namespace PHPMD\Rule\Controversial;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;
use PHPMD\Rule\InterfaceAware;

/**
 * This rule class detects classes not named in CamelCase.
 *
 * @author     Francis Besset <francis.besset@gmail.com>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since      1.1.0
 */
class CamelCaseClassName extends AbstractRule implements ClassAware, InterfaceAware
{
    /**
     * This method checks if a class is not named in CamelCase
     * and emits a rule violation.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        if (!preg_match('/^[A-Z][a-zA-Z0-9]*$/', $node->getName())) {
            $this->addViolation(
                $node,
                array(
                    $node->getName(),
                )
            );
        }
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Node\ASTNode;
use PHPMD\Node\ClassNode;

/**
 * This rule collects all private fields in a class that aren't used in any
 * method of the analyzed class.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class UnusedPrivateField extends AbstractRule implements ClassAware
{
    /**
     * Collected private fields/variable declarators in the currently processed
     * class.
     *
     * @var \PHPMD\Node\ASTNode[]
     */
    private $fields = array();

    /**
     * This method checks that all private class properties are at least accessed
     * by one method.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        foreach ($this->collectUnusedPrivateFields($node) as $field) {
            $this->addViolation($field, array($field->getImage()));
        }
    }

    /**
     * This method collects all private fields that aren't used by any class
     * method.
     *
     * @param \PHPMD\Node\ClassNode $class
     * @return \PHPMD\AbstractNode[]
     */
    private function collectUnusedPrivateFields(ClassNode $class)
    {
        $this->fields = array();

        $this->collectPrivateFields($class);
        $this->removeUsedFields($class);

        return $this->fields;
    }

    /**
     * This method collects all private fields in the given class and stores
     * them in the <b>$_fields</b> property.
     *
     * @param \PHPMD\Node\ClassNode $class
     * @return void
     */
    private function collectPrivateFields(ClassNode $class)
    {
        foreach ($class->findChildrenOfType('FieldDeclaration') as $declaration) {
            if ($declaration->isPrivate()) {
                $this->collectPrivateField($declaration);
            }
        }
    }

    /**
     * This method extracts all variable declarators from the given field
     * declaration and stores them in the <b>$_fields</b> property.
     *
     * @param \PHPMD\Node\ASTNode $declaration
     * @return void
     */
    private function collectPrivateField(ASTNode $declaration)
    {
        $fields = $declaration->findChildrenOfType('VariableDeclarator');
        foreach ($fields as $field) {
            $this->fields[$field->getImage()] = $field;
        }
    }

    /**
     * This method extracts all property postfix nodes from the given class and
     * removes all fields from the <b>$_fields</b> property that are accessed by
     * one of the postfix nodes.
     *
     * @param \PHPMD\Node\ClassNode $class
     * @return void
     */
    private function removeUsedFields(ClassNode $class)
    {
        foreach ($class->findChildrenOfType('PropertyPostfix') as $postfix) {
            if ($this->isInScopeOfClass($class, $postfix)) {
                $this->removeUsedField($postfix);
            }
        }
    }

    /**
     * This method removes the field from the <b>$_fields</b> property that is
     * accessed through the given property postfix node.
     *
     * @param \PHPMD\Node\ASTNode $postfix
     * @return void
     */
    private function removeUsedField(ASTNode $postfix)
    {
        $image = '$';
        $child = $postfix->getFirstChildOfType('Identifier');

        if ($postfix->getParent()->isStatic()) {
            $image = '';
            $child = $postfix->getFirstChildOfType('Variable');
        }

        if ($this->isValidPropertyNode($child)) {
            unset($this->fields[$image . $child->getImage()]);
        }
    }

    /**
     * Checks if the given node is a valid property node.
     *
     * @param \PHPMD\Node\ASTNode $node
     * @return boolean
     * @since 0.2.6
     */
    protected function isValidPropertyNode(ASTNode $node = null)
    {
        if ($node === null) {
            return false;
        }
        
        $parent = $node->getParent();
        while (!$parent->isInstanceOf('PropertyPostfix')) {
            if ($parent->isInstanceOf('CompoundVariable')) {
                return false;
            }
            $parent = $parent->getParent();
            if (is_null($parent)) {
                   return false;
            }
        }
        return true;
    }

    /**
     * This method checks that the given property postfix is accessed on an
     * instance or static reference to the given class.
     *
     * @param \PHPMD\Node\ClassNode $class
     * @param \PHPMD\Node\ASTNode $postfix
     * @return boolean
     */
    protected function isInScopeOfClass(ClassNode $class, ASTNode $postfix)
    {
        $owner = $postfix->getParent()->getChild(0);
        if ($owner->isInstanceOf('PropertyPostfix')) {
            $owner = $owner->getParent()->getParent()->getChild(0);
        }
        return (
            $owner->isInstanceOf('SelfReference') ||
            $owner->isInstanceOf('StaticReference') ||
            strcasecmp($owner->getImage(), '$this') === 0 ||
            strcasecmp($owner->getImage(), $class->getImage()) === 0
        );
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule;

/**
 * This interface marks a rule implementation as interface aware,
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface InterfaceAware
{
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\CleanCode;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Node\ASTNode;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;

/**
 * Check if there is an else expression somewhere in the method/function and
 * warn about it.
 *
 * Object Calisthenics teaches us, that an else expression can always be
 * avoided by simple guard clause or return statements.
 *
 * @author    Benjamin Eberlei <benjamin@qafoo.com>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ElseExpression extends AbstractRule implements MethodAware, FunctionAware
{
    /**
     * This method checks if a method/function uses an else expression and add a violation for each one found.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        foreach ($node->findChildrenOfType('ScopeStatement') as $scope) {
            $parent = $scope->getParent();

            if (false === $this->isIfOrElseIfStatement($parent)) {
                continue;
            }

            if (false === $this->isElseScope($scope, $parent)) {
                continue;
            }

            $this->addViolation($scope, array($node->getImage()));
        }
    }

    private function isElseScope($scope, ASTNode $parent)
    {
        return (
            count($parent->getChildren()) === 3 &&
            $scope->getNode() === $parent->getChild(2)->getNode()
        );
    }

    private function isIfOrElseIfStatement(ASTNode $parent)
    {
        return ($parent->getName() === "if" || $parent->getName() === "elseif");
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\CleanCode;

use PDepend\Source\AST\ASTClassOrInterfaceReference;
use PDepend\Source\AST\ASTMethodPostfix;
use PDepend\Source\AST\ASTParentReference;
use PDepend\Source\AST\ASTSelfReference;
use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;

/**
 * Check if static access is used in a method.
 *
 * Static access is known to cause hard dependencies between classes
 * and is a bad practice.
 *
 * @author    Benjamin Eberlei <benjamin@qafoo.com>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class StaticAccess extends AbstractRule implements MethodAware, FunctionAware
{
    /**
     * Method checks for use of static access and warns about it.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $exceptions = $this->getExceptionsList();
        $nodes = $node->findChildrenOfType('MemberPrimaryPrefix');

        foreach ($nodes as $methodCall) {
            if (!$this->isStaticMethodCall($methodCall)) {
                continue;
            }

            $className = $methodCall->getChild(0)->getNode()->getImage();
            if (in_array(trim($className, " \t\n\r\0\x0B\\"), $exceptions)) {
                continue;
            }

            $this->addViolation($methodCall, array($className, $node->getName()));
        }
    }

    private function isStaticMethodCall(AbstractNode $methodCall)
    {
        return $methodCall->getChild(0)->getNode() instanceof ASTClassOrInterfaceReference &&
               $methodCall->getChild(1)->getNode() instanceof ASTMethodPostfix &&
               !$this->isCallingParent($methodCall) &&
               !$this->isCallingSelf($methodCall);
    }

    private function isCallingParent(AbstractNode $methodCall)
    {
        return $methodCall->getChild(0)->getNode() instanceof ASTParentReference;
    }

    private function isCallingSelf(AbstractNode $methodCall)
    {
        return $methodCall->getChild(0)->getNode() instanceof ASTSelfReference;
    }

    /**
     * Gets array of exceptions from property
     *
     * @return array
     */
    private function getExceptionsList()
    {
        try {
            $exceptions = $this->getStringProperty('exceptions');
        } catch (\OutOfBoundsException $e) {
            $exceptions = '';
        }

        return array_map(
            function ($className) {
                return trim($className, " \t\n\r\0\x0B\\");
            },
            explode(',', $exceptions)
        );
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule\CleanCode;

use PDepend\Source\AST\ASTValue;
use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;

/**
 * Check for a boolean flag in the method/function signature.
 *
 * Boolean flags are signs for single responsibility principle violations.
 *
 * @author    Benjamin Eberlei <benjamin@qafoo.com>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class BooleanArgumentFlag extends AbstractRule implements MethodAware, FunctionAware
{
    /**
     * This method checks if a method/function has boolean flag arguments and warns about them.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        foreach ($node->findChildrenOfType('FormalParameter') as $param) {
            $declarator = $param->getFirstChildOfType('VariableDeclarator');
            $value = $declarator->getValue();

            if (false === $this->isBooleanValue($value)) {
                continue;
            }

            $this->addViolation($param, array($node->getImage(), $declarator->getImage()));
        }
    }

    private function isBooleanValue(ASTValue $value = null)
    {
        return $value && $value->isValueAvailable() && ($value->getValue() === true || $value->getValue() === false);
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule;

/**
 * This interface is used to mark a rule implementation as function aware.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface FunctionAware
{
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule;

use PHPMD\AbstractNode;
use PHPMD\Node\MethodNode;

/**
 * This rule collects all formal parameters of a given function or method that
 * are not used in a statement of the artifact's body.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class UnusedFormalParameter extends AbstractLocalVariable implements FunctionAware, MethodAware
{
    /**
     * Collected ast nodes.
     *
     * @var \PHPMD\Node\ASTNode[]
     */
    private $nodes = array();

    /**
     * This method checks that all parameters of a given function or method are
     * used at least one time within the artifacts body.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        if ($this->isAbstractMethod($node)) {
            return;
        }

        // Magic methods should be ignored as invalid declarations are picked up by PHP.
        if ($this->isMagicMethod($node)) {
            return;
        }

        if ($this->isInheritedSignature($node)) {
            return;
        }

        if ($this->isNotDeclaration($node)) {
            return;
        }

        $this->nodes = array();

        $this->collectParameters($node);
        $this->removeUsedParameters($node);

        foreach ($this->nodes as $node) {
            $this->addViolation($node, array($node->getImage()));
        }
    }

    /**
     * Returns <b>true</b> when the given node is an abstract method.
     *
     * @param \PHPMD\AbstractNode $node
     * @return boolean
     */
    private function isAbstractMethod(AbstractNode $node)
    {
        if ($node instanceof MethodNode) {
            return $node->isAbstract();
        }
        return false;
    }

    /**
     * Returns <b>true</b> when the given node is method with signature declared as inherited using
     * {@inheritdoc} annotation.
     *
     * @param \PHPMD\AbstractNode $node
     * @return boolean
     */
    private function isInheritedSignature(AbstractNode $node)
    {
        if ($node instanceof MethodNode) {
            return preg_match('/\@inheritdoc/i', $node->getDocComment());
        }
        return false;
    }

    /**
     * Returns <b>true</b> when the given node is a magic method signature
     * @param AbstractNode $node
     * @return boolean
     */
    private function isMagicMethod(AbstractNode $node)
    {
        static $names = array(
                'call',
                'callStatic',
                'get',
                'set',
                'isset',
                'unset',
                'set_state'
        );

        if ($node instanceof MethodNode) {
            return preg_match('/\__(?:' . implode("|", $names) . ')/i', $node->getName());
        }
        return false;
    }

    /**
     * Tests if the given <b>$node</b> is a method and if this method is also
     * the initial declaration.
     *
     * @param \PHPMD\AbstractNode $node
     * @return boolean
     * @since 1.2.1
     */
    private function isNotDeclaration(AbstractNode $node)
    {
        if ($node instanceof MethodNode) {
            return !$node->isDeclaration();
        }
        return false;
    }

    /**
     * This method extracts all parameters for the given function or method node
     * and it stores the parameter images in the <b>$_images</b> property.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    private function collectParameters(AbstractNode $node)
    {
        // First collect the formal parameters container
        $parameters = $node->getFirstChildOfType('FormalParameters');

        // Now get all declarators in the formal parameters container
        $declarators = $parameters->findChildrenOfType('VariableDeclarator');

        foreach ($declarators as $declarator) {
            $this->nodes[$declarator->getImage()] = $declarator;
        }
    }

    /**
     * This method collects all local variables in the body of the currently
     * analyzed method or function and removes those parameters that are
     * referenced by one of the collected variables.
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    private function removeUsedParameters(AbstractNode $node)
    {
        $variables = $node->findChildrenOfType('Variable');
        foreach ($variables as $variable) {
            if ($this->isRegularVariable($variable)) {
                unset($this->nodes[$variable->getImage()]);
            }
        }

        /* If the method calls func_get_args() then all parameters are
         * automatically referenced */
        $functionCalls = $node->findChildrenOfType('FunctionPostfix');
        foreach ($functionCalls as $functionCall) {
            if ($this->isFunctionNameEqual($functionCall, 'func_get_args')) {
                $this->nodes = array();
            }

            if ($this->isFunctionNameEndingWith($functionCall, 'compact')) {
                foreach ($functionCall->findChildrenOfType('Literal') as $literal) {
                    unset($this->nodes['$' . trim($literal->getImage(), '"\'')]);
                }
            }
        }
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Rule;

/**
 * This interface is used to mark a rule implementation as class aware.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface ClassAware
{
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD;

/**
 * This type of exception is thrown when a not existing rule-set was specified.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class RuleSetNotFoundException extends \RuntimeException
{
    /**
     * Constructs a new exception for the given rule-set identifier or file name.
     *
     * @param string $ruleSet The rule-set identifier or file name.
     */
    public function __construct($ruleSet)
    {
        parent::__construct('Cannot find specified rule-set "' . $ruleSet . '".');
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD;

/**
 * Abstract base class for PHPMD rendering engines.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
abstract class AbstractRenderer
{
    /**
     * The associated output writer instance.
     *
     * @var \PHPMD\AbstractWriter
     */
    private $writer = null;

    /**
     * Returns the associated output writer instance.
     *
     * @return \PHPMD\AbstractWriter
     */
    public function getWriter()
    {
        return $this->writer;
    }

    /**
     * Returns the associated output writer instance.
     *
     * @param \PHPMD\AbstractWriter $writer
     * @return void
     */
    public function setWriter(AbstractWriter $writer)
    {
        $this->writer = $writer;
    }

    /**
     * This method will be called on all renderers before the engine starts the
     * real report processing.
     *
     * @return void
     */
    public function start()
    {
        // Just a hook
    }

    /**
     * This method will be called when the engine has finished the source analysis
     * phase.
     *
     * @param \PHPMD\Report $report
     * @return void
     */
    abstract public function renderReport(Report $report);

    /**
     * This method will be called the engine has finished the report processing
     * for all registered renderers.
     *
     * @return void
     */
    public function end()
    {
        // Just a hook
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD;

/**
 * This is the main facade of the PHP PMD application
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class PHPMD
{
    /**
     * The current PHPMD version.
     */
    const VERSION = '@project.version@';

    /**
     * List of valid file extensions for analyzed files.
     *
     * @var array(string)
     */
    private $fileExtensions = array('php', 'php3', 'php4', 'php5', 'inc');

    /**
     * List of exclude directory patterns.
     *
     * @var array(string)
     */
    private $ignorePatterns = array('.git', '.svn', 'CVS', '.bzr', '.hg', 'SCCS');

    /**
     * The input source file or directory.
     *
     * @var string
     */
    private $input;
    
    /**
     * This property will be set to <b>true</b> when an error or a violation
     * was found in the processed source code.
     *
     * @var boolean
     * @since 0.2.5
     */
    private $violations = false;

    /**
     * Additional options for PHPMD or one of it's parser backends.
     *
     * @var array
     * @since 1.2.0
     */
    private $options = array();

    /**
     * This method will return <b>true</b> when the processed source code
     * contains violations.
     *
     * @return boolean
     * @since 0.2.5
     */
    public function hasViolations()
    {
        return $this->violations;
    }

    /**
     * Returns the input source file or directory path.
     *
     * @return string
     */
    public function getInput()
    {
        return $this->input;
    }

    /**
     * Returns an array with valid php source file extensions.
     *
     * @return array(string)
     * @since 0.2.0
     */
    public function getFileExtensions()
    {
        return $this->fileExtensions;
    }

    /**
     * Sets a list of filename extensions for valid php source code files.
     *
     * @param array(string) $fileExtensions Extensions without leading dot.
     *
     * @return void
     */
    public function setFileExtensions(array $fileExtensions)
    {
        $this->fileExtensions = $fileExtensions;
    }

    /**
     * Returns an array with string patterns that mark a file path as invalid.
     *
     * @return array(string)
     * @since 0.2.0
     */
    public function getIgnorePattern()
    {
        return $this->ignorePatterns;
    }

    /**
     * Sets a list of ignore patterns that is used to exclude directories from
     * the source analysis.
     *
     * @param array(string) $ignorePatterns List of ignore patterns.
     *
     * @return void
     */
    public function setIgnorePattern(array $ignorePatterns)
    {
        $this->ignorePatterns = array_merge(
            $this->ignorePatterns,
            $ignorePatterns
        );
    }

    /**
     * Returns additional options for PHPMD or one of it's parser backends.
     *
     * @return array
     */
    public function getOptions()
    {
        return $this->options;
    }

    /**
     * Sets additional options for PHPMD or one of it's parser backends.
     *
     * @param array $options Additional backend or PHPMD options.
     * @return void
     */
    public function setOptions(array $options)
    {
        $this->options = $options;
    }

    /**
     * This method will process all files that can be found in the given input
     * path. It will apply rules defined in the comma-separated <b>$ruleSets</b>
     * argument. The result will be passed to all given renderer instances.
     *
     * @param string $inputPath
     * @param string $ruleSets
     * @param \PHPMD\AbstractRenderer[] $renderers
     * @param \PHPMD\RuleSetFactory $ruleSetFactory
     * @return void
     */
    public function processFiles(
        $inputPath,
        $ruleSets,
        array $renderers,
        RuleSetFactory $ruleSetFactory
    ) {

        // Merge parsed excludes
        $this->ignorePatterns = array_merge($this->ignorePatterns, $ruleSetFactory->getIgnorePattern($ruleSets));

        $this->input = $inputPath;

        $report = new Report();

        $factory = new ParserFactory();
        $parser  = $factory->create($this);

        foreach ($ruleSetFactory->createRuleSets($ruleSets) as $ruleSet) {
            $parser->addRuleSet($ruleSet);
        }

        $report->start();
        $parser->parse($report);
        $report->end();

        foreach ($renderers as $renderer) {
            $renderer->start();
        }
        
        foreach ($renderers as $renderer) {
            $renderer->renderReport($report);
        }

        foreach ($renderers as $renderer) {
            $renderer->end();
        }

        $this->violations = !$report->isEmpty();
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD;

use PDepend\Application;
use PDepend\Engine;
use PDepend\Input\ExcludePathFilter;
use PDepend\Input\ExtensionFilter;

/**
 * Simple factory that is used to return a ready to use PDepend instance.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ParserFactory
{
    /**
     * Mapping between phpmd option names and those used by pdepend.
     *
     * @var array
     */
    private $phpmd2pdepend = array(
        'coverage'  =>  'coverage-report'
    );

    /**
     * Creates the used {@link \PHPMD\Parser} analyzer instance.
     *
     * @param \PHPMD\PHPMD $phpmd
     * @return \PHPMD\Parser
     */
    public function create(PHPMD $phpmd)
    {
        $pdepend = $this->createInstance();
        $pdepend = $this->init($pdepend, $phpmd);

        return new Parser($pdepend);
    }

    /**
     * Creates a clean php depend instance with some base settings.
     *
     * @return \PDepend\Engine
     */
    private function createInstance()
    {
        $application = new Application();

        if (file_exists(getcwd() . '/pdepend.xml')) {
            $application->setConfigurationFile(getcwd() . '/pdepend.xml');
        } elseif (file_exists(getcwd() . '/pdepend.xml.dist')) {
            $application->setConfigurationFile(getcwd() . '/pdepend.xml.dist');
        }

        return $application->getEngine();
    }

    /**
     * Configures the given PDepend\Engine instance based on some user settings.
     *
     * @param \PDepend\Engine $pdepend
     * @param \PHPMD\PHPMD $phpmd
     * @return \PDepend\Engine
     */
    private function init(Engine $pdepend, PHPMD $phpmd)
    {
        $this->initOptions($pdepend, $phpmd);
        $this->initInput($pdepend, $phpmd);
        $this->initIgnores($pdepend, $phpmd);
        $this->initExtensions($pdepend, $phpmd);

        return $pdepend;
    }

    /**
     * Configures the input source.
     *
     * @param \PDepend\Engine $pdepend
     * @param \PHPMD\PHPMD $phpmd
     * @return void
     */
    private function initInput(Engine $pdepend, PHPMD $phpmd)
    {
        foreach (explode(',', $phpmd->getInput()) as $path) {
            if (is_dir(trim($path))) {
                $pdepend->addDirectory(trim($path));
            } else {
                $pdepend->addFile(trim($path));
            }
        }
    }

    /**
     * Initializes the ignored files and path's.
     *
     * @param \PDepend\Engine $pdepend
     * @param \PHPMD\PHPMD $phpmd
     * @return void
     */
    private function initIgnores(Engine $pdepend, PHPMD $phpmd)
    {
        if (count($phpmd->getIgnorePattern()) > 0) {
            $pdepend->addFileFilter(
                new ExcludePathFilter($phpmd->getIgnorePattern())
            );
        }
    }

    /**
     * Initializes the accepted php source file extensions.
     *
     * @param \PDepend\Engine $pdepend
     * @param \PHPMD\PHPMD $phpmd
     * @return void
     */
    private function initExtensions(Engine $pdepend, PHPMD $phpmd)
    {
        if (count($phpmd->getFileExtensions()) > 0) {
            $pdepend->addFileFilter(
                new ExtensionFilter($phpmd->getFileExtensions())
            );
        }
    }

    /**
     * Initializes additional options for pdepend.
     *
     * @param \PDepend\Engine $pdepend
     * @param \PHPMD\PHPMD $phpmd
     * @return void
     */
    private function initOptions(Engine $pdepend, PHPMD $phpmd)
    {
        $options = array();
        foreach (array_filter($phpmd->getOptions()) as $name => $value) {
            if (isset($this->phpmd2pdepend[$name])) {
                $options[$this->phpmd2pdepend[$name]] = $value;
            }
        }
        $pdepend->setOptions($options);
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Node;

use PDepend\Source\AST\ASTInterface;

/**
 * Wrapper around PHP_Depend's interface objects.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class InterfaceNode extends AbstractTypeNode
{
    /**
     * Constructs a new interface wrapper instance.
     *
     * @param \PDepend\Source\AST\ASTInterface $node
     */
    public function __construct(ASTInterface $node)
    {
        parent::__construct($node);
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Node;

use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTTrait;
use PHPMD\Rule;

/**
 * Wrapper around a PHP_Depend method node.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class MethodNode extends AbstractCallableNode
{
    /**
     * Constructs a new method wrapper.
     *
     * @param \PDepend\Source\AST\ASTMethod $node
     */
    public function __construct(ASTMethod $node)
    {
        parent::__construct($node);
    }

    /**
     * Returns the name of the parent package.
     *
     * @return string
     */
    public function getNamespaceName()
    {
        return $this->getNode()->getParent()->getNamespace()->getName();
    }

    /**
     * Returns the name of the parent type or <b>null</b> when this node has no
     * parent type.
     *
     * @return string
     */
    public function getParentName()
    {
        return $this->getNode()->getParent()->getName();
    }

    /**
     * Returns the full qualified name of a class, an interface, a method or
     * a function.
     *
     * @return string
     */
    public function getFullQualifiedName()
    {
        return sprintf(
            '%s\\%s::%s()',
            $this->getNamespaceName(),
            $this->getParentName(),
            $this->getName()
        );
    }

    /**
     * Returns <b>true</b> when the underlying method is declared as abstract or
     * is declared as child of an interface.
     *
     * @return boolean
     */
    public function isAbstract()
    {
        return $this->getNode()->isAbstract();
    }

    /**
     * Checks if this node has a suppressed annotation for the given rule
     * instance.
     *
     * @param \PHPMD\Rule $rule
     * @return boolean
     */
    public function hasSuppressWarningsAnnotationFor(Rule $rule)
    {
        if (parent::hasSuppressWarningsAnnotationFor($rule)) {
            return true;
        }
        return $this->getParentType()->hasSuppressWarningsAnnotationFor($rule);
    }

    /**
     * Returns the parent class or interface instance.
     *
     * @return \PHPMD\Node\AbstractTypeNode
     */
    public function getParentType()
    {
        $parentNode = $this->getNode()->getParent();

        if ($parentNode instanceof ASTTrait) {
            return new TraitNode($parentNode);
        }

        if ($parentNode instanceof ASTClass) {
            return new ClassNode($parentNode);
        }
        
        return new InterfaceNode($parentNode);
    }

    /**
     * Returns <b>true</b> when this method is the initial method declaration.
     * Otherwise this method will return <b>false</b>.
     *
     * @return boolean
     * @since 1.2.1
     */
    public function isDeclaration()
    {
        if ($this->isPrivate()) {
            return true;
        }

        $methodName = strtolower($this->getName());

        $parentNode = $this->getNode()->getParent();
        foreach ($parentNode->getInterfaces() as $parentType) {
            $methods = $parentType->getAllMethods();
            if (isset($methods[$methodName])) {
                return false;
            }
        }

        if (is_object($parentType = $parentNode->getParentClass())) {
            $methods = $parentType->getAllMethods();
            if (isset($methods[$methodName])) {
                return false;
            }
        }

        return true;
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Node;

use PDepend\Source\AST\ASTTrait;

/**
 * Wrapper around PHP_Depend's interface objects.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class TraitNode extends AbstractTypeNode
{
    /**
     * Constructs a new interface wrapper instance.
     *
     * @param \PDepend\Source\AST\ASTTrait $node
     */
    public function __construct(ASTTrait $node)
    {
        parent::__construct($node);
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Node;

use PHPMD\Rule;

/**
 * Collection of code annotations.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Annotations
{
    /**
     * Detected annotations.
     *
     * @var \PHPMD\Node\Annotation[]
     */
    private $annotations = array();

    /**
     * Regexp used to extract code annotations.
     *
     * @var string
     */
    private $regexp = '(@([a-z_][a-z0-9_]+)\(([^\)]+)\))i';

    /**
     * Constructs a new collection instance.
     *
     * @param \PHPMD\AbstractNode $node
     */
    public function __construct(\PHPMD\AbstractNode $node)
    {
        preg_match_all($this->regexp, $node->getDocComment(), $matches);
        foreach (array_keys($matches[0]) as $i) {
            $name  = $matches[1][$i];
            $value = trim($matches[2][$i], '" ');

            $this->annotations[] = new Annotation($name, $value);
        }
    }
    
    /**
     * Checks if one of the annotations suppresses the given rule.
     *
     * @param \PHPMD\Rule $rule
     * @return boolean
     */
    public function suppresses(Rule $rule)
    {
        foreach ($this->annotations as $annotation) {
            if ($annotation->suppresses($rule)) {
                return true;
            }
        }
        return false;
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Node;

use PHPMD\Rule;

/**
 * Wrapper around a PHP_Depend ast node.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTNode extends \PHPMD\AbstractNode
{
    /**
     * The source file of this node.
     *
     * @var string
     */
    private $fileName = null;

    /**
     * Constructs a new ast node instance.
     *
     * @param \PDepend\Source\AST\ASTNode $node
     * @param string $fileName
     */
    public function __construct(\PDepend\Source\AST\ASTNode $node, $fileName)
    {
        parent::__construct($node);

        $this->fileName = $fileName;
    }

    /**
     * Checks if this node has a suppressed annotation for the given rule
     * instance.
     *
     * @param \PHPMD\Rule $rule
     * @return boolean
     * @SuppressWarnings("PMD.UnusedFormalParameter")
     */
    public function hasSuppressWarningsAnnotationFor(Rule $rule)
    {
        return false;
    }

    /**
     * Returns the source name for this node, maybe a class or interface name,
     * or a package, method, function name.
     *
     * @return string
     */
    public function getName()
    {
        return $this->getImage();
    }

    /**
     * Returns the image of the underlying node.
     *
     * @return string
     */
    public function getImage()
    {
        return $this->getNode()->getImage();
    }

    /**
     * Returns the name of the declaring source file.
     *
     * @return string
     */
    public function getFileName()
    {
        return $this->fileName;
    }

    /**
     * Returns the name of the parent type or <b>null</b> when this node has no
     * parent type.
     *
     * @return string
     */
    public function getParentName()
    {
        return null;
    }

    /**
     * Returns the name of the parent namespace.
     *
     * @return string
     */
    public function getNamespaceName()
    {
        return null;
    }

    /**
     * Returns the full qualified name of a class, an interface, a method or
     * a function.
     *
     * @return string
     */
    public function getFullQualifiedName()
    {
        return null;
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Node;

use PDepend\Source\AST\AbstractASTClassOrInterface;

/**
 * Abstract base class for classes and interfaces.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
abstract class AbstractTypeNode extends AbstractNode
{
    /**
     * @var \PDepend\Source\AST\AbstractASTClassOrInterface
     */
    private $node;

    /**
     * Constructs a new generic class or interface node.
     *
     * @param \PDepend\Source\AST\AbstractASTClassOrInterface $node
     */
    public function __construct(AbstractASTClassOrInterface $node)
    {
        parent::__construct($node);

        $this->node = $node;
    }

    /**
     * Returns an <b>array</b> with all methods defined in the context class or
     * interface.
     *
     * @return \PHPMD\Node\MethodNode[]
     */
    public function getMethods()
    {
        $methods = array();
        foreach ($this->node->getMethods() as $method) {
            $methods[] = new MethodNode($method);
        }
        return $methods;
    }

    /**
     * Returns an array with the names of all methods within this class or
     * interface node.
     *
     * @return array(string)
     */
    public function getMethodNames()
    {
        $names = array();
        foreach ($this->node->getMethods() as $method) {
            $names[] = $method->getName();
        }
        return $names;
    }

    /**
     * Returns the number of constants declared in this type.
     *
     * @return integer
     */
    public function getConstantCount()
    {
        return count($this->node->getConstants());
    }

    /**
     * Returns the name of the parent namespace.
     *
     * @return string
     */
    public function getNamespaceName()
    {
        return $this->node->getNamespace()->getName();
    }

    /**
     * Returns the name of the parent type or <b>null</b> when this node has no
     * parent type.
     *
     * @return string
     */
    public function getParentName()
    {
        return null;
    }

    /**
     * Returns the full qualified name of a class, an interface, a method or
     * a function.
     *
     * @return string
     */
    public function getFullQualifiedName()
    {
        return sprintf('%s\\%s', $this->getNamespaceName(), $this->getName());
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Node;

use PDepend\Source\AST\AbstractASTCallable;

/**
 * Abstract base class for PHP_Depend function and method wrappers.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
abstract class AbstractCallableNode extends AbstractNode
{
    /**
     * Constructs a new callable wrapper.
     *
     * @param \PDepend\Source\AST\AbstractASTCallable $node
     */
    public function __construct(AbstractASTCallable $node)
    {
        parent::__construct($node);
    }

    /**
     * Returns the number of parameters in the callable signature.
     *
     * @return integer
     */
    public function getParameterCount()
    {
        return count($this->getNode()->getParameters());
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Node;

use PHPMD\Rule;

/**
 * Abstract base class for all code nodes.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
abstract class AbstractNode extends \PHPMD\AbstractNode
{
    /**
     * Annotations associated with node instance.
     *
     * @var \PHPMD\Node\Annotations
     */
    private $annotations = null;

    /**
     * Checks if this node has a suppressed annotation for the given rule
     * instance.
     *
     * @param \PHPMD\Rule $rule
     * @return boolean
     */
    public function hasSuppressWarningsAnnotationFor(Rule $rule)
    {
        if ($this->annotations === null) {
            $this->annotations = new Annotations($this);
        }
        return $this->annotations->suppresses($rule);
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Node;

use PHPMD\Rule;

/**
 * Simple code annotation class.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Annotation
{
    /**
     * Name of the suppress warnings annotation.
     */
    const SUPPRESS_ANNOTATION = 'SuppressWarnings';

    /**
     * The annotation name.
     *
     * @var string
     */
    private $name = null;

    /**
     * The annotation value.
     *
     * @var string
     */
    private $value = null;

    /**
     * Constructs a new annotation instance.
     *
     * @param string $name
     * @param string $value
     */
    public function __construct($name, $value)
    {
        $this->name  = $name;
        $this->value = trim($value, '" ');
    }

    /**
     * Checks if this annotation suppresses the given rule.
     *
     * @param \PHPMD\Rule $rule
     * @return boolean
     */
    public function suppresses(Rule $rule)
    {
        if ($this->name === self::SUPPRESS_ANNOTATION) {
            return $this->isSuppressed($rule);
        }
        return false;
    }

    /**
     * Checks if this annotation suppresses the given rule.
     *
     * @param \PHPMD\Rule $rule
     * @return boolean
     */
    private function isSuppressed(Rule $rule)
    {
        if (in_array($this->value, array('PHPMD', 'PMD'))) {
            return true;
        } elseif (preg_match('/^(PH)?PMD\.' . $rule->getName() . '/', $this->value)) {
            return true;
        }
        return (stripos($rule->getName(), $this->value) !== false);
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Node;

use PDepend\Source\AST\ASTClass;

/**
 * Wrapper around PHP_Depend's class objects.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ClassNode extends AbstractTypeNode
{
    /**
     * The type of this class.
     */
    const CLAZZ = __CLASS__;

    /**
     * Constructs a new class wrapper node.
     *
     * @param \PDepend\Source\AST\ASTClass $node
     */
    public function __construct(ASTClass $node)
    {
        parent::__construct($node);
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Node;

use PDepend\Source\AST\ASTFunction;

/**
 * Wrapper around a PDepend function node.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class FunctionNode extends AbstractCallableNode
{
    /**
     * Constructs a new function wrapper.
     *
     * @param \PDepend\Source\AST\ASTFunction $node
     */
    public function __construct(ASTFunction $node)
    {
        parent::__construct($node);
    }

    /**
     * Returns the name of the parent package.
     *
     * @return string
     */
    public function getNamespaceName()
    {
        return $this->getNode()->getNamespace()->getName();
    }

    /**
     * Returns the name of the parent type or <b>null</b> when this node has no
     * parent type.
     *
     * @return string
     */
    public function getParentName()
    {
        return null;
    }

    /**
     * Returns the full qualified name of a class, an interface, a method or
     * a function.
     *
     * @return string
     */
    public function getFullQualifiedName()
    {
        return sprintf('%s\\%s()', $this->getNamespaceName(), $this->getName());
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD;

/**
 * This type of exception is thrown when the class file for a configured rule
 * does not exist within php's include path.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class RuleClassFileNotFoundException extends \RuntimeException
{
    /**
     * Constructs a new class file not found exception.
     *
     * @param string $className The rule class name.
     */
    public function __construct($className)
    {
        parent::__construct('Cannot load source file for class: ' . $className);
    }
}
<?php
/**
 * This file is part of PHPMD.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD;

use PHPMD\Node\ASTNode;

/**
 * This is an abstract base class for PHPMD code nodes, it is just a wrapper
 * around PDepend's object model.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
abstract class AbstractNode
{
    /**
     *
     * @var \PDepend\Source\AST\ASTArtifact|\PDepend\Source\AST\ASTNode $node
     */
    private $node = null;

    /**
     * The collected metrics for this node.
     *
     * @var array(string=>mixed) $_metrics
     */
    private $metrics = null;

    /**
     * Constructs a new PHPMD node.
     *
     * @param \PDepend\Source\AST\ASTArtifact|\PDepend\Source\AST\ASTNode $node
     */
    public function __construct($node)
    {
        $this->node = $node;
    }

    /**
     * The magic call method is used to pipe requests from rules direct
     * to the underlying PDepend ast node.
     *
     * @param string $name
     * @param array $args
     * @return mixed
     * @throws \BadMethodCallException When the underlying PDepend node
     *         does not contain a method named <b>$name</b>.
     */
    public function __call($name, array $args)
    {
        if (method_exists($this->getNode(), $name)) {
            return call_user_func_array(array($this->getNode(), $name), $args);
        }
        throw new \BadMethodCallException(
            sprintf('Invalid method %s() called.', $name)
        );
    }

    /**
     * Returns the parent of this node or <b>null</b> when no parent node
     * exists.
     *
     * @return ASTNode
     */
    public function getParent()
    {
        if (($node = $this->node->getParent()) === null) {
            return null;
        }
        return new ASTNode($node, $this->getFileName());
    }

    /**
     * Returns a child node at the given index.
     *
     * @param integer $index The child offset.
     *
     * @return \PHPMD\Node\ASTNode
     */
    public function getChild($index)
    {
        return new ASTNode(
            $this->node->getChild($index),
            $this->getFileName()
        );
    }

    /**
     * Returns the first child of the given type or <b>null</b> when this node
     * has no child of the given type.
     *
     * @param string $type The searched child type.
     * @return \PHPMD\AbstractNode
     */
    public function getFirstChildOfType($type)
    {
        $node = $this->node->getFirstChildOfType('PDepend\Source\AST\AST' . $type);
        if ($node === null) {
            return null;
        }
        return new ASTNode($node, $this->getFileName());
    }

    /**
     * Searches recursive for all children of this node that are of the given
     * type.
     *
     * @param string $type The searched child type.
     * @return \PHPMD\AbstractNode[]
     */
    public function findChildrenOfType($type)
    {
        $children = $this->node->findChildrenOfType('PDepend\Source\AST\AST' . $type);

        $nodes = array();
        foreach ($children as $child) {
            $nodes[] = new ASTNode($child, $this->getFileName());
        }
        return $nodes;
    }

    /**
     * Tests if this node represents the the given type.
     *
     * @param string $type The expected node type.
     * @return boolean
     */
    public function isInstanceOf($type)
    {
        $class = 'PDepend\Source\AST\AST' . $type;
        return ($this->node instanceof $class);
    }

    /**
     * Returns the image of the underlying node.
     *
     * @return string
     */
    public function getImage()
    {
        return $this->node->getName();
    }

    /**
     * Returns the source name for this node, maybe a class or interface name,
     * or a package, method, function name.
     *
     * @return string
     */
    public function getName()
    {
        return $this->node->getName();
    }

    /**
     * Returns the begin line for this node in the php source code file.
     *
     * @return integer
     */
    public function getBeginLine()
    {
        return $this->node->getStartLine();
    }

    /**
     * Returns the end line for this node in the php source code file.
     *
     * @return integer
     */
    public function getEndLine()
    {
        return $this->node->getEndLine();
    }

    /**
     * Returns the name of the declaring source file.
     *
     * @return string
     */
    public function getFileName()
    {
        return (string) $this->node->getCompilationUnit()->getFileName();
    }

    /**
     * Returns the wrapped PDepend node instance.
     *
     * @return \PDepend\Source\AST\ASTArtifact
     */
    public function getNode()
    {
        return $this->node;
    }

    /**
     * Returns a textual representation/name for the concrete node type.
     *
     * @return string
     */
    public function getType()
    {
        $type = explode('\\', get_class($this));
        return preg_replace('(node$)', '', strtolower(array_pop($type)));
    }

    /**
     * This method will return the metric value for the given identifier or
     * <b>null</b> when no such metric exists.
     *
     * @param string $name The metric name or abbreviation.
     *
     * @return mixed
     */
    public function getMetric($name)
    {
        if (isset($this->metrics[$name])) {
            return $this->metrics[$name];
        }
        return null;
    }

    /**
     * This method will set the metrics for this node.
     *
     * @param array(string=>mixed) $metrics The collected node metrics.
     * @return void
     */
    public function setMetrics(array $metrics)
    {
        if ($this->metrics === null) {
            $this->metrics = $metrics;
        }
    }

    /**
     * Checks if this node has a suppressed annotation for the given rule
     * instance.
     *
     * @param \PHPMD\Rule $rule
     * @return boolean
     */
    abstract public function hasSuppressWarningsAnnotationFor(Rule $rule);

    /**
     * Returns the full qualified name of a class, an interface, a method or
     * a function.
     *
     * @return string
     */
    abstract public function getFullQualifiedName();

    /**
     * Returns the name of the parent type or <b>null</b> when this node has no
     * parent type.
     *
     * @return string
     */
    abstract public function getParentName();

    /**
     * Returns the name of the parent package.
     *
     * @return string
     */
    abstract public function getNamespaceName();
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since     1.2.1
 */

namespace PHPMD;

/**
 * Simple data class that we use to keep parsing errors for the report renderer.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since     1.2.1
 */
class ProcessingError
{
    /**
     * The original processing error message.
     *
     * @var string
     */
    private $message;

    /**
     * The source file where the processing error occurred.
     *
     * @var string
     */
    private $file;

    /**
     * Constructs a new processing error instance.
     *
     * @param string $message
     */
    public function __construct($message)
    {
        $this->message = $message;
        $this->file    = $this->extractFile($message);
    }

    /**
     * Returns the source file where the processing error occurred.
     *
     * @return string
     */
    public function getFile()
    {
        return $this->file;
    }

    /**
     * Returns the original processing error message.
     *
     * @return string
     */
    public function getMessage()
    {
        return $this->message;
    }

    /**
     * Evil hack that extracts the source file from the original exception
     * message. This method should be removed once we have added the source file
     * as a mandatory property to PDepend's exceptions.
     *
     * @param string $message
     * @return string
     */
    private function extractFile($message)
    {
        preg_match('(file: (.+)\.$| file "([^"]+)")', $message, $match);

        $match = array_values(array_filter($match));
        if (isset($match[1])) {
            return $match[1];
        }
        return '';
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD;

use PHPMD\Node\AbstractTypeNode;
use PHPMD\Node\FunctionNode;
use PHPMD\Node\MethodNode;

/**
 * This class is used as container for a single rule violation related to a source
 * node.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class RuleViolation
{
    /**
     * The rule that causes this violation.
     *
     * @var \PHPMD\Rule
     */
    private $rule;

    /**
     * The context code node for this rule violation.
     *
     * @var \PHPMD\AbstractNode
     */
    private $node;

    /**
     * The description/message text that describes the violation.
     *
     * @var string
     */
    private $description;

    /**
     * The raw metric value which caused this rule violation.
     *
     * @var mixed
     */
    private $metric;

    /**
     * Name of the owning/context class or interface of this violation.
     *
     * @var string
     */
    private $className = null;

    /**
     * The name of a method or <b>null</b> when this violation has no method
     * context.
     *
     * @var string
     */
    private $methodName = null;

    /**
     * The name of a function or <b>null</b> when this violation has no function
     * context.
     *
     * @var string
     */
    private $functionName = null;

    /**
     * Constructs a new rule violation instance.
     *
     * @param \PHPMD\Rule $rule
     * @param \PHPMD\AbstractNode $node
     * @param string $violationMessage
     * @param mixed $metric
     */
    public function __construct(Rule $rule, AbstractNode $node, $violationMessage, $metric = null)
    {
        $this->rule        = $rule;
        $this->node        = $node;
        $this->metric      = $metric;
        $this->description = $violationMessage;

        if ($node instanceof AbstractTypeNode) {
            $this->className = $node->getName();
        } elseif ($node instanceof MethodNode) {
            $this->className  = $node->getParentName();
            $this->methodName = $node->getName();
        } elseif ($node instanceof FunctionNode) {
            $this->functionName = $node->getName();
        }
    }

    /**
     * Returns the rule that causes this violation.
     *
     * @return \PHPMD\Rule
     */
    public function getRule()
    {
        return $this->rule;
    }

    /**
     * Returns the description/message text that describes the violation.
     *
     * @return string
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * Returns the raw metric value which caused this rule violation.
     *
     * @return mixed|null
     */
    public function getMetric()
    {
        return $this->metric;
    }

    /**
     * Returns the file name where this rule violation was detected.
     *
     * @return string
     */
    public function getFileName()
    {
        return $this->node->getFileName();
    }

    /**
     * Returns the first line of the node that causes this rule violation.
     *
     * @return integer
     */
    public function getBeginLine()
    {
        return $this->node->getBeginLine();
    }

    /**
     * Returns the last line of the node that causes this rule violation.
     *
     * @return integer
     */
    public function getEndLine()
    {
        return $this->node->getEndLine();
    }

    /**
     * Returns the name of the package that contains this violation.
     *
     * @return string
     */
    public function getNamespaceName()
    {
        return $this->node->getNamespaceName();
    }

    /**
     * Returns the name of the parent class or interface or <b>null</b> when there
     * is no parent class.
     *
     * @return string
     */
    public function getClassName()
    {
        return $this->className;
    }

    /**
     * Returns the name of a method or <b>null</b> when this violation has no
     * method context.
     *
     * @return string
     */
    public function getMethodName()
    {
        return $this->methodName;
    }

    /**
     * Returns the name of a function or <b>null</b> when this violation has no
     * function context.
     *
     * @return string
     */
    public function getFunctionName()
    {
        return $this->functionName;
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD\Writer;

use PHPMD\AbstractWriter;

/**
 * This writer uses PHP's stream api as its output target.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class StreamWriter extends AbstractWriter
{
    /**
     * The stream resource handle
     *
     * @var resource
     */
    private $stream = null;

    /**
     * Constructs a new stream writer instance.
     *
     * @param resource|string $streamResourceOrUri
     */
    public function __construct($streamResourceOrUri)
    {
        if (is_resource($streamResourceOrUri) === true) {
            $this->stream = $streamResourceOrUri;
        } else {
            $dirName = dirname($streamResourceOrUri);
            if (file_exists($dirName) === false) {
                mkdir($dirName, 0777, true);
            }
            if (file_exists($dirName) === false) {
                $message = 'Cannot find output directory "' . $dirName . '".';
                throw new \RuntimeException($message);
            }

            $this->stream = fopen($streamResourceOrUri, 'wb');
        }
    }

    /**
     * The dtor closes the open output resource.
     */
    public function __destruct()
    {
        if ($this->stream !== STDOUT && is_resource($this->stream) === true) {
            @fclose($this->stream);
        }
        $this->stream = null;
    }

    /**
     * Writes the given <b>$data</b> fragment to the wrapper output stream.
     *
     * @param string $data
     * @return void
     */
    public function write($data)
    {
        fwrite($this->stream, $data);
    }
}
<?php
/**
 * This file is part of PHP Mess Detector.
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@phpmd.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PHPMD;

/**
 * This factory class is used to create the {@link \PHPMD\RuleSet} instance
 * that PHPMD will use to analyze the source code.
 *
 * @author Manuel Pichler <mapi@phpmd.org>
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class RuleSetFactory
{
    /**
     * Is the strict mode active?
     *
     * @var boolean
     * @since 1.2.0
     */
    private $strict = false;

    /**
     * The data directory set by PEAR or a dynamic property set within the class
     * constructor.
     *
     * @var string
     */
    private $location = '@data_dir@';

    /**
     * The minimum priority for rules to load.
     *
     * @var integer
     */
    private $minimumPriority = Rule::LOWEST_PRIORITY;

    /**
     * Constructs a new default rule-set factory instance.
     */
    public function __construct()
    {
        // PEAR installer workaround
        if (strpos($this->location, '@data_dir') === 0) {
            $this->location = __DIR__ . '/../../resources';
        } else {
            $this->location .= '/PHPMD/resources';
        }
    }

    /**
     * Activates the strict mode for all rule sets.
     *
     * @return void
     * @since 1.2.0
     */
    public function setStrict()
    {
        $this->strict = true;
    }

    /**
     * Sets the minimum priority that a rule must have.
     *
     * @param integer $minimumPriority The minimum priority value.
     *
     * @return void
     */
    public function setMinimumPriority($minimumPriority)
    {
        $this->minimumPriority = $minimumPriority;
    }

    /**
     * Creates an array of rule-set instances for the given argument.
     *
     * @param string $ruleSetFileNames Comma-separated string of rule-set filenames or identifier.
     * @return \PHPMD\RuleSet[]
     */
    public function createRuleSets($ruleSetFileNames)
    {
        $ruleSets = array();

        $ruleSetFileName = strtok($ruleSetFileNames, ',');
        while ($ruleSetFileName !== false) {
            $ruleSets[] = $this->createSingleRuleSet($ruleSetFileName);

            $ruleSetFileName = strtok(',');
        }
        return $ruleSets;
    }

    /**
     * Creates a single rule-set instance for the given filename or identifier.
     *
     * @param string $ruleSetOrFileName The rule-set filename or identifier.
     * @return \PHPMD\RuleSet
     */
    public function createSingleRuleSet($ruleSetOrFileName)
    {
        $fileName = $this->createRuleSetFileName($ruleSetOrFileName);
        return $this->parseRuleSetNode($fileName);
    }

    /**
     * Lists available rule-set identifiers.
     *
     * @return array(string)
     */
    public function listAvailableRuleSets()
    {
        return array_merge(
            self::listRuleSetsInDirectory($this->location . '/rulesets/'),
            self::listRuleSetsInDirectory(getcwd() . '/rulesets/')
        );
    }

    /**
     * This method creates the filename for a rule-set identifier or it returns
     * the input when it is already a filename.
     *
     * @param string $ruleSetOrFileName The rule-set filename or identifier.
     * @return string
     */
    private function createRuleSetFileName($ruleSetOrFileName)
    {
        if (file_exists($ruleSetOrFileName) === true) {
            return $ruleSetOrFileName;
        }

        $fileName = $this->location . '/' . $ruleSetOrFileName;
        if (file_exists($fileName) === true) {
            return $fileName;
        }

        $fileName = $this->location . '/rulesets/' . $ruleSetOrFileName . '.xml';
        if (file_exists($fileName) === true) {
            return $fileName;
        }

        $fileName = getcwd() . '/rulesets/' . $ruleSetOrFileName . '.xml';
        if (file_exists($fileName) === true) {
            return $fileName;
        }

        foreach (explode(PATH_SEPARATOR, get_include_path()) as $includePath) {
            $fileName = $includePath . '/' . $ruleSetOrFileName;
            if (file_exists($fileName) === true) {
                return $fileName;
            }
            $fileName = $includePath . '/' . $ruleSetOrFileName . ".xml";
            if (file_exists($fileName) === true) {
                return $fileName;
            }
        }
        
        throw new RuleSetNotFoundException($ruleSetOrFileName);
    }

    /**
     * Lists available rule-set identifiers in given directory.
     *
     * @param string $directory The directory to scan for rule-sets.
     *
     * @return array(string)
     */
    private static function listRuleSetsInDirectory($directory)
    {
        $ruleSets = array();
        if (is_dir($directory)) {
            foreach (scandir($directory) as $file) {
                $matches = array();
                if (is_file($directory . $file) && preg_match('/^(.*)\.xml$/', $file, $matches)) {
                    $ruleSets[] = $matches[1];
                }
            }
        }
        return $ruleSets;
    }

    /**
     * This method parses the rule-set definition in the given file.
     *
     * @param string $fileName
     * @return \PHPMD\RuleSet
     */
    private function parseRuleSetNode($fileName)
    {
        // Hide error messages
        $libxml = libxml_use_internal_errors(true);

        $xml = simplexml_load_string(file_get_contents($fileName));
        if ($xml === false) {
            // Reset error handling to previous setting
            libxml_use_internal_errors($libxml);

            throw new \RuntimeException(trim(libxml_get_last_error()->message));
        }

        $ruleSet = new RuleSet();
        $ruleSet->setFileName($fileName);
        $ruleSet->setName((string) $xml['name']);

        if ($this->strict) {
            $ruleSet->setStrict();
        }

        foreach ($xml->children() as $node) {
            if ($node->getName() === 'php-includepath') {
                $includePath = (string) $node;
                
                if (is_dir(dirname($fileName) . DIRECTORY_SEPARATOR . $includePath)) {
                    $includePath = dirname($fileName) . DIRECTORY_SEPARATOR . $includePath;
                    $includePath = realpath($includePath);
                }
                
                $includePath = get_include_path() . PATH_SEPARATOR . $includePath;
                set_include_path($includePath);
            }
        }
        
        foreach ($xml->children() as $node) {
            if ($node->getName() === 'description') {
                $ruleSet->setDescription((string) $node);
            } elseif ($node->getName() === 'rule') {
                $this->parseRuleNode($ruleSet, $node);
            }
        }

        return $ruleSet;
    }

    /**
     * This method parses a single rule xml node. Bases on the structure of the
     * xml node this method delegates the parsing process to another method in
     * this class.
     *
     * @param \PHPMD\RuleSet $ruleSet
     * @param \SimpleXMLElement $node
     * @return void
     */
    private function parseRuleNode(RuleSet $ruleSet, \SimpleXMLElement $node)
    {
        if (substr($node['ref'], -3, 3) === 'xml') {
            $this->parseRuleSetReferenceNode($ruleSet, $node);
        } elseif ('' === (string) $node['ref']) {
            $this->parseSingleRuleNode($ruleSet, $node);
        } else {
            $this->parseRuleReferenceNode($ruleSet, $node);
        }
    }

    /**
     * This method parses a complete rule set that was includes a reference in
     * the currently parsed ruleset.
     *
     * @param \PHPMD\RuleSet $ruleSet
     * @param \SimpleXMLElement $ruleSetNode
     * @return void
     */
    private function parseRuleSetReferenceNode(RuleSet $ruleSet, \SimpleXMLElement $ruleSetNode)
    {
        $rules = $this->parseRuleSetReference($ruleSetNode);
        foreach ($rules as $rule) {
            if ($this->isIncluded($rule, $ruleSetNode)) {
                $ruleSet->addRule($rule);
            }
        }
    }

    /**
     * Parses a rule-set xml file referenced by the given rule-set xml element.
     *
     * @param \SimpleXMLElement $ruleSetNode
     * @return \PHPMD\RuleSet
     * @since 0.2.3
     */
    private function parseRuleSetReference(\SimpleXMLElement $ruleSetNode)
    {
        $ruleSetFactory = new RuleSetFactory();
        $ruleSetFactory->setMinimumPriority($this->minimumPriority);

        return $ruleSetFactory->createSingleRuleSet((string) $ruleSetNode['ref']);
    }

    /**
     * Checks if the given rule is included/not excluded by the given rule-set
     * reference node.
     *
     * @param \PHPMD\Rule $rule
     * @param \SimpleXMLElement $ruleSetNode
     * @return boolean
     * @since 0.2.3
     */
    private function isIncluded(Rule $rule, \SimpleXMLElement $ruleSetNode)
    {
        foreach ($ruleSetNode->exclude as $exclude) {
            if ($rule->getName() === (string) $exclude['name']) {
                return false;
            }
        }
        return true;
    }

    /**
     * This method will create a single rule instance and add it to the given
     * {@link \PHPMD\RuleSet} object.
     *
     * @param \PHPMD\RuleSet $ruleSet
     * @param \SimpleXMLElement $ruleNode
     * @return void
     * @throws \PHPMD\RuleClassFileNotFoundException
     * @throws \PHPMD\RuleClassNotFoundException
     */
    private function parseSingleRuleNode(RuleSet $ruleSet, \SimpleXMLElement $ruleNode)
    {
        $fileName = "";

        $ruleSetFolderPath = dirname($ruleSet->getFileName());

        if (isset($ruleNode['file'])) {
            if (is_readable((string) $ruleNode['file'])) {
                $fileName = (string) $ruleNode['file'];

            } elseif (is_readable($ruleSetFolderPath . DIRECTORY_SEPARATOR . (string) $ruleNode['file'])) {
                $fileName = $ruleSetFolderPath . DIRECTORY_SEPARATOR . (string) $ruleNode['file'];
            }
        }

        $className = (string) $ruleNode['class'];
        
        if (!is_readable($fileName)) {
            $fileName = strtr($className, '\\', '/') . '.php';
        }

        if (!is_readable($fileName)) {
            $fileName = str_replace(array('\\', '_'), '/', $className) . '.php';
        }
        
        if (class_exists($className) === false) {
            $handle = @fopen($fileName, 'r', true);
            if ($handle === false) {
                throw new RuleClassFileNotFoundException($className);
            }
            fclose($handle);

            include_once $fileName;

            if (class_exists($className) === false) {
                throw new RuleClassNotFoundException($className);
            }
        }

        /* @var $rule \PHPMD\Rule */
        $rule = new $className();
        $rule->setName((string) $ruleNode['name']);
        $rule->setMessage((string) $ruleNode['message']);
        $rule->setExternalInfoUrl((string) $ruleNode['externalInfoUrl']);

        $rule->setRuleSetName($ruleSet->getName());

        if (trim($ruleNode['since']) !== '') {
            $rule->setSince((string) $ruleNode['since']);
        }

        foreach ($ruleNode->children() as $node) {
            if ($node->getName() === 'description') {
                $rule->setDescription((string) $node);
            } elseif ($node->getName() === 'example') {
                $rule->addExample((string) $node);
            } elseif ($node->getName() === 'priority') {
                $rule->setPriority((integer) $node);
            } elseif ($node->getName() === 'properties') {
                $this->parsePropertiesNode($rule, $node);
            }
        }

        if ($rule->getPriority() <= $this->minimumPriority) {
            $ruleSet->addRule($rule);
        }
    }

    /**
     * This method parses a single rule that was included from a different
     * rule-set.
     *
     * @param \PHPMD\RuleSet $ruleSet
     * @param \SimpleXMLElement $ruleNode
     * @return void
     */
    private function parseRuleReferenceNode(RuleSet $ruleSet, \SimpleXMLElement $ruleNode)
    {
        $ref = (string) $ruleNode['ref'];

        $fileName = substr($ref, 0, strpos($ref, '.xml/') + 4);
        $fileName = $this->createRuleSetFileName($fileName);

        $ruleName = substr($ref, strpos($ref, '.xml/') + 5);

        $ruleSetFactory = new RuleSetFactory();

        $ruleSetRef = $ruleSetFactory->createSingleRuleSet($fileName);
        $rule       = $ruleSetRef->getRuleByName($ruleName);

        if (trim($ruleNode['name']) !== '') {
            $rule->setName((string) $ruleNode['name']);
        }
        if (trim($ruleNode['message']) !== '') {
            $rule->setMessage((string) $ruleNode['message']);
        }
        if (trim($ruleNode['externalInfoUrl']) !== '') {
            $rule->setExternalInfoUrl((string) $ruleNode['externalInfoUrl']);
        }

        foreach ($ruleNode->children() as $node) {
            if ($node->getName() === 'description') {
                $rule->setDescription((string) $node);
            } elseif ($node->getName() === 'example') {
                $rule->addExample((string) $node);
            } elseif ($node->getName() === 'priority') {
                $rule->setPriority((integer) $node);
            } elseif ($node->getName() === 'properties') {
                $this->parsePropertiesNode($rule, $node);
            }
        }

        if ($rule->getPriority() <= $this->minimumPriority) {
            $ruleSet->addRule($rule);
        }
    }

    /**
     * This method parses a xml properties structure and adds all found properties
     * to the given <b>$rule</b> object.
     *
     * <code>
     *   ...
     *   <properties>
     *       <property name="foo" value="42" />
     *       <property name="bar" value="23" />
     *       ...
     *   </properties>
     *   ...
     * </code>
     *
     * @param \PHPMD\Rule $rule
     * @param \SimpleXMLElement $propertiesNode
     * @return void
     */
    private function parsePropertiesNode(Rule $rule, \SimpleXMLElement $propertiesNode)
    {
        foreach ($propertiesNode->children() as $node) {
            if ($node->getName() === 'property') {
                $this->addProperty($rule, $node);
            }
        }
    }

    /**
     * Adds an additional property to the given <b>$rule</b> instance.
     *
     * @param \PHPMD\Rule $rule
     * @param \SimpleXMLElement $node
     * @return void
     */
    private function addProperty(Rule $rule, \SimpleXMLElement $node)
    {
        $name  = trim($node['name']);
        $value = trim($this->getPropertyValue($node));
        if ($name !== '' && $value !== '') {
            $rule->addProperty($name, $value);
        }
    }

    /**
     * Returns the value of a property node. This value can be expressed in
     * two different notations. First version is an attribute named <b>value</b>
     * and the second valid notation is a child element named <b>value</b> that
     * contains the value as character data.
     *
     * @param \SimpleXMLElement $propertyNode
     * @return string
     * @since 0.2.5
     */
    private function getPropertyValue(\SimpleXMLElement $propertyNode)
    {
        if (isset($propertyNode->value)) {
            return (string) $propertyNode->value;
        }
        return (string) $propertyNode['value'];
    }

    /**
     * Returns an array of path exclude patterns in format described at
     *
     * http://pmd.sourceforge.net/pmd-5.0.4/howtomakearuleset.html#Excluding_files_from_a_ruleset
     *
     * @param string $fileName The filename of a rule-set definition.
     *
     * @return array|null
     * @throws \RuntimeException
     */
    public function getIgnorePattern($fileName)
    {
        $excludes = array();
        foreach (array_map('trim', explode(',', $fileName)) as $ruleSetFileName) {
            $ruleSetFileName = $this->createRuleSetFileName($ruleSetFileName);

            // Hide error messages
            $libxml = libxml_use_internal_errors(true);

            $xml = simplexml_load_string(file_get_contents($ruleSetFileName));
            if ($xml === false) {
                // Reset error handling to previous setting
                libxml_use_internal_errors($libxml);

                throw new \RuntimeException(trim(libxml_get_last_error()->message));
            }

            foreach ($xml->children() as $node) {
                if ($node->getName() === 'exclude-pattern') {
                    $excludes[] = '' . $node;
                }
            }

            return $excludes;
        }
        return null;
    }
}
<?php

// autoload_psr4.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'PDepend\\' => array($vendorDir . '/pdepend/pdepend/src/main/php/PDepend'),
);
<?php

// autoload_static.php @generated by Composer

namespace Composer\Autoload;

class ComposerStaticInite734a91eed98c612a4345af43a64a59e
{
    public static $prefixLengthsPsr4 = array (
        'P' => 
        array (
            'PDepend\\' => 8,
        ),
    );

    public static $prefixDirsPsr4 = array (
        'PDepend\\' => 
        array (
            0 => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend',
        ),
    );

    public static $prefixesPsr0 = array (
        'S' => 
        array (
            'Symfony\\Component\\Filesystem\\' => 
            array (
                0 => __DIR__ . '/..' . '/symfony/filesystem',
            ),
            'Symfony\\Component\\DependencyInjection\\' => 
            array (
                0 => __DIR__ . '/..' . '/symfony/dependency-injection',
            ),
            'Symfony\\Component\\Config\\' => 
            array (
                0 => __DIR__ . '/..' . '/symfony/config',
            ),
        ),
        'P' => 
        array (
            'PHPMD\\' => 
            array (
                0 => __DIR__ . '/../..' . '/src/main/php',
            ),
        ),
    );

    public static function getInitializer(ClassLoader $loader)
    {
        return \Closure::bind(function () use ($loader) {
            $loader->prefixLengthsPsr4 = ComposerStaticInite734a91eed98c612a4345af43a64a59e::$prefixLengthsPsr4;
            $loader->prefixDirsPsr4 = ComposerStaticInite734a91eed98c612a4345af43a64a59e::$prefixDirsPsr4;
            $loader->prefixesPsr0 = ComposerStaticInite734a91eed98c612a4345af43a64a59e::$prefixesPsr0;

        }, null, ClassLoader::class);
    }
}
[
    {
        "name": "symfony/filesystem",
        "version": "v2.3.0",
        "version_normalized": "2.3.0.0",
        "target-dir": "Symfony/Component/Filesystem",
        "source": {
            "type": "git",
            "url": "https://github.com/symfony/filesystem.git",
            "reference": "93ca76c45530d146d0def76d1eb6f60a939a2104"
        },
        "dist": {
            "type": "zip",
            "url": "https://api.github.com/repos/symfony/filesystem/zipball/93ca76c45530d146d0def76d1eb6f60a939a2104",
            "reference": "93ca76c45530d146d0def76d1eb6f60a939a2104",
            "shasum": ""
        },
        "require": {
            "php": ">=5.3.3"
        },
        "time": "2013-05-06T20:03:44+00:00",
        "type": "library",
        "extra": {
            "branch-alias": {
                "dev-master": "2.3-dev"
            }
        },
        "installation-source": "dist",
        "autoload": {
            "psr-0": {
                "Symfony\\Component\\Filesystem\\": ""
            }
        },
        "notification-url": "https://packagist.org/downloads/",
        "license": [
            "MIT"
        ],
        "authors": [
            {
                "name": "Symfony Community",
                "homepage": "http://symfony.com/contributors"
            },
            {
                "name": "Fabien Potencier",
                "email": "fabien@symfony.com"
            }
        ],
        "description": "Symfony Filesystem Component",
        "homepage": "http://symfony.com"
    },
    {
        "name": "symfony/dependency-injection",
        "version": "v2.3.0",
        "version_normalized": "2.3.0.0",
        "target-dir": "Symfony/Component/DependencyInjection",
        "source": {
            "type": "git",
            "url": "https://github.com/symfony/dependency-injection.git",
            "reference": "402b1c843d77b6b6aa8e2aaa21641d6047ccac2f"
        },
        "dist": {
            "type": "zip",
            "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/402b1c843d77b6b6aa8e2aaa21641d6047ccac2f",
            "reference": "402b1c843d77b6b6aa8e2aaa21641d6047ccac2f",
            "shasum": ""
        },
        "require": {
            "php": ">=5.3.3"
        },
        "require-dev": {
            "symfony/config": "~2.2",
            "symfony/yaml": "~2.0"
        },
        "suggest": {
            "symfony/config": "",
            "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
            "symfony/yaml": ""
        },
        "time": "2013-05-13T14:36:40+00:00",
        "type": "library",
        "extra": {
            "branch-alias": {
                "dev-master": "2.3-dev"
            }
        },
        "installation-source": "dist",
        "autoload": {
            "psr-0": {
                "Symfony\\Component\\DependencyInjection\\": ""
            }
        },
        "notification-url": "https://packagist.org/downloads/",
        "license": [
            "MIT"
        ],
        "authors": [
            {
                "name": "Symfony Community",
                "homepage": "http://symfony.com/contributors"
            },
            {
                "name": "Fabien Potencier",
                "email": "fabien@symfony.com"
            }
        ],
        "description": "Symfony DependencyInjection Component",
        "homepage": "http://symfony.com"
    },
    {
        "name": "symfony/config",
        "version": "v2.3.0",
        "version_normalized": "2.3.0.0",
        "target-dir": "Symfony/Component/Config",
        "source": {
            "type": "git",
            "url": "https://github.com/symfony/config.git",
            "reference": "9b798bb01eddf0a86df0ea1498b05d426d2aa17d"
        },
        "dist": {
            "type": "zip",
            "url": "https://api.github.com/repos/symfony/config/zipball/9b798bb01eddf0a86df0ea1498b05d426d2aa17d",
            "reference": "9b798bb01eddf0a86df0ea1498b05d426d2aa17d",
            "shasum": ""
        },
        "require": {
            "php": ">=5.3.3",
            "symfony/filesystem": "~2.3"
        },
        "time": "2013-05-18T21:11:24+00:00",
        "type": "library",
        "extra": {
            "branch-alias": {
                "dev-master": "2.3-dev"
            }
        },
        "installation-source": "dist",
        "autoload": {
            "psr-0": {
                "Symfony\\Component\\Config\\": ""
            }
        },
        "notification-url": "https://packagist.org/downloads/",
        "license": [
            "MIT"
        ],
        "authors": [
            {
                "name": "Symfony Community",
                "homepage": "http://symfony.com/contributors"
            },
            {
                "name": "Fabien Potencier",
                "email": "fabien@symfony.com"
            }
        ],
        "description": "Symfony Config Component",
        "homepage": "http://symfony.com"
    },
    {
        "name": "pdepend/pdepend",
        "version": "2.5.0",
        "version_normalized": "2.5.0.0",
        "source": {
            "type": "git",
            "url": "https://github.com/pdepend/pdepend.git",
            "reference": "0c50874333149c0dad5a2877801aed148f2767ff"
        },
        "dist": {
            "type": "zip",
            "url": "https://api.github.com/repos/pdepend/pdepend/zipball/0c50874333149c0dad5a2877801aed148f2767ff",
            "reference": "0c50874333149c0dad5a2877801aed148f2767ff",
            "shasum": ""
        },
        "require": {
            "php": ">=5.3.7",
            "symfony/config": "^2.3.0|^3",
            "symfony/dependency-injection": "^2.3.0|^3",
            "symfony/filesystem": "^2.3.0|^3"
        },
        "require-dev": {
            "phpunit/phpunit": "^4.4.0,<4.8",
            "squizlabs/php_codesniffer": "^2.0.0"
        },
        "time": "2017-01-19T14:23:36+00:00",
        "bin": [
            "src/bin/pdepend"
        ],
        "type": "library",
        "installation-source": "dist",
        "autoload": {
            "psr-4": {
                "PDepend\\": "src/main/php/PDepend"
            }
        },
        "notification-url": "https://packagist.org/downloads/",
        "license": [
            "BSD-3-Clause"
        ],
        "description": "Official version of pdepend to be handled with Composer"
    }
]
<?php

// autoload_classmap.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
);

Copyright (c) 2016 Nils Adermann, Jordi Boggiano

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

<?php

// autoload_real.php @generated by Composer

class ComposerAutoloaderInite734a91eed98c612a4345af43a64a59e
{
    private static $loader;

    public static function loadClassLoader($class)
    {
        if ('Composer\Autoload\ClassLoader' === $class) {
            require __DIR__ . '/ClassLoader.php';
        }
    }

    public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }

        spl_autoload_register(array('ComposerAutoloaderInite734a91eed98c612a4345af43a64a59e', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader();
        spl_autoload_unregister(array('ComposerAutoloaderInite734a91eed98c612a4345af43a64a59e', 'loadClassLoader'));

        $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
        if ($useStaticLoader) {
            require_once __DIR__ . '/autoload_static.php';

            call_user_func(\Composer\Autoload\ComposerStaticInite734a91eed98c612a4345af43a64a59e::getInitializer($loader));
        } else {
            $map = require __DIR__ . '/autoload_namespaces.php';
            foreach ($map as $namespace => $path) {
                $loader->set($namespace, $path);
            }

            $map = require __DIR__ . '/autoload_psr4.php';
            foreach ($map as $namespace => $path) {
                $loader->setPsr4($namespace, $path);
            }

            $classMap = require __DIR__ . '/autoload_classmap.php';
            if ($classMap) {
                $loader->addClassMap($classMap);
            }
        }

        $loader->register(true);

        return $loader;
    }
}
<?php

// autoload_namespaces.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'),
    'Symfony\\Component\\DependencyInjection\\' => array($vendorDir . '/symfony/dependency-injection'),
    'Symfony\\Component\\Config\\' => array($vendorDir . '/symfony/config'),
    'PHPMD\\' => array($baseDir . '/src/main/php'),
);
<?php

/*
 * This file is part of Composer.
 *
 * (c) Nils Adermann <naderman@naderman.de>
 *     Jordi Boggiano <j.boggiano@seld.be>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Composer\Autoload;

/**
 * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
 *
 *     $loader = new \Composer\Autoload\ClassLoader();
 *
 *     // register classes with namespaces
 *     $loader->add('Symfony\Component', __DIR__.'/component');
 *     $loader->add('Symfony',           __DIR__.'/framework');
 *
 *     // activate the autoloader
 *     $loader->register();
 *
 *     // to enable searching the include path (eg. for PEAR packages)
 *     $loader->setUseIncludePath(true);
 *
 * In this example, if you try to use a class in the Symfony\Component
 * namespace or one of its children (Symfony\Component\Console for instance),
 * the autoloader will first look for the class under the component/
 * directory, and it will then fallback to the framework/ directory if not
 * found before giving up.
 *
 * This class is loosely based on the Symfony UniversalClassLoader.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Jordi Boggiano <j.boggiano@seld.be>
 * @see    http://www.php-fig.org/psr/psr-0/
 * @see    http://www.php-fig.org/psr/psr-4/
 */
class ClassLoader
{
    // PSR-4
    private $prefixLengthsPsr4 = array();
    private $prefixDirsPsr4 = array();
    private $fallbackDirsPsr4 = array();

    // PSR-0
    private $prefixesPsr0 = array();
    private $fallbackDirsPsr0 = array();

    private $useIncludePath = false;
    private $classMap = array();
    private $classMapAuthoritative = false;
    private $missingClasses = array();
    private $apcuPrefix;

    public function getPrefixes()
    {
        if (!empty($this->prefixesPsr0)) {
            return call_user_func_array('array_merge', $this->prefixesPsr0);
        }

        return array();
    }

    public function getPrefixesPsr4()
    {
        return $this->prefixDirsPsr4;
    }

    public function getFallbackDirs()
    {
        return $this->fallbackDirsPsr0;
    }

    public function getFallbackDirsPsr4()
    {
        return $this->fallbackDirsPsr4;
    }

    public function getClassMap()
    {
        return $this->classMap;
    }

    /**
     * @param array $classMap Class to filename map
     */
    public function addClassMap(array $classMap)
    {
        if ($this->classMap) {
            $this->classMap = array_merge($this->classMap, $classMap);
        } else {
            $this->classMap = $classMap;
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix, either
     * appending or prepending to the ones previously set for this prefix.
     *
     * @param string       $prefix  The prefix
     * @param array|string $paths   The PSR-0 root directories
     * @param bool         $prepend Whether to prepend the directories
     */
    public function add($prefix, $paths, $prepend = false)
    {
        if (!$prefix) {
            if ($prepend) {
                $this->fallbackDirsPsr0 = array_merge(
                    (array) $paths,
                    $this->fallbackDirsPsr0
                );
            } else {
                $this->fallbackDirsPsr0 = array_merge(
                    $this->fallbackDirsPsr0,
                    (array) $paths
                );
            }

            return;
        }

        $first = $prefix[0];
        if (!isset($this->prefixesPsr0[$first][$prefix])) {
            $this->prefixesPsr0[$first][$prefix] = (array) $paths;

            return;
        }
        if ($prepend) {
            $this->prefixesPsr0[$first][$prefix] = array_merge(
                (array) $paths,
                $this->prefixesPsr0[$first][$prefix]
            );
        } else {
            $this->prefixesPsr0[$first][$prefix] = array_merge(
                $this->prefixesPsr0[$first][$prefix],
                (array) $paths
            );
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace, either
     * appending or prepending to the ones previously set for this namespace.
     *
     * @param string       $prefix  The prefix/namespace, with trailing '\\'
     * @param array|string $paths   The PSR-4 base directories
     * @param bool         $prepend Whether to prepend the directories
     *
     * @throws \InvalidArgumentException
     */
    public function addPsr4($prefix, $paths, $prepend = false)
    {
        if (!$prefix) {
            // Register directories for the root namespace.
            if ($prepend) {
                $this->fallbackDirsPsr4 = array_merge(
                    (array) $paths,
                    $this->fallbackDirsPsr4
                );
            } else {
                $this->fallbackDirsPsr4 = array_merge(
                    $this->fallbackDirsPsr4,
                    (array) $paths
                );
            }
        } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
            // Register directories for a new namespace.
            $length = strlen($prefix);
            if ('\\' !== $prefix[$length - 1]) {
                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
            }
            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
            $this->prefixDirsPsr4[$prefix] = (array) $paths;
        } elseif ($prepend) {
            // Prepend directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                (array) $paths,
                $this->prefixDirsPsr4[$prefix]
            );
        } else {
            // Append directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                $this->prefixDirsPsr4[$prefix],
                (array) $paths
            );
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix,
     * replacing any others previously set for this prefix.
     *
     * @param string       $prefix The prefix
     * @param array|string $paths  The PSR-0 base directories
     */
    public function set($prefix, $paths)
    {
        if (!$prefix) {
            $this->fallbackDirsPsr0 = (array) $paths;
        } else {
            $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace,
     * replacing any others previously set for this namespace.
     *
     * @param string       $prefix The prefix/namespace, with trailing '\\'
     * @param array|string $paths  The PSR-4 base directories
     *
     * @throws \InvalidArgumentException
     */
    public function setPsr4($prefix, $paths)
    {
        if (!$prefix) {
            $this->fallbackDirsPsr4 = (array) $paths;
        } else {
            $length = strlen($prefix);
            if ('\\' !== $prefix[$length - 1]) {
                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
            }
            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
            $this->prefixDirsPsr4[$prefix] = (array) $paths;
        }
    }

    /**
     * Turns on searching the include path for class files.
     *
     * @param bool $useIncludePath
     */
    public function setUseIncludePath($useIncludePath)
    {
        $this->useIncludePath = $useIncludePath;
    }

    /**
     * Can be used to check if the autoloader uses the include path to check
     * for classes.
     *
     * @return bool
     */
    public function getUseIncludePath()
    {
        return $this->useIncludePath;
    }

    /**
     * Turns off searching the prefix and fallback directories for classes
     * that have not been registered with the class map.
     *
     * @param bool $classMapAuthoritative
     */
    public function setClassMapAuthoritative($classMapAuthoritative)
    {
        $this->classMapAuthoritative = $classMapAuthoritative;
    }

    /**
     * Should class lookup fail if not found in the current class map?
     *
     * @return bool
     */
    public function isClassMapAuthoritative()
    {
        return $this->classMapAuthoritative;
    }

    /**
     * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
     *
     * @param string|null $apcuPrefix
     */
    public function setApcuPrefix($apcuPrefix)
    {
        $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
    }

    /**
     * The APCu prefix in use, or null if APCu caching is not enabled.
     *
     * @return string|null
     */
    public function getApcuPrefix()
    {
        return $this->apcuPrefix;
    }

    /**
     * Registers this instance as an autoloader.
     *
     * @param bool $prepend Whether to prepend the autoloader or not
     */
    public function register($prepend = false)
    {
        spl_autoload_register(array($this, 'loadClass'), true, $prepend);
    }

    /**
     * Unregisters this instance as an autoloader.
     */
    public function unregister()
    {
        spl_autoload_unregister(array($this, 'loadClass'));
    }

    /**
     * Loads the given class or interface.
     *
     * @param  string    $class The name of the class
     * @return bool|null True if loaded, null otherwise
     */
    public function loadClass($class)
    {
        if ($file = $this->findFile($class)) {
            includeFile($file);

            return true;
        }
    }

    /**
     * Finds the path to the file where the class is defined.
     *
     * @param string $class The name of the class
     *
     * @return string|false The path if found, false otherwise
     */
    public function findFile($class)
    {
        // class map lookup
        if (isset($this->classMap[$class])) {
            return $this->classMap[$class];
        }
        if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
            return false;
        }
        if (null !== $this->apcuPrefix) {
            $file = apcu_fetch($this->apcuPrefix.$class, $hit);
            if ($hit) {
                return $file;
            }
        }

        $file = $this->findFileWithExtension($class, '.php');

        // Search for Hack files if we are running on HHVM
        if (false === $file && defined('HHVM_VERSION')) {
            $file = $this->findFileWithExtension($class, '.hh');
        }

        if (null !== $this->apcuPrefix) {
            apcu_add($this->apcuPrefix.$class, $file);
        }

        if (false === $file) {
            // Remember that this class does not exist.
            $this->missingClasses[$class] = true;
        }

        return $file;
    }

    private function findFileWithExtension($class, $ext)
    {
        // PSR-4 lookup
        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;

        $first = $class[0];
        if (isset($this->prefixLengthsPsr4[$first])) {
            foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
                if (0 === strpos($class, $prefix)) {
                    foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
                        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
                            return $file;
                        }
                    }
                }
            }
        }

        // PSR-4 fallback dirs
        foreach ($this->fallbackDirsPsr4 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
                return $file;
            }
        }

        // PSR-0 lookup
        if (false !== $pos = strrpos($class, '\\')) {
            // namespaced class name
            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
        } else {
            // PEAR-like class name
            $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
        }

        if (isset($this->prefixesPsr0[$first])) {
            foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
                if (0 === strpos($class, $prefix)) {
                    foreach ($dirs as $dir) {
                        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                            return $file;
                        }
                    }
                }
            }
        }

        // PSR-0 fallback dirs
        foreach ($this->fallbackDirsPsr0 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                return $file;
            }
        }

        // PSR-0 include paths.
        if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
            return $file;
        }

        return false;
    }
}

/**
 * Scope isolated include.
 *
 * Prevents access to $this/self from included files.
 */
function includeFile($file)
{
    include $file;
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Filesystem\Exception;

/**
 * Exception class thrown when a filesystem operation failure happens
 *
 * @author Romain Neutron <imprec@gmail.com>
 *
 * @api
 */
class IOException extends \RuntimeException implements ExceptionInterface
{

}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Filesystem\Exception;

/**
 * Exception interface for all exceptions thrown by the component.
 *
 * @author Romain Neutron <imprec@gmail.com>
 *
 * @api
 */
interface ExceptionInterface
{

}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Filesystem;

use Symfony\Component\Filesystem\Exception\IOException;

/**
 * Provides basic utility to manipulate the file system.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class Filesystem
{
    /**
     * Copies a file.
     *
     * This method only copies the file if the origin file is newer than the target file.
     *
     * By default, if the target already exists, it is not overridden.
     *
     * @param string  $originFile The original filename
     * @param string  $targetFile The target filename
     * @param boolean $override   Whether to override an existing file or not
     *
     * @throws IOException When copy fails
     */
    public function copy($originFile, $targetFile, $override = false)
    {
        if (stream_is_local($originFile) && !is_file($originFile)) {
            throw new IOException(sprintf('Failed to copy %s because file not exists', $originFile));
        }

        $this->mkdir(dirname($targetFile));

        if (!$override && is_file($targetFile)) {
            $doCopy = filemtime($originFile) > filemtime($targetFile);
        } else {
            $doCopy = true;
        }

        if ($doCopy) {
            // https://bugs.php.net/bug.php?id=64634
            $source = fopen($originFile, 'r');
            $target = fopen($targetFile, 'w+');
            stream_copy_to_stream($source, $target);
            fclose($source);
            fclose($target);
            unset($source, $target);

            if (!is_file($targetFile)) {
                throw new IOException(sprintf('Failed to copy %s to %s', $originFile, $targetFile));
            }
        }
    }

    /**
     * Creates a directory recursively.
     *
     * @param string|array|\Traversable $dirs The directory path
     * @param integer                   $mode The directory mode
     *
     * @throws IOException On any directory creation failure
     */
    public function mkdir($dirs, $mode = 0777)
    {
        foreach ($this->toIterator($dirs) as $dir) {
            if (is_dir($dir)) {
                continue;
            }

            if (true !== @mkdir($dir, $mode, true)) {
                throw new IOException(sprintf('Failed to create %s', $dir));
            }
        }
    }

    /**
     * Checks the existence of files or directories.
     *
     * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to check
     *
     * @return Boolean true if the file exists, false otherwise
     */
    public function exists($files)
    {
        foreach ($this->toIterator($files) as $file) {
            if (!file_exists($file)) {
                return false;
            }
        }

        return true;
    }

    /**
     * Sets access and modification time of file.
     *
     * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to create
     * @param integer                   $time  The touch time as a unix timestamp
     * @param integer                   $atime The access time as a unix timestamp
     *
     * @throws IOException When touch fails
     */
    public function touch($files, $time = null, $atime = null)
    {
        foreach ($this->toIterator($files) as $file) {
            $touch = $time ? @touch($file, $time, $atime) : @touch($file);
            if (true !== $touch) {
                throw new IOException(sprintf('Failed to touch %s', $file));
            }
        }
    }

    /**
     * Removes files or directories.
     *
     * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to remove
     *
     * @throws IOException When removal fails
     */
    public function remove($files)
    {
        $files = iterator_to_array($this->toIterator($files));
        $files = array_reverse($files);
        foreach ($files as $file) {
            if (!file_exists($file) && !is_link($file)) {
                continue;
            }

            if (is_dir($file) && !is_link($file)) {
                $this->remove(new \FilesystemIterator($file));

                if (true !== @rmdir($file)) {
                    throw new IOException(sprintf('Failed to remove directory %s', $file));
                }
            } else {
                // https://bugs.php.net/bug.php?id=52176
                if (defined('PHP_WINDOWS_VERSION_MAJOR') && is_dir($file)) {
                    if (true !== @rmdir($file)) {
                        throw new IOException(sprintf('Failed to remove file %s', $file));
                    }
                } else {
                    if (true !== @unlink($file)) {
                        throw new IOException(sprintf('Failed to remove file %s', $file));
                    }
                }
            }
        }
    }

    /**
     * Change mode for an array of files or directories.
     *
     * @param string|array|\Traversable $files     A filename, an array of files, or a \Traversable instance to change mode
     * @param integer                   $mode      The new mode (octal)
     * @param integer                   $umask     The mode mask (octal)
     * @param Boolean                   $recursive Whether change the mod recursively or not
     *
     * @throws IOException When the change fail
     */
    public function chmod($files, $mode, $umask = 0000, $recursive = false)
    {
        foreach ($this->toIterator($files) as $file) {
            if ($recursive && is_dir($file) && !is_link($file)) {
                $this->chmod(new \FilesystemIterator($file), $mode, $umask, true);
            }
            if (true !== @chmod($file, $mode & ~$umask)) {
                throw new IOException(sprintf('Failed to chmod file %s', $file));
            }
        }
    }

    /**
     * Change the owner of an array of files or directories
     *
     * @param string|array|\Traversable $files     A filename, an array of files, or a \Traversable instance to change owner
     * @param string                    $user      The new owner user name
     * @param Boolean                   $recursive Whether change the owner recursively or not
     *
     * @throws IOException When the change fail
     */
    public function chown($files, $user, $recursive = false)
    {
        foreach ($this->toIterator($files) as $file) {
            if ($recursive && is_dir($file) && !is_link($file)) {
                $this->chown(new \FilesystemIterator($file), $user, true);
            }
            if (is_link($file) && function_exists('lchown')) {
                if (true !== @lchown($file, $user)) {
                    throw new IOException(sprintf('Failed to chown file %s', $file));
                }
            } else {
                if (true !== @chown($file, $user)) {
                    throw new IOException(sprintf('Failed to chown file %s', $file));
                }
            }
        }
    }

    /**
     * Change the group of an array of files or directories
     *
     * @param string|array|\Traversable $files     A filename, an array of files, or a \Traversable instance to change group
     * @param string                    $group     The group name
     * @param Boolean                   $recursive Whether change the group recursively or not
     *
     * @throws IOException When the change fail
     */
    public function chgrp($files, $group, $recursive = false)
    {
        foreach ($this->toIterator($files) as $file) {
            if ($recursive && is_dir($file) && !is_link($file)) {
                $this->chgrp(new \FilesystemIterator($file), $group, true);
            }
            if (is_link($file) && function_exists('lchgrp')) {
                if (true !== @lchgrp($file, $group)) {
                    throw new IOException(sprintf('Failed to chgrp file %s', $file));
                }
            } else {
                if (true !== @chgrp($file, $group)) {
                    throw new IOException(sprintf('Failed to chgrp file %s', $file));
                }
            }
        }
    }

    /**
     * Renames a file.
     *
     * @param string  $origin    The origin filename
     * @param string  $target    The new filename
     * @param Boolean $overwrite Whether to overwrite the target if it already exists
     *
     * @throws IOException When target file already exists
     * @throws IOException When origin cannot be renamed
     */
    public function rename($origin, $target, $overwrite = false)
    {
        // we check that target does not exist
        if (!$overwrite && is_readable($target)) {
            throw new IOException(sprintf('Cannot rename because the target "%s" already exist.', $target));
        }

        if (true !== @rename($origin, $target)) {
            throw new IOException(sprintf('Cannot rename "%s" to "%s".', $origin, $target));
        }
    }

    /**
     * Creates a symbolic link or copy a directory.
     *
     * @param string  $originDir     The origin directory path
     * @param string  $targetDir     The symbolic link name
     * @param Boolean $copyOnWindows Whether to copy files if on Windows
     *
     * @throws IOException When symlink fails
     */
    public function symlink($originDir, $targetDir, $copyOnWindows = false)
    {
        if (!function_exists('symlink') && $copyOnWindows) {
            $this->mirror($originDir, $targetDir);

            return;
        }

        $this->mkdir(dirname($targetDir));

        $ok = false;
        if (is_link($targetDir)) {
            if (readlink($targetDir) != $originDir) {
                $this->remove($targetDir);
            } else {
                $ok = true;
            }
        }

        if (!$ok) {
            if (true !== @symlink($originDir, $targetDir)) {
                $report = error_get_last();
                if (is_array($report)) {
                    if (defined('PHP_WINDOWS_VERSION_MAJOR') && false !== strpos($report['message'], 'error code(1314)')) {
                        throw new IOException('Unable to create symlink due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?');
                    }
                }
                throw new IOException(sprintf('Failed to create symbolic link from %s to %s', $originDir, $targetDir));
            }
        }
    }

    /**
     * Given an existing path, convert it to a path relative to a given starting path
     *
     * @param string $endPath   Absolute path of target
     * @param string $startPath Absolute path where traversal begins
     *
     * @return string Path of target relative to starting path
     */
    public function makePathRelative($endPath, $startPath)
    {
        // Normalize separators on windows
        if (defined('PHP_WINDOWS_VERSION_MAJOR')) {
            $endPath = strtr($endPath, '\\', '/');
            $startPath = strtr($startPath, '\\', '/');
        }

        // Split the paths into arrays
        $startPathArr = explode('/', trim($startPath, '/'));
        $endPathArr = explode('/', trim($endPath, '/'));

        // Find for which directory the common path stops
        $index = 0;
        while (isset($startPathArr[$index]) && isset($endPathArr[$index]) && $startPathArr[$index] === $endPathArr[$index]) {
            $index++;
        }

        // Determine how deep the start path is relative to the common path (ie, "web/bundles" = 2 levels)
        $depth = count($startPathArr) - $index;

        // Repeated "../" for each level need to reach the common path
        $traverser = str_repeat('../', $depth);

        $endPathRemainder = implode('/', array_slice($endPathArr, $index));

        // Construct $endPath from traversing to the common path, then to the remaining $endPath
        $relativePath = $traverser.(strlen($endPathRemainder) > 0 ? $endPathRemainder.'/' : '');

        return (strlen($relativePath) === 0) ? './' : $relativePath;
    }

    /**
     * Mirrors a directory to another.
     *
     * @param string       $originDir The origin directory
     * @param string       $targetDir The target directory
     * @param \Traversable $iterator  A Traversable instance
     * @param array        $options   An array of boolean options
     *                               Valid options are:
     *                                 - $options['override'] Whether to override an existing file on copy or not (see copy())
     *                                 - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see symlink())
     *                                 - $options['delete'] Whether to delete files that are not in the source directory (defaults to false)
     *
     * @throws IOException When file type is unknown
     */
    public function mirror($originDir, $targetDir, \Traversable $iterator = null, $options = array())
    {
        $targetDir = rtrim($targetDir, '/\\');
        $originDir = rtrim($originDir, '/\\');

        // Iterate in destination folder to remove obsolete entries
        if ($this->exists($targetDir) && isset($options['delete']) && $options['delete']) {
            $deleteIterator = $iterator;
            if (null === $deleteIterator) {
                $flags = \FilesystemIterator::SKIP_DOTS;
                $deleteIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($targetDir, $flags), \RecursiveIteratorIterator::CHILD_FIRST);
            }
            foreach ($deleteIterator as $file) {
                $origin = str_replace($targetDir, $originDir, $file->getPathname());
                if (!$this->exists($origin)) {
                    $this->remove($file);
                }
            }
        }

        $copyOnWindows = false;
        if (isset($options['copy_on_windows']) && !function_exists('symlink')) {
            $copyOnWindows = $options['copy_on_windows'];
        }

        if (null === $iterator) {
            $flags = $copyOnWindows ? \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::FOLLOW_SYMLINKS : \FilesystemIterator::SKIP_DOTS;
            $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($originDir, $flags), \RecursiveIteratorIterator::SELF_FIRST);
        }

        foreach ($iterator as $file) {
            $target = str_replace($originDir, $targetDir, $file->getPathname());

            if ($copyOnWindows) {
                if (is_link($file) || is_file($file)) {
                    $this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
                } elseif (is_dir($file)) {
                    $this->mkdir($target);
                } else {
                    throw new IOException(sprintf('Unable to guess "%s" file type.', $file));
                }
            } else {
                if (is_link($file)) {
                    $this->symlink($file, $target);
                } elseif (is_dir($file)) {
                    $this->mkdir($target);
                } elseif (is_file($file)) {
                    $this->copy($file, $target, isset($options['override']) ? $options['override'] : false);
                } else {
                    throw new IOException(sprintf('Unable to guess "%s" file type.', $file));
                }
            }
        }
    }

    /**
     * Returns whether the file path is an absolute path.
     *
     * @param string $file A file path
     *
     * @return Boolean
     */
    public function isAbsolutePath($file)
    {
        if (strspn($file, '/\\', 0, 1)
            || (strlen($file) > 3 && ctype_alpha($file[0])
                && substr($file, 1, 1) === ':'
                && (strspn($file, '/\\', 2, 1))
            )
            || null !== parse_url($file, PHP_URL_SCHEME)
        ) {
            return true;
        }

        return false;
    }

    /**
     * @param mixed $files
     *
     * @return \Traversable
     */
    private function toIterator($files)
    {
        if (!$files instanceof \Traversable) {
            $files = new \ArrayObject(is_array($files) ? $files : array($files));
        }

        return $files;
    }

    /**
     * Atomically dumps content into a file.
     *
     * @param  string  $filename The file to be written to.
     * @param  string  $content  The data to write into the file.
     * @param  integer $mode     The file mode (octal).
     * @throws IOException       If the file cannot be written to.
     */
    public function dumpFile($filename, $content, $mode = 0666)
    {
        $dir = dirname($filename);

        if (!is_dir($dir)) {
            $this->mkdir($dir);
        } elseif (!is_writable($dir)) {
            throw new IOException(sprintf('Unable to write in the %s directory\n', $dir));
        }

        $tmpFile = tempnam($dir, basename($filename));

        if (false === @file_put_contents($tmpFile, $content)) {
            throw new IOException(sprintf('Failed to write file "%s".', $filename));
        }

        $this->rename($tmpFile, $filename, true);
        $this->chmod($filename, $mode);
    }
}
<?xml version="1.0" encoding="UTF-8"?>

<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false"
         syntaxCheck="false"
         bootstrap="vendor/autoload.php"
>
    <testsuites>
        <testsuite name="Symfony Filesystem Component Test Suite">
            <directory>./Tests/</directory>
        </testsuite>
    </testsuites>

    <filter>
        <whitelist>
            <directory>./</directory>
            <exclude>
                <directory>./Tests</directory>
            </exclude>
        </whitelist>
    </filter>
</phpunit>
{
    "name": "symfony/filesystem",
    "type": "library",
    "description": "Symfony Filesystem Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Filesystem\\": "" }
    },
    "target-dir": "Symfony/Component/Filesystem",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.3-dev"
        }
    }
}
Copyright (c) 2004-2013 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
CHANGELOG
=========

2.3.0
-----

 * added the dumpFile() method to atomically write files
 
2.2.0
-----

 * added a delete option for the mirror() method

2.1.0
-----

 * 24eb396 : BC Break : mkdir() function now throws exception in case of failure instead of returning Boolean value
 * created the component
Filesystem Component
====================

Filesystem provides basic utility to manipulate the file system:

```php
<?php

use Symfony\Component\Filesystem\Filesystem;

$filesystem = new Filesystem();

$filesystem->copy($originFile, $targetFile, $override = false);

$filesystem->mkdir($dirs, $mode = 0777);

$filesystem->touch($files, $time = null, $atime = null);

$filesystem->remove($files);

$filesystem->chmod($files, $mode, $umask = 0000, $recursive = false);

$filesystem->chown($files, $user, $recursive = false);

$filesystem->chgrp($files, $group, $recursive = false);

$filesystem->rename($origin, $target);

$filesystem->symlink($originDir, $targetDir, $copyOnWindows = false);

$filesystem->makePathRelative($endPath, $startPath);

$filesystem->mirror($originDir, $targetDir, \Traversable $iterator = null, $options = array());

$filesystem->isAbsolutePath($file);
```

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/Filesystem/
    $ composer.phar install --dev
    $ phpunit
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection;

use Symfony\Component\Config\Util\XmlUtils;

/**
 * SimpleXMLElement class.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class SimpleXMLElement extends \SimpleXMLElement
{
    /**
     * Converts an attribute as a php type.
     *
     * @param string $name
     *
     * @return mixed
     */
    public function getAttributeAsPhp($name)
    {
        return self::phpize($this[$name]);
    }

    /**
     * Returns arguments as valid php types.
     *
     * @param string  $name
     * @param Boolean $lowercase
     *
     * @return mixed
     */
    public function getArgumentsAsPhp($name, $lowercase = true)
    {
        $arguments = array();
        foreach ($this->$name as $arg) {
            if (isset($arg['name'])) {
                $arg['key'] = (string) $arg['name'];
            }
            $key = isset($arg['key']) ? (string) $arg['key'] : (!$arguments ? 0 : max(array_keys($arguments)) + 1);

            // parameter keys are case insensitive
            if ('parameter' == $name && $lowercase) {
                $key = strtolower($key);
            }

            // this is used by DefinitionDecorator to overwrite a specific
            // argument of the parent definition
            if (isset($arg['index'])) {
                $key = 'index_'.$arg['index'];
            }

            switch ($arg['type']) {
                case 'service':
                    $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
                    if (isset($arg['on-invalid']) && 'ignore' == $arg['on-invalid']) {
                        $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
                    } elseif (isset($arg['on-invalid']) && 'null' == $arg['on-invalid']) {
                        $invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE;
                    }

                    if (isset($arg['strict'])) {
                        $strict = self::phpize($arg['strict']);
                    } else {
                        $strict = true;
                    }

                    $arguments[$key] = new Reference((string) $arg['id'], $invalidBehavior, $strict);
                    break;
                case 'collection':
                    $arguments[$key] = $arg->getArgumentsAsPhp($name, false);
                    break;
                case 'string':
                    $arguments[$key] = (string) $arg;
                    break;
                case 'constant':
                    $arguments[$key] = constant((string) $arg);
                    break;
                default:
                    $arguments[$key] = self::phpize($arg);
            }
        }

        return $arguments;
    }

    /**
     * Converts an xml value to a php type.
     *
     * @param mixed $value
     *
     * @return mixed
     */
    public static function phpize($value)
    {
        return XmlUtils::phpize($value);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Dumper;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;

/**
 * XmlDumper dumps a service container as an XML string.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Martin HasoÅˆ <martin.hason@gmail.com>
 *
 * @api
 */
class XmlDumper extends Dumper
{
    /**
     * @var \DOMDocument
     */
    private $document;

    /**
     * Dumps the service container as an XML string.
     *
     * @param array $options An array of options
     *
     * @return string An xml string representing of the service container
     *
     * @api
     */
    public function dump(array $options = array())
    {
        $this->document = new \DOMDocument('1.0', 'utf-8');
        $this->document->formatOutput = true;

        $container = $this->document->createElementNS('http://symfony.com/schema/dic/services', 'container');
        $container->setAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
        $container->setAttribute('xsi:schemaLocation', 'http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd');

        $this->addParameters($container);
        $this->addServices($container);

        $this->document->appendChild($container);
        $xml = $this->document->saveXML();
        $this->document = null;

        return $xml;
    }

    /**
     * Adds parameters.
     *
     * @param \DOMElement $parent
     */
    private function addParameters(\DOMElement $parent)
    {
        $data = $this->container->getParameterBag()->all();
        if (!$data) {
            return;
        }

        if ($this->container->isFrozen()) {
            $data = $this->escape($data);
        }

        $parameters = $this->document->createElement('parameters');
        $parent->appendChild($parameters);
        $this->convertParameters($data, 'parameter', $parameters);
    }

    /**
     * Adds method calls.
     *
     * @param array       $methodcalls
     * @param \DOMElement $parent
     */
    private function addMethodCalls(array $methodcalls, \DOMElement $parent)
    {
        foreach ($methodcalls as $methodcall) {
            $call = $this->document->createElement('call');
            $call->setAttribute('method', $methodcall[0]);
            if (count($methodcall[1])) {
                $this->convertParameters($methodcall[1], 'argument', $call);
            }
            $parent->appendChild($call);
        }
    }

    /**
     * Adds a service.
     *
     * @param Definition  $definition
     * @param string      $id
     * @param \DOMElement $parent
     */
    private function addService($definition, $id, \DOMElement $parent)
    {
        $service = $this->document->createElement('service');
        if (null !== $id) {
            $service->setAttribute('id', $id);
        }
        if ($definition->getClass()) {
            $service->setAttribute('class', $definition->getClass());
        }
        if ($definition->getFactoryMethod()) {
            $service->setAttribute('factory-method', $definition->getFactoryMethod());
        }
        if ($definition->getFactoryService()) {
            $service->setAttribute('factory-service', $definition->getFactoryService());
        }
        if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope()) {
            $service->setAttribute('scope', $scope);
        }
        if (!$definition->isPublic()) {
            $service->setAttribute('public', 'false');
        }
        if ($definition->isSynthetic()) {
            $service->setAttribute('synthetic', 'true');
        }
        if ($definition->isSynchronized()) {
            $service->setAttribute('synchronized', 'true');
        }
        if ($definition->isLazy()) {
            $service->setAttribute('lazy', 'true');
        }

        foreach ($definition->getTags() as $name => $tags) {
            foreach ($tags as $attributes) {
                $tag = $this->document->createElement('tag');
                $tag->setAttribute('name', $name);
                foreach ($attributes as $key => $value) {
                    $tag->setAttribute($key, $value);
                }
                $service->appendChild($tag);
            }
        }

        if ($definition->getFile()) {
            $file = $this->document->createElement('file');
            $file->appendChild($this->document->createTextNode($definition->getFile()));
            $service->appendChild($file);
        }

        if ($parameters = $definition->getArguments()) {
            $this->convertParameters($parameters, 'argument', $service);
        }

        if ($parameters = $definition->getProperties()) {
            $this->convertParameters($parameters, 'property', $service, 'name');
        }

        $this->addMethodCalls($definition->getMethodCalls(), $service);

        if ($callable = $definition->getConfigurator()) {
            $configurator = $this->document->createElement('configurator');
            if (is_array($callable)) {
                $configurator->setAttribute($callable[0] instanceof Reference ? 'service' : 'class', $callable[0]);
                $configurator->setAttribute('method', $callable[1]);
            } else {
                $configurator->setAttribute('function', $callable);
            }
            $service->appendChild($configurator);
        }

        $parent->appendChild($service);
    }

    /**
     * Adds a service alias.
     *
     * @param string      $alias
     * @param string      $id
     * @param \DOMElement $parent
     */
    private function addServiceAlias($alias, $id, \DOMElement $parent)
    {
        $service = $this->document->createElement('service');
        $service->setAttribute('id', $alias);
        $service->setAttribute('alias', $id);
        if (!$id->isPublic()) {
            $service->setAttribute('public', 'false');
        }
        $parent->appendChild($service);
    }

    /**
     * Adds services.
     *
     * @param \DOMElement $parent
     */
    private function addServices(\DOMElement $parent)
    {
        $definitions = $this->container->getDefinitions();
        if (!$definitions) {
            return;
        }

        $services = $this->document->createElement('services');
        foreach ($definitions as $id => $definition) {
            $this->addService($definition, $id, $services);
        }

        foreach ($this->container->getAliases() as $alias => $id) {
            $this->addServiceAlias($alias, $id, $services);
        }
        $parent->appendChild($services);
    }

    /**
     * Converts parameters.
     *
     * @param array       $parameters
     * @param string      $type
     * @param \DOMElement $parent
     * @param string      $keyAttribute
     */
    private function convertParameters($parameters, $type, \DOMElement $parent, $keyAttribute = 'key')
    {
        $withKeys = array_keys($parameters) !== range(0, count($parameters) - 1);
        foreach ($parameters as $key => $value) {
            $element = $this->document->createElement($type);
            if ($withKeys) {
                $element->setAttribute($keyAttribute, $key);
            }

            if (is_array($value)) {
                $element->setAttribute('type', 'collection');
                $this->convertParameters($value, $type, $element, 'key');
            } elseif ($value instanceof Reference) {
                $element->setAttribute('type', 'service');
                $element->setAttribute('id', (string) $value);
                $behaviour = $value->getInvalidBehavior();
                if ($behaviour == ContainerInterface::NULL_ON_INVALID_REFERENCE) {
                    $element->setAttribute('on-invalid', 'null');
                } elseif ($behaviour == ContainerInterface::IGNORE_ON_INVALID_REFERENCE) {
                    $element->setAttribute('on-invalid', 'ignore');
                }
                if (!$value->isStrict()) {
                    $element->setAttribute('strict', 'false');
                }
            } elseif ($value instanceof Definition) {
                $element->setAttribute('type', 'service');
                $this->addService($value, null, $element);
            } else {
                if (in_array($value, array('null', 'true', 'false'), true)) {
                    $element->setAttribute('type', 'string');
                }
                $text = $this->document->createTextNode(self::phpToXml($value));
                $element->appendChild($text);
            }
            $parent->appendChild($element);
        }
    }

    /**
     * Escapes arguments
     *
     * @param array $arguments
     *
     * @return array
     */
    private function escape($arguments)
    {
        $args = array();
        foreach ($arguments as $k => $v) {
            if (is_array($v)) {
                $args[$k] = $this->escape($v);
            } elseif (is_string($v)) {
                $args[$k] = str_replace('%', '%%', $v);
            } else {
                $args[$k] = $v;
            }
        }

        return $args;
    }

    /**
     * Converts php types to xml types.
     *
     * @param mixed $value Value to convert
     *
     * @return string
     *
     * @throws RuntimeException When trying to dump object or resource
     */
    public static function phpToXml($value)
    {
        switch (true) {
            case null === $value:
                return 'null';
            case true === $value:
                return 'true';
            case false === $value:
                return 'false';
            case $value instanceof Parameter:
                return '%'.$value.'%';
            case is_object($value) || is_resource($value):
                throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
            default:
                return (string) $value;
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Dumper;

use Symfony\Component\Yaml\Dumper as YmlDumper;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
 * YamlDumper dumps a service container as a YAML string.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @api
 */
class YamlDumper extends Dumper
{
    private $dumper;

    /**
     * Constructor.
     *
     * @param ContainerBuilder $container The service container to dump
     *
     * @api
     */
    public function __construct(ContainerBuilder $container)
    {
        parent::__construct($container);

        $this->dumper = new YmlDumper();
    }

    /**
     * Dumps the service container as an YAML string.
     *
     * @param array $options An array of options
     *
     * @return string A YAML string representing of the service container
     *
     * @api
     */
    public function dump(array $options = array())
    {
        return $this->addParameters()."\n".$this->addServices();
    }

    /**
     * Adds a service
     *
     * @param string     $id
     * @param Definition $definition
     *
     * @return string
     */
    private function addService($id, $definition)
    {
        $code = "    $id:\n";
        if ($definition->getClass()) {
            $code .= sprintf("        class: %s\n", $definition->getClass());
        }

        $tagsCode = '';
        foreach ($definition->getTags() as $name => $tags) {
            foreach ($tags as $attributes) {
                $att = array();
                foreach ($attributes as $key => $value) {
                    $att[] = sprintf('%s: %s', $this->dumper->dump($key), $this->dumper->dump($value));
                }
                $att = $att ? ', '.implode(' ', $att) : '';

                $tagsCode .= sprintf("            - { name: %s%s }\n", $this->dumper->dump($name), $att);
            }
        }
        if ($tagsCode) {
            $code .= "        tags:\n".$tagsCode;
        }

        if ($definition->getFile()) {
            $code .= sprintf("        file: %s\n", $definition->getFile());
        }

        if ($definition->isSynthetic()) {
            $code .= sprintf("        synthetic: true\n");
        }

        if ($definition->isSynchronized()) {
            $code .= sprintf("        synchronized: true\n");
        }

        if ($definition->getFactoryClass()) {
            $code .= sprintf("        factory_class: %s\n", $definition->getFactoryClass());
        }

        if ($definition->isLazy()) {
            $code .= sprintf("        lazy: true\n");
        }

        if ($definition->getFactoryMethod()) {
            $code .= sprintf("        factory_method: %s\n", $definition->getFactoryMethod());
        }

        if ($definition->getFactoryService()) {
            $code .= sprintf("        factory_service: %s\n", $definition->getFactoryService());
        }

        if ($definition->getArguments()) {
            $code .= sprintf("        arguments: %s\n", $this->dumper->dump($this->dumpValue($definition->getArguments()), 0));
        }

        if ($definition->getProperties()) {
            $code .= sprintf("        properties: %s\n", $this->dumper->dump($this->dumpValue($definition->getProperties()), 0));
        }

        if ($definition->getMethodCalls()) {
            $code .= sprintf("        calls:\n%s\n", $this->dumper->dump($this->dumpValue($definition->getMethodCalls()), 1, 12));
        }

        if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope()) {
            $code .= sprintf("        scope: %s\n", $scope);
        }

        if ($callable = $definition->getConfigurator()) {
            if (is_array($callable)) {
                if ($callable[0] instanceof Reference) {
                    $callable = array($this->getServiceCall((string) $callable[0], $callable[0]), $callable[1]);
                } else {
                    $callable = array($callable[0], $callable[1]);
                }
            }

            $code .= sprintf("        configurator: %s\n", $this->dumper->dump($callable, 0));
        }

        return $code;
    }

    /**
     * Adds a service alias
     *
     * @param string $alias
     * @param Alias  $id
     *
     * @return string
     */
    private function addServiceAlias($alias, $id)
    {
        if ($id->isPublic()) {
            return sprintf("    %s: @%s\n", $alias, $id);
        } else {
            return sprintf("    %s:\n        alias: %s\n        public: false", $alias, $id);
        }
    }

    /**
     * Adds services
     *
     * @return string
     */
    private function addServices()
    {
        if (!$this->container->getDefinitions()) {
            return '';
        }

        $code = "services:\n";
        foreach ($this->container->getDefinitions() as $id => $definition) {
            $code .= $this->addService($id, $definition);
        }

        foreach ($this->container->getAliases() as $alias => $id) {
            $code .= $this->addServiceAlias($alias, $id);
        }

        return $code;
    }

    /**
     * Adds parameters
     *
     * @return string
     */
    private function addParameters()
    {
        if (!$this->container->getParameterBag()->all()) {
            return '';
        }

        $parameters = $this->prepareParameters($this->container->getParameterBag()->all(), $this->container->isFrozen());

        return $this->dumper->dump(array('parameters' => $parameters), 2);
    }

    /**
     * Dumps the value to YAML format
     *
     * @param mixed $value
     *
     * @return mixed
     *
     * @throws RuntimeException When trying to dump object or resource
     */
    private function dumpValue($value)
    {
        if (is_array($value)) {
            $code = array();
            foreach ($value as $k => $v) {
                $code[$k] = $this->dumpValue($v);
            }

            return $code;
        } elseif ($value instanceof Reference) {
            return $this->getServiceCall((string) $value, $value);
        } elseif ($value instanceof Parameter) {
            return $this->getParameterCall((string) $value);
        } elseif (is_object($value) || is_resource($value)) {
            throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
        }

        return $value;
    }

    /**
     * Gets the service call.
     *
     * @param string    $id
     * @param Reference $reference
     *
     * @return string
     */
    private function getServiceCall($id, Reference $reference = null)
    {
        if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
            return sprintf('@?%s', $id);
        }

        return sprintf('@%s', $id);
    }

    /**
     * Gets parameter call.
     *
     * @param string $id
     *
     * @return string
     */
    private function getParameterCall($id)
    {
        return sprintf('%%%s%%', $id);
    }

    /**
     * Prepares parameters.
     *
     * @param array   $parameters
     * @param Boolean $escape
     *
     * @return array
     */
    private function prepareParameters($parameters, $escape = true)
    {
        $filtered = array();
        foreach ($parameters as $key => $value) {
            if (is_array($value)) {
                $value = $this->prepareParameters($value, $escape);
            } elseif ($value instanceof Reference || is_string($value) && 0 === strpos($value, '@')) {
                $value = '@'.$value;
            }

            $filtered[$key] = $value;
        }

        return $escape ? $this->escape($filtered) : $filtered;
    }

    /**
     * Escapes arguments
     *
     * @param array $arguments
     *
     * @return array
     */
    private function escape($arguments)
    {
        $args = array();
        foreach ($arguments as $k => $v) {
            if (is_array($v)) {
                $args[$k] = $this->escape($v);
            } elseif (is_string($v)) {
                $args[$k] = str_replace('%', '%%', $v);
            } else {
                $args[$k] = $v;
            }
        }

        return $args;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Dumper;

use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;

/**
 * GraphvizDumper dumps a service container as a graphviz file.
 *
 * You can convert the generated dot file with the dot utility (http://www.graphviz.org/):
 *
 *   dot -Tpng container.dot > foo.png
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class GraphvizDumper extends Dumper
{
    private $nodes;
    private $edges;
    private $options = array(
            'graph' => array('ratio' => 'compress'),
            'node'  => array('fontsize' => 11, 'fontname' => 'Arial', 'shape' => 'record'),
            'edge'  => array('fontsize' => 9, 'fontname' => 'Arial', 'color' => 'grey', 'arrowhead' => 'open', 'arrowsize' => 0.5),
            'node.instance' => array('fillcolor' => '#9999ff', 'style' => 'filled'),
            'node.definition' => array('fillcolor' => '#eeeeee'),
            'node.missing' => array('fillcolor' => '#ff9999', 'style' => 'filled'),
        );

    /**
     * Dumps the service container as a graphviz graph.
     *
     * Available options:
     *
     *  * graph: The default options for the whole graph
     *  * node: The default options for nodes
     *  * edge: The default options for edges
     *  * node.instance: The default options for services that are defined directly by object instances
     *  * node.definition: The default options for services that are defined via service definition instances
     *  * node.missing: The default options for missing services
     *
     * @param array $options An array of options
     *
     * @return string The dot representation of the service container
     */
    public function dump(array $options = array())
    {
        foreach (array('graph', 'node', 'edge', 'node.instance', 'node.definition', 'node.missing') as $key) {
            if (isset($options[$key])) {
                $this->options[$key] = array_merge($this->options[$key], $options[$key]);
            }
        }

        $this->nodes = $this->findNodes();

        $this->edges = array();
        foreach ($this->container->getDefinitions() as $id => $definition) {
            $this->edges[$id] = array_merge(
                $this->findEdges($id, $definition->getArguments(), true, ''),
                $this->findEdges($id, $definition->getProperties(), false, '')
            );

            foreach ($definition->getMethodCalls() as $call) {
                $this->edges[$id] = array_merge(
                    $this->edges[$id],
                    $this->findEdges($id, $call[1], false, $call[0].'()')
                );
            }
        }

        return $this->startDot().$this->addNodes().$this->addEdges().$this->endDot();
    }

    /**
     * Returns all nodes.
     *
     * @return string A string representation of all nodes
     */
    private function addNodes()
    {
        $code = '';
        foreach ($this->nodes as $id => $node) {
            $aliases = $this->getAliases($id);

            $code .= sprintf("  node_%s [label=\"%s\\n%s\\n\", shape=%s%s];\n", $this->dotize($id), $id.($aliases ? ' ('.implode(', ', $aliases).')' : ''), $node['class'], $this->options['node']['shape'], $this->addAttributes($node['attributes']));
        }

        return $code;
    }

    /**
     * Returns all edges.
     *
     * @return string A string representation of all edges
     */
    private function addEdges()
    {
        $code = '';
        foreach ($this->edges as $id => $edges) {
            foreach ($edges as $edge) {
                $code .= sprintf("  node_%s -> node_%s [label=\"%s\" style=\"%s\"];\n", $this->dotize($id), $this->dotize($edge['to']), $edge['name'], $edge['required'] ? 'filled' : 'dashed');
            }
        }

        return $code;
    }

    /**
     * Finds all edges belonging to a specific service id.
     *
     * @param string  $id        The service id used to find edges
     * @param array   $arguments An array of arguments
     * @param Boolean $required
     * @param string  $name
     *
     * @return array An array of edges
     */
    private function findEdges($id, $arguments, $required, $name)
    {
        $edges = array();
        foreach ($arguments as $argument) {
            if ($argument instanceof Parameter) {
                $argument = $this->container->hasParameter($argument) ? $this->container->getParameter($argument) : null;
            } elseif (is_string($argument) && preg_match('/^%([^%]+)%$/', $argument, $match)) {
                $argument = $this->container->hasParameter($match[1]) ? $this->container->getParameter($match[1]) : null;
            }

            if ($argument instanceof Reference) {
                if (!$this->container->has((string) $argument)) {
                    $this->nodes[(string) $argument] = array('name' => $name, 'required' => $required, 'class' => '', 'attributes' => $this->options['node.missing']);
                }

                $edges[] = array('name' => $name, 'required' => $required, 'to' => $argument);
            } elseif (is_array($argument)) {
                $edges = array_merge($edges, $this->findEdges($id, $argument, $required, $name));
            }
        }

        return $edges;
    }

    /**
     * Finds all nodes.
     *
     * @return array An array of all nodes
     */
    private function findNodes()
    {
        $nodes = array();

        $container = $this->cloneContainer();

        foreach ($container->getDefinitions() as $id => $definition) {
            $nodes[$id] = array('class' => str_replace('\\', '\\\\', $this->container->getParameterBag()->resolveValue($definition->getClass())), 'attributes' => array_merge($this->options['node.definition'], array('style' => ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope() ? 'filled' : 'dotted')));

            $container->setDefinition($id, new Definition('stdClass'));
        }

        foreach ($container->getServiceIds() as $id) {
            $service = $container->get($id);

            if (in_array($id, array_keys($container->getAliases()))) {
                continue;
            }

            if (!$container->hasDefinition($id)) {
                $class = ('service_container' === $id) ? get_class($this->container) : get_class($service);
                $nodes[$id] = array('class' => str_replace('\\', '\\\\', $class), 'attributes' => $this->options['node.instance']);
            }
        }

        return $nodes;
    }

    private function cloneContainer()
    {
        $parameterBag = new ParameterBag($this->container->getParameterBag()->all());

        $container = new ContainerBuilder($parameterBag);
        $container->setDefinitions($this->container->getDefinitions());
        $container->setAliases($this->container->getAliases());
        $container->setResources($this->container->getResources());
        foreach ($this->container->getScopes() as $scope) {
            $container->addScope($scope);
        }
        foreach ($this->container->getExtensions() as $extension) {
            $container->registerExtension($extension);
        }

        return $container;
    }

    /**
     * Returns the start dot.
     *
     * @return string The string representation of a start dot
     */
    private function startDot()
    {
        return sprintf("digraph sc {\n  %s\n  node [%s];\n  edge [%s];\n\n",
            $this->addOptions($this->options['graph']),
            $this->addOptions($this->options['node']),
            $this->addOptions($this->options['edge'])
        );
    }

    /**
     * Returns the end dot.
     *
     * @return string
     */
    private function endDot()
    {
        return "}\n";
    }

    /**
     * Adds attributes
     *
     * @param array $attributes An array of attributes
     *
     * @return string A comma separated list of attributes
     */
    private function addAttributes($attributes)
    {
        $code = array();
        foreach ($attributes as $k => $v) {
            $code[] = sprintf('%s="%s"', $k, $v);
        }

        return $code ? ', '.implode(', ', $code) : '';
    }

    /**
     * Adds options
     *
     * @param array $options An array of options
     *
     * @return string A space separated list of options
     */
    private function addOptions($options)
    {
        $code = array();
        foreach ($options as $k => $v) {
            $code[] = sprintf('%s="%s"', $k, $v);
        }

        return implode(' ', $code);
    }

    /**
     * Dotizes an identifier.
     *
     * @param string $id The identifier to dotize
     *
     * @return string A dotized string
     */
    private function dotize($id)
    {
        return strtolower(preg_replace('/[^\w]/i', '_', $id));
    }

    /**
     * Compiles an array of aliases for a specified service id.
     *
     * @param string $id A service id
     *
     * @return array An array of aliases
     */
    private function getAliases($id)
    {
        $aliases = array();
        foreach ($this->container->getAliases() as $alias => $origin) {
            if ($id == $origin) {
                $aliases[] = $alias;
            }
        }

        return $aliases;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Dumper;

/**
 * DumperInterface is the interface implemented by service container dumper classes.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @api
 */
interface DumperInterface
{
    /**
     * Dumps the service container.
     *
     * @param array $options An array of options
     *
     * @return string The representation of the service container
     *
     * @api
     */
    public function dump(array $options = array());
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Dumper;

use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
 * Dumper is the abstract class for all built-in dumpers.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @api
 */
abstract class Dumper implements DumperInterface
{
    protected $container;

    /**
     * Constructor.
     *
     * @param ContainerBuilder $container The service container to dump
     *
     * @api
     */
    public function __construct(ContainerBuilder $container)
    {
        $this->container = $container;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Dumper;

use Symfony\Component\DependencyInjection\Variable;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface as ProxyDumper;
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper;

/**
 * PhpDumper dumps a service container as a PHP class.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 *
 * @api
 */
class PhpDumper extends Dumper
{
    /**
     * Characters that might appear in the generated variable name as first character
     * @var string
     */
    const FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz';

    /**
     * Characters that might appear in the generated variable name as any but the first character
     * @var string
     */
    const NON_FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789_';

    private $inlinedDefinitions;
    private $definitionVariables;
    private $referenceVariables;
    private $variableCount;
    private $reservedVariables = array('instance', 'class');

    /**
     * @var \Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface
     */
    private $proxyDumper;

    /**
     * {@inheritDoc}
     *
     * @api
     */
    public function __construct(ContainerBuilder $container)
    {
        parent::__construct($container);

        $this->inlinedDefinitions = new \SplObjectStorage;
    }

    /**
     * Sets the dumper to be used when dumping proxies in the generated container.
     *
     * @param ProxyDumper $proxyDumper
     */
    public function setProxyDumper(ProxyDumper $proxyDumper)
    {
        $this->proxyDumper = $proxyDumper;
    }

    /**
     * Dumps the service container as a PHP class.
     *
     * Available options:
     *
     *  * class:      The class name
     *  * base_class: The base class name
     *
     * @param array $options An array of options
     *
     * @return string A PHP class representing of the service container
     *
     * @api
     */
    public function dump(array $options = array())
    {
        $options = array_merge(array(
            'class'      => 'ProjectServiceContainer',
            'base_class' => 'Container',
        ), $options);

        $code = $this->startClass($options['class'], $options['base_class']);

        if ($this->container->isFrozen()) {
            $code .= $this->addFrozenConstructor();
        } else {
            $code .= $this->addConstructor();
        }

        $code .=
            $this->addServices().
            $this->addDefaultParametersMethod().
            $this->endClass().
            $this->addProxyClasses()
        ;

        return $code;
    }

    /**
     * Retrieves the currently set proxy dumper or instantiates one.
     *
     * @return ProxyDumper
     */
    private function getProxyDumper()
    {
        if (!$this->proxyDumper) {
            $this->proxyDumper = new NullDumper();
        }

        return $this->proxyDumper;
    }

    /**
     * Generates Service local temp variables.
     *
     * @param string $cId
     * @param string $definition
     *
     * @return string
     */
    private function addServiceLocalTempVariables($cId, $definition)
    {
        static $template = "        \$%s = %s;\n";

        $localDefinitions = array_merge(
            array($definition),
            $this->getInlinedDefinitions($definition)
        );

        $calls = $behavior = array();
        foreach ($localDefinitions as $iDefinition) {
            $this->getServiceCallsFromArguments($iDefinition->getArguments(), $calls, $behavior);
            $this->getServiceCallsFromArguments($iDefinition->getMethodCalls(), $calls, $behavior);
            $this->getServiceCallsFromArguments($iDefinition->getProperties(), $calls, $behavior);
        }

        $code = '';
        foreach ($calls as $id => $callCount) {
            if ('service_container' === $id || $id === $cId) {
                continue;
            }

            if ($callCount > 1) {
                $name = $this->getNextVariableName();
                $this->referenceVariables[$id] = new Variable($name);

                if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $behavior[$id]) {
                    $code .= sprintf($template, $name, $this->getServiceCall($id));
                } else {
                    $code .= sprintf($template, $name, $this->getServiceCall($id, new Reference($id, ContainerInterface::NULL_ON_INVALID_REFERENCE)));
                }
            }
        }

        if ('' !== $code) {
            $code .= "\n";
        }

        return $code;
    }

    /**
     * Generates code for the proxies to be attached after the container class
     *
     * @return string
     */
    private function addProxyClasses()
    {
        /* @var $proxyDefinitions Definition[] */
        $definitions = array_filter(
            $this->container->getDefinitions(),
            array($this->getProxyDumper(), 'isProxyCandidate')
        );
        $code = '';

        foreach ($definitions as $definition) {
            $code .= "\n" . $this->getProxyDumper()->getProxyCode($definition);
        }

        return $code;
    }

    /**
     * Generates the require_once statement for service includes.
     *
     * @param string     $id         The service id
     * @param Definition $definition
     *
     * @return string
     */
    private function addServiceInclude($id, $definition)
    {
        $template = "        require_once %s;\n";
        $code = '';

        if (null !== $file = $definition->getFile()) {
            $code .= sprintf($template, $this->dumpValue($file));
        }

        foreach ($this->getInlinedDefinitions($definition) as $definition) {
            if (null !== $file = $definition->getFile()) {
                $code .= sprintf($template, $this->dumpValue($file));
            }
        }

        if ('' !== $code) {
            $code .= "\n";
        }

        return $code;
    }

    /**
     * Generates the inline definition of a service.
     *
     * @param string     $id
     * @param Definition $definition
     *
     * @return string
     *
     * @throws RuntimeException When the factory definition is incomplete
     * @throws ServiceCircularReferenceException When a circular reference is detected
     */
    private function addServiceInlinedDefinitions($id, $definition)
    {
        $code = '';
        $variableMap = $this->definitionVariables;
        $nbOccurrences = new \SplObjectStorage();
        $processed = new \SplObjectStorage();
        $inlinedDefinitions = $this->getInlinedDefinitions($definition);

        foreach ($inlinedDefinitions as $definition) {
            if (false === $nbOccurrences->contains($definition)) {
                $nbOccurrences->offsetSet($definition, 1);
            } else {
                $i = $nbOccurrences->offsetGet($definition);
                $nbOccurrences->offsetSet($definition, $i + 1);
            }
        }

        foreach ($inlinedDefinitions as $sDefinition) {
            if ($processed->contains($sDefinition)) {
                continue;
            }
            $processed->offsetSet($sDefinition);

            $class = $this->dumpValue($sDefinition->getClass());
            if ($nbOccurrences->offsetGet($sDefinition) > 1 || $sDefinition->getMethodCalls() || $sDefinition->getProperties() || null !== $sDefinition->getConfigurator() || false !== strpos($class, '$')) {
                $name = $this->getNextVariableName();
                $variableMap->offsetSet($sDefinition, new Variable($name));

                // a construct like:
                // $a = new ServiceA(ServiceB $b); $b = new ServiceB(ServiceA $a);
                // this is an indication for a wrong implementation, you can circumvent this problem
                // by setting up your service structure like this:
                // $b = new ServiceB();
                // $a = new ServiceA(ServiceB $b);
                // $b->setServiceA(ServiceA $a);
                if ($this->hasReference($id, $sDefinition->getArguments())) {
                    throw new ServiceCircularReferenceException($id, array($id));
                }

                $code .= $this->addNewInstance($id, $sDefinition, '$'.$name, ' = ');

                if (!$this->hasReference($id, $sDefinition->getMethodCalls(), true) && !$this->hasReference($id, $sDefinition->getProperties(), true)) {
                    $code .= $this->addServiceMethodCalls(null, $sDefinition, $name);
                    $code .= $this->addServiceProperties(null, $sDefinition, $name);
                    $code .= $this->addServiceConfigurator(null, $sDefinition, $name);
                }

                $code .= "\n";
            }
        }

        return $code;
    }

    /**
     * Adds the service return statement.
     *
     * @param string     $id         Service id
     * @param Definition $definition
     *
     * @return string
     */
    private function addServiceReturn($id, $definition)
    {
        if ($this->isSimpleInstance($id, $definition)) {
            return "    }\n";
        }

        return "\n        return \$instance;\n    }\n";
    }

    /**
     * Generates the service instance.
     *
     * @param string     $id
     * @param Definition $definition
     *
     * @return string
     *
     * @throws InvalidArgumentException
     * @throws RuntimeException
     */
    private function addServiceInstance($id, $definition)
    {
        $class = $this->dumpValue($definition->getClass());

        if (0 === strpos($class, "'") && !preg_match('/^\'[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*(\\\{2}[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)*\'$/', $class)) {
            throw new InvalidArgumentException(sprintf('"%s" is not a valid class name for the "%s" service.', $class, $id));
        }

        $simple           = $this->isSimpleInstance($id, $definition);
        $isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition);
        $instantiation    = '';

        if (!$isProxyCandidate && ContainerInterface::SCOPE_CONTAINER === $definition->getScope()) {
            $instantiation = "\$this->services['$id'] = ".($simple ? '' : '$instance');
        } elseif (!$isProxyCandidate && ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) {
            $instantiation = "\$this->services['$id'] = \$this->scopedServices['$scope']['$id'] = ".($simple ? '' : '$instance');
        } elseif (!$simple) {
            $instantiation = '$instance';
        }

        $return = '';
        if ($simple) {
            $return = 'return ';
        } else {
            $instantiation .= ' = ';
        }

        $code = $this->addNewInstance($id, $definition, $return, $instantiation);

        if (!$simple) {
            $code .= "\n";
        }

        return $code;
    }

    /**
     * Checks if the definition is a simple instance.
     *
     * @param string     $id
     * @param Definition $definition
     *
     * @return Boolean
     */
    private function isSimpleInstance($id, $definition)
    {
        foreach (array_merge(array($definition), $this->getInlinedDefinitions($definition)) as $sDefinition) {
            if ($definition !== $sDefinition && !$this->hasReference($id, $sDefinition->getMethodCalls())) {
                continue;
            }

            if ($sDefinition->getMethodCalls() || $sDefinition->getProperties() || $sDefinition->getConfigurator()) {
                return false;
            }
        }

        return true;
    }

    /**
     * Adds method calls to a service definition.
     *
     * @param string     $id
     * @param Definition $definition
     * @param string     $variableName
     *
     * @return string
     */
    private function addServiceMethodCalls($id, $definition, $variableName = 'instance')
    {
        $calls = '';
        foreach ($definition->getMethodCalls() as $call) {
            $arguments = array();
            foreach ($call[1] as $value) {
                $arguments[] = $this->dumpValue($value);
            }

            $calls .= $this->wrapServiceConditionals($call[1], sprintf("        \$%s->%s(%s);\n", $variableName, $call[0], implode(', ', $arguments)));
        }

        return $calls;
    }

    private function addServiceProperties($id, $definition, $variableName = 'instance')
    {
        $code = '';
        foreach ($definition->getProperties() as $name => $value) {
            $code .= sprintf("        \$%s->%s = %s;\n", $variableName, $name, $this->dumpValue($value));
        }

        return $code;
    }

    /**
     * Generates the inline definition setup.
     *
     * @param string     $id
     * @param Definition $definition
     * @return string
     */
    private function addServiceInlinedDefinitionsSetup($id, $definition)
    {
        $this->referenceVariables[$id] = new Variable('instance');

        $code = '';
        $processed = new \SplObjectStorage();
        foreach ($this->getInlinedDefinitions($definition) as $iDefinition) {
            if ($processed->contains($iDefinition)) {
                continue;
            }
            $processed->offsetSet($iDefinition);

            if (!$this->hasReference($id, $iDefinition->getMethodCalls(), true) && !$this->hasReference($id, $iDefinition->getProperties(), true)) {
                continue;
            }

            $name = (string) $this->definitionVariables->offsetGet($iDefinition);
            $code .= $this->addServiceMethodCalls(null, $iDefinition, $name);
            $code .= $this->addServiceProperties(null, $iDefinition, $name);
            $code .= $this->addServiceConfigurator(null, $iDefinition, $name);
        }

        if ('' !== $code) {
            $code .= "\n";
        }

        return $code;
    }

    /**
     * Adds configurator definition
     *
     * @param string     $id
     * @param Definition $definition
     * @param string     $variableName
     *
     * @return string
     */
    private function addServiceConfigurator($id, $definition, $variableName = 'instance')
    {
        if (!$callable = $definition->getConfigurator()) {
            return '';
        }

        if (is_array($callable)) {
            if ($callable[0] instanceof Reference) {
                return sprintf("        %s->%s(\$%s);\n", $this->getServiceCall((string) $callable[0]), $callable[1], $variableName);
            }

            return sprintf("        call_user_func(array(%s, '%s'), \$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
        }

        return sprintf("        %s(\$%s);\n", $callable, $variableName);
    }

    /**
     * Adds a service
     *
     * @param string     $id
     * @param Definition $definition
     *
     * @return string
     */
    private function addService($id, $definition)
    {
        $name = Container::camelize($id);
        $this->definitionVariables = new \SplObjectStorage();
        $this->referenceVariables = array();
        $this->variableCount = 0;

        $return = array();

        if ($definition->isSynthetic()) {
            $return[] = '@throws RuntimeException always since this service is expected to be injected dynamically';
        } elseif ($class = $definition->getClass()) {
            $return[] = sprintf("@return %s A %s instance.", 0 === strpos($class, '%') ? 'object' : $class, $class);
        } elseif ($definition->getFactoryClass()) {
            $return[] = sprintf('@return object An instance returned by %s::%s().', $definition->getFactoryClass(), $definition->getFactoryMethod());
        } elseif ($definition->getFactoryService()) {
            $return[] = sprintf('@return object An instance returned by %s::%s().', $definition->getFactoryService(), $definition->getFactoryMethod());
        }

        $scope = $definition->getScope();
        if (!in_array($scope, array(ContainerInterface::SCOPE_CONTAINER, ContainerInterface::SCOPE_PROTOTYPE))) {
            if ($return && 0 === strpos($return[count($return) - 1], '@return')) {
                $return[] = '';
            }
            $return[] = sprintf("@throws InactiveScopeException when the '%s' service is requested while the '%s' scope is not active", $id, $scope);
        }

        $return = implode("\n     * ", $return);

        $doc = '';
        if (ContainerInterface::SCOPE_PROTOTYPE !== $scope) {
            $doc .= <<<EOF

     *
     * This service is shared.
     * This method always returns the same instance of the service.
EOF;
        }

        if (!$definition->isPublic()) {
            $doc .= <<<EOF

     *
     * This service is private.
     * If you want to be able to request this service from the container directly,
     * make it public, otherwise you might end up with broken code.
EOF;
        }

        if ($definition->isLazy()) {
            $lazyInitialization    = '$lazyLoad = true';
            $lazyInitializationDoc = "\n     * @param boolean \$lazyLoad whether to try lazy-loading the service with a proxy\n     *";
        } else {
            $lazyInitialization    = '';
            $lazyInitializationDoc = '';
        }

        // with proxies, for 5.3.3 compatibility, the getter must be public to be accessible to the initializer
        $isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition);
        $visibility       = $isProxyCandidate ? 'public' : 'protected';
        $code             = <<<EOF

    /**
     * Gets the '$id' service.$doc
     *$lazyInitializationDoc
     * $return
     */
    {$visibility} function get{$name}Service($lazyInitialization)
    {

EOF;

        $code .= $isProxyCandidate ? $this->getProxyDumper()->getProxyFactoryCode($definition, $id) : '';

        if (!in_array($scope, array(ContainerInterface::SCOPE_CONTAINER, ContainerInterface::SCOPE_PROTOTYPE))) {
            $code .= <<<EOF
        if (!isset(\$this->scopedServices['$scope'])) {
            throw new InactiveScopeException('$id', '$scope');
        }


EOF;
        }

        if ($definition->isSynthetic()) {
            $code .= sprintf("        throw new RuntimeException('You have requested a synthetic service (\"%s\"). The DIC does not know how to construct this service.');\n    }\n", $id);
        } else {
            $code .=
                $this->addServiceInclude($id, $definition).
                $this->addServiceLocalTempVariables($id, $definition).
                $this->addServiceInlinedDefinitions($id, $definition).
                $this->addServiceInstance($id, $definition).
                $this->addServiceInlinedDefinitionsSetup($id, $definition).
                $this->addServiceMethodCalls($id, $definition).
                $this->addServiceProperties($id, $definition).
                $this->addServiceConfigurator($id, $definition).
                $this->addServiceReturn($id, $definition)
            ;
        }

        $this->definitionVariables = null;
        $this->referenceVariables = null;

        return $code;
    }

    /**
     * Adds a service alias.
     *
     * @param string $alias
     * @param string $id
     *
     * @return string
     */
    private function addServiceAlias($alias, $id)
    {
        $name = Container::camelize($alias);
        $type = 'Object';

        if ($this->container->hasDefinition($id)) {
            $class = $this->container->getDefinition($id)->getClass();
            $type = 0 === strpos($class, '%') ? 'Object' : $class;
        }

        return <<<EOF

    /**
     * Gets the $alias service alias.
     *
     * @return $type An instance of the $id service
     */
    protected function get{$name}Service()
    {
        return {$this->getServiceCall($id)};
    }

EOF;
    }

    /**
     * Adds multiple services
     *
     * @return string
     */
    private function addServices()
    {
        $publicServices = $privateServices = $aliasServices = $synchronizers = '';
        $definitions = $this->container->getDefinitions();
        ksort($definitions);
        foreach ($definitions as $id => $definition) {
            if ($definition->isPublic()) {
                $publicServices .= $this->addService($id, $definition);
            } else {
                $privateServices .= $this->addService($id, $definition);
            }

            $synchronizers .= $this->addServiceSynchronizer($id, $definition);
        }

        $aliases = $this->container->getAliases();
        ksort($aliases);
        foreach ($aliases as $alias => $id) {
            $aliasServices .= $this->addServiceAlias($alias, $id);
        }

        return $publicServices.$aliasServices.$synchronizers.$privateServices;
    }

    /**
     * Adds synchronizer methods.
     *
     * @param string     $id         A service identifier
     * @param Definition $definition A Definition instance
     */
    private function addServiceSynchronizer($id, Definition $definition)
    {
        if (!$definition->isSynchronized()) {
            return;
        }

        $code = '';
        foreach ($this->container->getDefinitions() as $definitionId => $definition) {
            foreach ($definition->getMethodCalls() as $call) {
                foreach ($call[1] as $argument) {
                    if ($argument instanceof Reference && $id == (string) $argument) {
                        $arguments = array();
                        foreach ($call[1] as $value) {
                            $arguments[] = $this->dumpValue($value);
                        }

                        $call = $this->wrapServiceConditionals($call[1], sprintf("\$this->get('%s')->%s(%s);", $definitionId, $call[0], implode(', ', $arguments)));

                        $code .= <<<EOF
        if (\$this->initialized('$definitionId')) {
            $call
        }

EOF;
                    }
                }
            }
        }

        if (!$code) {
            return;
        }

        $name = Container::camelize($id);

        return <<<EOF

    /**
     * Updates the '$id' service.
     */
    protected function synchronize{$name}Service()
    {
$code    }

EOF;
    }

    private function addNewInstance($id, Definition $definition, $return, $instantiation)
    {
        $class = $this->dumpValue($definition->getClass());

        $arguments = array();
        foreach ($definition->getArguments() as $value) {
            $arguments[] = $this->dumpValue($value);
        }

        if (null !== $definition->getFactoryMethod()) {
            if (null !== $definition->getFactoryClass()) {
                return sprintf("        $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($definition->getFactoryClass()), $definition->getFactoryMethod(), $arguments ? ', '.implode(', ', $arguments) : '');
            }

            if (null !== $definition->getFactoryService()) {
                return sprintf("        $return{$instantiation}%s->%s(%s);\n", $this->getServiceCall($definition->getFactoryService()), $definition->getFactoryMethod(), implode(', ', $arguments));
            }

            throw new RuntimeException(sprintf('Factory method requires a factory service or factory class in service definition for %s', $id));
        }

        if (false !== strpos($class, '$')) {
            return sprintf("        \$class = %s;\n\n        $return{$instantiation}new \$class(%s);\n", $class, implode(', ', $arguments));
        }

        return sprintf("        $return{$instantiation}new \\%s(%s);\n", substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments));
    }

    /**
     * Adds the class headers.
     *
     * @param string $class     Class name
     * @param string $baseClass The name of the base class
     *
     * @return string
     */
    private function startClass($class, $baseClass)
    {
        $bagClass = $this->container->isFrozen() ? 'use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;' : 'use Symfony\Component\DependencyInjection\ParameterBag\\ParameterBag;';

        return <<<EOF
<?php

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Parameter;
$bagClass

/**
 * $class
 *
 * This class has been auto-generated
 * by the Symfony Dependency Injection Component.
 */
class $class extends $baseClass
{
EOF;
    }

    /**
     * Adds the constructor.
     *
     * @return string
     */
    private function addConstructor()
    {
        $arguments = $this->container->getParameterBag()->all() ? 'new ParameterBag($this->getDefaultParameters())' : null;

        $code = <<<EOF

    /**
     * Constructor.
     */
    public function __construct()
    {
        parent::__construct($arguments);

EOF;

        if (count($scopes = $this->container->getScopes()) > 0) {
            $code .= "\n";
            $code .= "        \$this->scopes = ".$this->dumpValue($scopes).";\n";
            $code .= "        \$this->scopeChildren = ".$this->dumpValue($this->container->getScopeChildren()).";\n";
        }

        $code .= <<<EOF
    }

EOF;

        return $code;
    }

    /**
     * Adds the constructor for a frozen container.
     *
     * @return string
     */
    private function addFrozenConstructor()
    {
        $code = <<<EOF

    /**
     * Constructor.
     */
    public function __construct()
    {
EOF;

        if ($this->container->getParameterBag()->all()) {
            $code .= "\n        \$this->parameters = \$this->getDefaultParameters();\n";
        }

        $code .= <<<EOF

        \$this->services =
        \$this->scopedServices =
        \$this->scopeStacks = array();

        \$this->set('service_container', \$this);

EOF;

        $code .= "\n";
        if (count($scopes = $this->container->getScopes()) > 0) {
            $code .= "        \$this->scopes = ".$this->dumpValue($scopes).";\n";
            $code .= "        \$this->scopeChildren = ".$this->dumpValue($this->container->getScopeChildren()).";\n";
        } else {
            $code .= "        \$this->scopes = array();\n";
            $code .= "        \$this->scopeChildren = array();\n";
        }

        // build method map
        $code .= "        \$this->methodMap = array(\n";
        $definitions = $this->container->getDefinitions();
        ksort($definitions);
        foreach ($definitions as $id => $definition) {
            $code .= '            '.var_export($id, true).' => '.var_export('get'.Container::camelize($id).'Service', true).",\n";
        }
        $aliases = $this->container->getAliases();
        ksort($aliases);
        foreach ($aliases as $alias => $id) {
            $code .= '            '.var_export($alias, true).' => '.var_export('get'.Container::camelize($id).'Service', true).",\n";
        }
        $code .= "        );\n";

        $code .= <<<EOF
    }

EOF;

        return $code;
    }

    /**
     * Adds default parameters method.
     *
     * @return string
     */
    private function addDefaultParametersMethod()
    {
        if (!$this->container->getParameterBag()->all()) {
            return '';
        }

        $parameters = $this->exportParameters($this->container->getParameterBag()->all());

        $code = '';
        if ($this->container->isFrozen()) {
            $code .= <<<EOF

    /**
     * {@inheritdoc}
     */
    public function getParameter(\$name)
    {
        \$name = strtolower(\$name);

        if (!(isset(\$this->parameters[\$name]) || array_key_exists(\$name, \$this->parameters))) {
            throw new InvalidArgumentException(sprintf('The parameter "%s" must be defined.', \$name));
        }

        return \$this->parameters[\$name];
    }

    /**
     * {@inheritdoc}
     */
    public function hasParameter(\$name)
    {
        \$name = strtolower(\$name);

        return isset(\$this->parameters[\$name]) || array_key_exists(\$name, \$this->parameters);
    }

    /**
     * {@inheritdoc}
     */
    public function setParameter(\$name, \$value)
    {
        throw new LogicException('Impossible to call set() on a frozen ParameterBag.');
    }

    /**
     * {@inheritDoc}
     */
    public function getParameterBag()
    {
        if (null === \$this->parameterBag) {
            \$this->parameterBag = new FrozenParameterBag(\$this->parameters);
        }

        return \$this->parameterBag;
    }
EOF;
        }

        $code .= <<<EOF

    /**
     * Gets the default parameters.
     *
     * @return array An array of the default parameters
     */
    protected function getDefaultParameters()
    {
        return $parameters;
    }

EOF;

        return $code;
    }

    /**
     * Exports parameters.
     *
     * @param array   $parameters
     * @param string  $path
     * @param integer $indent
     *
     * @return string
     *
     * @throws InvalidArgumentException
     */
    private function exportParameters($parameters, $path = '', $indent = 12)
    {
        $php = array();
        foreach ($parameters as $key => $value) {
            if (is_array($value)) {
                $value = $this->exportParameters($value, $path.'/'.$key, $indent + 4);
            } elseif ($value instanceof Variable) {
                throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain variable references. Variable "%s" found in "%s".', $value, $path.'/'.$key));
            } elseif ($value instanceof Definition) {
                throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain service definitions. Definition for "%s" found in "%s".', $value->getClass(), $path.'/'.$key));
            } elseif ($value instanceof Reference) {
                throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain references to other services (reference to service "%s" found in "%s").', $value, $path.'/'.$key));
            } else {
                $value = var_export($value, true);
            }

            $php[] = sprintf('%s%s => %s,', str_repeat(' ', $indent), var_export($key, true), $value);
        }

        return sprintf("array(\n%s\n%s)", implode("\n", $php), str_repeat(' ', $indent - 4));
    }

    /**
     * Ends the class definition.
     *
     * @return string
     */
    private function endClass()
    {
        return <<<EOF
}

EOF;
    }

    /**
     * Wraps the service conditionals.
     *
     * @param string $value
     * @param string $code
     *
     * @return string
     */
    private function wrapServiceConditionals($value, $code)
    {
        if (!$services = ContainerBuilder::getServiceConditionals($value)) {
            return $code;
        }

        $conditions = array();
        foreach ($services as $service) {
            $conditions[] = sprintf("\$this->has('%s')", $service);
        }

        // re-indent the wrapped code
        $code = implode("\n", array_map(function ($line) { return $line ? '    '.$line : $line; }, explode("\n", $code)));

        return sprintf("        if (%s) {\n%s        }\n", implode(' && ', $conditions), $code);
    }

    /**
     * Builds service calls from arguments.
     *
     * @param array  $arguments
     * @param array  &$calls    By reference
     * @param array  &$behavior By reference
     */
    private function getServiceCallsFromArguments(array $arguments, array &$calls, array &$behavior)
    {
        foreach ($arguments as $argument) {
            if (is_array($argument)) {
                $this->getServiceCallsFromArguments($argument, $calls, $behavior);
            } elseif ($argument instanceof Reference) {
                $id = (string) $argument;

                if (!isset($calls[$id])) {
                    $calls[$id] = 0;
                }
                if (!isset($behavior[$id])) {
                    $behavior[$id] = $argument->getInvalidBehavior();
                } elseif (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $behavior[$id]) {
                    $behavior[$id] = $argument->getInvalidBehavior();
                }

                $calls[$id] += 1;
            }
        }
    }

    /**
     * Returns the inline definition.
     *
     * @param Definition $definition
     *
     * @return array
     */
    private function getInlinedDefinitions(Definition $definition)
    {
        if (false === $this->inlinedDefinitions->contains($definition)) {
            $definitions = array_merge(
                $this->getDefinitionsFromArguments($definition->getArguments()),
                $this->getDefinitionsFromArguments($definition->getMethodCalls()),
                $this->getDefinitionsFromArguments($definition->getProperties())
            );

            $this->inlinedDefinitions->offsetSet($definition, $definitions);

            return $definitions;
        }

        return $this->inlinedDefinitions->offsetGet($definition);
    }

    /**
     * Gets the definition from arguments.
     *
     * @param array $arguments
     *
     * @return array
     */
    private function getDefinitionsFromArguments(array $arguments)
    {
        $definitions = array();
        foreach ($arguments as $argument) {
            if (is_array($argument)) {
                $definitions = array_merge($definitions, $this->getDefinitionsFromArguments($argument));
            } elseif ($argument instanceof Definition) {
                $definitions = array_merge(
                    $definitions,
                    $this->getInlinedDefinitions($argument),
                    array($argument)
                );
            }
        }

        return $definitions;
    }

    /**
     * Checks if a service id has a reference.
     *
     * @param string  $id
     * @param array   $arguments
     * @param Boolean $deep
     * @param array   $visited
     *
     * @return Boolean
     */
    private function hasReference($id, array $arguments, $deep = false, $visited = array())
    {
        foreach ($arguments as $argument) {
            if (is_array($argument)) {
                if ($this->hasReference($id, $argument, $deep, $visited)) {
                    return true;
                }
            } elseif ($argument instanceof Reference) {
                if ($id === (string) $argument) {
                    return true;
                }

                if ($deep && !isset($visited[(string) $argument])) {
                    $visited[(string) $argument] = true;

                    $service = $this->container->getDefinition((string) $argument);
                    $arguments = array_merge($service->getMethodCalls(), $service->getArguments(), $service->getProperties());

                    if ($this->hasReference($id, $arguments, $deep, $visited)) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

    /**
     * Dumps values.
     *
     * @param array   $value
     * @param Boolean $interpolate
     *
     * @return string
     *
     * @throws RuntimeException
     */
    private function dumpValue($value, $interpolate = true)
    {
        if (is_array($value)) {
            $code = array();
            foreach ($value as $k => $v) {
                $code[] = sprintf('%s => %s', $this->dumpValue($k, $interpolate), $this->dumpValue($v, $interpolate));
            }

            return sprintf('array(%s)', implode(', ', $code));
        } elseif ($value instanceof Definition) {
            if (null !== $this->definitionVariables && $this->definitionVariables->contains($value)) {
                return $this->dumpValue($this->definitionVariables->offsetGet($value), $interpolate);
            }
            if (count($value->getMethodCalls()) > 0) {
                throw new RuntimeException('Cannot dump definitions which have method calls.');
            }
            if (null !== $value->getConfigurator()) {
                throw new RuntimeException('Cannot dump definitions which have a configurator.');
            }

            $arguments = array();
            foreach ($value->getArguments() as $argument) {
                $arguments[] = $this->dumpValue($argument);
            }
            $class = $this->dumpValue($value->getClass());

            if (false !== strpos($class, '$')) {
                throw new RuntimeException('Cannot dump definitions which have a variable class name.');
            }

            if (null !== $value->getFactoryMethod()) {
                if (null !== $value->getFactoryClass()) {
                    return sprintf("call_user_func(array(%s, '%s')%s)", $this->dumpValue($value->getFactoryClass()), $value->getFactoryMethod(), count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
                } elseif (null !== $value->getFactoryService()) {
                    return sprintf("%s->%s(%s)", $this->getServiceCall($value->getFactoryService()), $value->getFactoryMethod(), implode(', ', $arguments));
                } else {
                    throw new RuntimeException('Cannot dump definitions which have factory method without factory service or factory class.');
                }
            }

            return sprintf("new \\%s(%s)", substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments));
        } elseif ($value instanceof Variable) {
            return '$'.$value;
        } elseif ($value instanceof Reference) {
            if (null !== $this->referenceVariables && isset($this->referenceVariables[$id = (string) $value])) {
                return $this->dumpValue($this->referenceVariables[$id], $interpolate);
            }

            return $this->getServiceCall((string) $value, $value);
        } elseif ($value instanceof Parameter) {
            return $this->dumpParameter($value);
        } elseif (true === $interpolate && is_string($value)) {
            if (preg_match('/^%([^%]+)%$/', $value, $match)) {
                // we do this to deal with non string values (Boolean, integer, ...)
                // the preg_replace_callback converts them to strings
                return $this->dumpParameter(strtolower($match[1]));
            } else {
                $that = $this;
                $replaceParameters = function ($match) use ($that) {
                    return "'.".$that->dumpParameter(strtolower($match[2])).".'";
                };

                $code = str_replace('%%', '%', preg_replace_callback('/(?<!%)(%)([^%]+)\1/', $replaceParameters, var_export($value, true)));

                return $code;
            }
        } elseif (is_object($value) || is_resource($value)) {
            throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
        } else {
            return var_export($value, true);
        }
    }

    /**
     * Dumps a parameter
     *
     * @param string $name
     *
     * @return string
     */
    public function dumpParameter($name)
    {
        if ($this->container->isFrozen() && $this->container->hasParameter($name)) {
            return $this->dumpValue($this->container->getParameter($name), false);
        }

        return sprintf("\$this->getParameter('%s')", strtolower($name));
    }

    /**
     * Gets a service call
     *
     * @param string    $id
     * @param Reference $reference
     *
     * @return string
     */
    private function getServiceCall($id, Reference $reference = null)
    {
        if ('service_container' === $id) {
            return '$this';
        }

        if (null !== $reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $reference->getInvalidBehavior()) {
            return sprintf('$this->get(\'%s\', ContainerInterface::NULL_ON_INVALID_REFERENCE)', $id);
        } else {
            if ($this->container->hasAlias($id)) {
                $id = (string) $this->container->getAlias($id);
            }

            return sprintf('$this->get(\'%s\')', $id);
        }
    }

    /**
     * Returns the next name to use
     *
     * @return string
     */
    private function getNextVariableName()
    {
        $firstChars = self::FIRST_CHARS;
        $firstCharsLength = strlen($firstChars);
        $nonFirstChars = self::NON_FIRST_CHARS;
        $nonFirstCharsLength = strlen($nonFirstChars);

        while (true) {
            $name = '';
            $i = $this->variableCount;

            if ('' === $name) {
                $name .= $firstChars[$i%$firstCharsLength];
                $i = intval($i/$firstCharsLength);
            }

            while ($i > 0) {
                $i -= 1;
                $name .= $nonFirstChars[$i%$nonFirstCharsLength];
                $i = intval($i/$nonFirstCharsLength);
            }

            $this->variableCount += 1;

            // check that the name is not reserved
            if (in_array($name, $this->reservedVariables, true)) {
                continue;
            }

            return $name;
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection;

/**
 * Parameter represents a parameter reference.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @api
 */
class Parameter
{
    private $id;

    /**
     * Constructor.
     *
     * @param string $id The parameter key
     */
    public function __construct($id)
    {
        $this->id = $id;
    }

    /**
     * __toString.
     *
     * @return string The parameter key
     */
    public function __toString()
    {
        return (string) $this->id;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection;

/**
 * @api
 */
class Alias
{
    private $id;
    private $public;

    /**
     * Constructor.
     *
     * @param string  $id     Alias identifier
     * @param Boolean $public If this alias is public
     *
     * @api
     */
    public function __construct($id, $public = true)
    {
        $this->id = strtolower($id);
        $this->public = $public;
    }

    /**
     * Checks if this DI Alias should be public or not.
     *
     * @return Boolean
     *
     * @api
     */
    public function isPublic()
    {
        return $this->public;
    }

    /**
     * Sets if this Alias is public.
     *
     * @param Boolean $boolean If this Alias should be public
     *
     * @api
     */
    public function setPublic($boolean)
    {
        $this->public = (Boolean) $boolean;
    }

    /**
     * Returns the Id of this alias.
     *
     * @return string The alias id
     *
     * @api
     */
    public function __toString()
    {
        return $this->id;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection;

use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\OutOfBoundsException;

/**
 * This definition decorates another definition.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 *
 * @api
 */
class DefinitionDecorator extends Definition
{
    private $parent;
    private $changes;

    /**
     * Constructor.
     *
     * @param string $parent The id of Definition instance to decorate.
     *
     * @api
     */
    public function __construct($parent)
    {
        parent::__construct();

        $this->parent = $parent;
        $this->changes = array();
    }

    /**
     * Returns the Definition being decorated.
     *
     * @return string
     *
     * @api
     */
    public function getParent()
    {
        return $this->parent;
    }

    /**
     * Returns all changes tracked for the Definition object.
     *
     * @return array An array of changes for this Definition
     *
     * @api
     */
    public function getChanges()
    {
        return $this->changes;
    }

    /**
     * {@inheritDoc}
     *
     * @api
     */
    public function setClass($class)
    {
        $this->changes['class'] = true;

        return parent::setClass($class);
    }

    /**
     * {@inheritDoc}
     *
     * @api
     */
    public function setFactoryClass($class)
    {
        $this->changes['factory_class'] = true;

        return parent::setFactoryClass($class);
    }

    /**
     * {@inheritDoc}
     *
     * @api
     */
    public function setFactoryMethod($method)
    {
        $this->changes['factory_method'] = true;

        return parent::setFactoryMethod($method);
    }

    /**
     * {@inheritDoc}
     *
     * @api
     */
    public function setFactoryService($service)
    {
        $this->changes['factory_service'] = true;

        return parent::setFactoryService($service);
    }

    /**
     * {@inheritDoc}
     *
     * @api
     */
    public function setConfigurator($callable)
    {
        $this->changes['configurator'] = true;

        return parent::setConfigurator($callable);
    }

    /**
     * {@inheritDoc}
     *
     * @api
     */
    public function setFile($file)
    {
        $this->changes['file'] = true;

        return parent::setFile($file);
    }

    /**
     * {@inheritDoc}
     *
     * @api
     */
    public function setPublic($boolean)
    {
        $this->changes['public'] = true;

        return parent::setPublic($boolean);
    }

    /**
     * Gets an argument to pass to the service constructor/factory method.
     *
     * If replaceArgument() has been used to replace an argument, this method
     * will return the replacement value.
     *
     * @param integer $index
     *
     * @return mixed The argument value
     *
     * @throws OutOfBoundsException When the argument does not exist
     *
     * @api
     */
    public function getArgument($index)
    {
        if (array_key_exists('index_'.$index, $this->arguments)) {
            return $this->arguments['index_'.$index];
        }

        $lastIndex = count(array_filter(array_keys($this->arguments), 'is_int')) - 1;

        if ($index < 0 || $index > $lastIndex) {
            throw new OutOfBoundsException(sprintf('The index "%d" is not in the range [0, %d].', $index, $lastIndex));
        }

        return $this->arguments[$index];
    }

    /**
     * You should always use this method when overwriting existing arguments
     * of the parent definition.
     *
     * If you directly call setArguments() keep in mind that you must follow
     * certain conventions when you want to overwrite the arguments of the
     * parent definition, otherwise your arguments will only be appended.
     *
     * @param integer $index
     * @param mixed   $value
     *
     * @return DefinitionDecorator the current instance
     * @throws InvalidArgumentException when $index isn't an integer
     *
     * @api
     */
    public function replaceArgument($index, $value)
    {
        if (!is_int($index)) {
            throw new InvalidArgumentException('$index must be an integer.');
        }

        $this->arguments['index_'.$index] = $value;

        return $this;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection;

/**
 * Scope Interface.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 *
 * @api
 */
interface ScopeInterface
{
    /**
     * @api
     */
    public function getName();

    /**
     * @api
     */
    public function getParentName();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Exception;

/**
 * This exception is thrown when a non-existent parameter is used.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ParameterNotFoundException extends InvalidArgumentException
{
    private $key;
    private $sourceId;
    private $sourceKey;
    private $alternatives;

    /**
     * Constructor.
     *
     * @param string     $key          The requested parameter key
     * @param string     $sourceId     The service id that references the non-existent parameter
     * @param string     $sourceKey    The parameter key that references the non-existent parameter
     * @param \Exception $previous     The previous exception
     * @param string[]   $alternatives Some parameter name alternatives
     */
    public function __construct($key, $sourceId = null, $sourceKey = null, \Exception $previous = null, array $alternatives = array())
    {
        $this->key = $key;
        $this->sourceId = $sourceId;
        $this->sourceKey = $sourceKey;
        $this->alternatives = $alternatives;

        parent::__construct('', 0, $previous);

        $this->updateRepr();
    }

    public function updateRepr()
    {
        if (null !== $this->sourceId) {
            $this->message = sprintf('The service "%s" has a dependency on a non-existent parameter "%s".', $this->sourceId, $this->key);
        } elseif (null !== $this->sourceKey) {
            $this->message = sprintf('The parameter "%s" has a dependency on a non-existent parameter "%s".', $this->sourceKey, $this->key);
        } else {
            $this->message = sprintf('You have requested a non-existent parameter "%s".', $this->key);
        }

        if ($this->alternatives) {
            if (1 == count($this->alternatives)) {
                $this->message .= ' Did you mean this: "';
            } else {
                $this->message .= ' Did you mean one of these: "';
            }
            $this->message .= implode('", "', $this->alternatives).'"?';
        }
    }

    public function getKey()
    {
        return $this->key;
    }

    public function getSourceId()
    {
        return $this->sourceId;
    }

    public function getSourceKey()
    {
        return $this->sourceKey;
    }

    public function setSourceId($sourceId)
    {
        $this->sourceId = $sourceId;

        $this->updateRepr();
    }

    public function setSourceKey($sourceKey)
    {
        $this->sourceKey = $sourceKey;

        $this->updateRepr();
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Exception;

/**
 * This exception is thrown when the a scope crossing injection is detected.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ScopeCrossingInjectionException extends RuntimeException
{
    private $sourceServiceId;
    private $sourceScope;
    private $destServiceId;
    private $destScope;

    public function __construct($sourceServiceId, $sourceScope, $destServiceId, $destScope, \Exception $previous = null)
    {
        parent::__construct(sprintf(
            'Scope Crossing Injection detected: The definition "%s" references the service "%s" which belongs to another scope hierarchy. '
           .'This service might not be available consistently. Generally, it is safer to either move the definition "%s" to scope "%s", or '
           .'declare "%s" as a child scope of "%s". If you can be sure that the other scope is always active, you can set the reference to strict=false to get rid of this error.',
           $sourceServiceId,
           $destServiceId,
           $sourceServiceId,
           $destScope,
           $sourceScope,
           $destScope
        ), 0, $previous);

        $this->sourceServiceId = $sourceServiceId;
        $this->sourceScope = $sourceScope;
        $this->destServiceId = $destServiceId;
        $this->destScope = $destScope;
    }

    public function getSourceServiceId()
    {
        return $this->sourceServiceId;
    }

    public function getSourceScope()
    {
        return $this->sourceScope;
    }

    public function getDestServiceId()
    {
        return $this->destServiceId;
    }

    public function getDestScope()
    {
        return $this->destScope;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Exception;

/**
 * Thrown when a scope widening injection is detected.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ScopeWideningInjectionException extends RuntimeException
{
    private $sourceServiceId;
    private $sourceScope;
    private $destServiceId;
    private $destScope;

    public function __construct($sourceServiceId, $sourceScope, $destServiceId, $destScope, \Exception $previous = null)
    {
        parent::__construct(sprintf(
            'Scope Widening Injection detected: The definition "%s" references the service "%s" which belongs to a narrower scope. '
           .'Generally, it is safer to either move "%s" to scope "%s" or alternatively rely on the provider pattern by injecting the container itself, and requesting the service "%s" each time it is needed. '
           .'In rare, special cases however that might not be necessary, then you can set the reference to strict=false to get rid of this error.',
           $sourceServiceId,
           $destServiceId,
           $sourceServiceId,
           $destScope,
           $destServiceId
        ), 0, $previous);

        $this->sourceServiceId = $sourceServiceId;
        $this->sourceScope = $sourceScope;
        $this->destServiceId = $destServiceId;
        $this->destScope = $destScope;
    }

    public function getSourceServiceId()
    {
        return $this->sourceServiceId;
    }

    public function getSourceScope()
    {
        return $this->sourceScope;
    }

    public function getDestServiceId()
    {
        return $this->destServiceId;
    }

    public function getDestScope()
    {
        return $this->destScope;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Exception;

/**
 * Base InvalidArgumentException for Dependency Injection component.
 *
 * @author Bulat Shakirzyanov <bulat@theopenskyproject.com>
 */
class InvalidArgumentException extends \InvalidArgumentException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Exception;

/**
 * Base ExceptionInterface for Dependency Injection component.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Bulat Shakirzyanov <bulat@theopenskyproject.com>
 */
interface ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Exception;

/**
 * Base OutOfBoundsException for Dependency Injection component.
 */
class OutOfBoundsException extends \OutOfBoundsException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Exception;

/**
 * Base RuntimeException for Dependency Injection component.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class RuntimeException extends \RuntimeException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Exception;

/**
 * This exception is thrown when a circular reference in a parameter is detected.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ParameterCircularReferenceException extends RuntimeException
{
    private $parameters;

    public function __construct($parameters, \Exception $previous = null)
    {
        parent::__construct(sprintf('Circular reference detected for parameter "%s" ("%s" > "%s").', $parameters[0], implode('" > "', $parameters), $parameters[0]), 0, $previous);

        $this->parameters = $parameters;
    }

    public function getParameters()
    {
        return $this->parameters;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Exception;

/**
 * This exception is thrown when a non-existent service is requested.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ServiceNotFoundException extends InvalidArgumentException
{
    private $id;
    private $sourceId;

    public function __construct($id, $sourceId = null, \Exception $previous = null, array $alternatives = array())
    {
        if (null === $sourceId) {
            $msg = sprintf('You have requested a non-existent service "%s".', $id);
        } else {
            $msg = sprintf('The service "%s" has a dependency on a non-existent service "%s".', $sourceId, $id);
        }

        if ($alternatives) {
            if (1 == count($alternatives)) {
                $msg .= ' Did you mean this: "';
            } else {
                $msg .= ' Did you mean one of these: "';
            }
            $msg .= implode('", "', $alternatives).'"?';
        }

        parent::__construct($msg, 0, $previous);

        $this->id = $id;
        $this->sourceId = $sourceId;
    }

    public function getId()
    {
        return $this->id;
    }

    public function getSourceId()
    {
        return $this->sourceId;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Exception;

/**
 * Base LogicException for Dependency Injection component.
 */
class LogicException extends \LogicException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Exception;

/**
 * Base BadMethodCallException for Dependency Injection component.
 */
class BadMethodCallException extends \BadMethodCallException implements ExceptionInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Exception;

/**
 * This exception is thrown when a circular reference is detected.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ServiceCircularReferenceException extends RuntimeException
{
    private $serviceId;
    private $path;

    public function __construct($serviceId, array $path, \Exception $previous = null)
    {
        parent::__construct(sprintf('Circular reference detected for service "%s", path: "%s".', $serviceId, implode(' -> ', $path)), 0, $previous);

        $this->serviceId = $serviceId;
        $this->path = $path;
    }

    public function getServiceId()
    {
        return $this->serviceId;
    }

    public function getPath()
    {
        return $this->path;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Exception;

/**
 * This exception is thrown when you try to create a service of an inactive scope.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class InactiveScopeException extends RuntimeException
{
    private $serviceId;
    private $scope;

    public function __construct($serviceId, $scope, \Exception $previous = null)
    {
        parent::__construct(sprintf('You cannot create a service ("%s") of an inactive scope ("%s").', $serviceId, $scope), 0, $previous);

        $this->serviceId = $serviceId;
        $this->scope = $scope;
    }

    public function getServiceId()
    {
        return $this->serviceId;
    }

    public function getScope()
    {
        return $this->scope;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection;

/**
 * TaggedContainerInterface is the interface implemented when a container knows how to deals with tags.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @api
 */
interface TaggedContainerInterface extends ContainerInterface
{
    /**
     * Returns service ids for a given tag.
     *
     * @param string $name The tag name
     *
     * @return array An array of tags
     *
     * @api
     */
    public function findTaggedServiceIds($name);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection;

use Symfony\Component\DependencyInjection\Compiler\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\Exception\BadMethodCallException;
use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Config\Resource\ResourceInterface;
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator;

/**
 * ContainerBuilder is a DI container that provides an API to easily describe services.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @api
 */
class ContainerBuilder extends Container implements TaggedContainerInterface
{
    /**
     * @var ExtensionInterface[]
     */
    private $extensions = array();

    /**
     * @var ExtensionInterface[]
     */
    private $extensionsByNs = array();

    /**
     * @var Definition[]
     */
    private $definitions = array();

    /**
     * @var Definition[]
     */
    private $obsoleteDefinitions = array();

    /**
     * @var Alias[]
     */
    private $aliases = array();

    /**
     * @var ResourceInterface[]
     */
    private $resources = array();

    private $extensionConfigs = array();

    /**
     * @var Compiler
     */
    private $compiler;

    private $trackResources = true;

    /**
     * @var InstantiatorInterface|null
     */
    private $proxyInstantiator;

    /**
     * Sets the track resources flag.
     *
     * If you are not using the loaders and therefore don't want
     * to depend on the Config component, set this flag to false.
     *
     * @param Boolean $track true if you want to track resources, false otherwise
     */
    public function setResourceTracking($track)
    {
        $this->trackResources = (Boolean) $track;
    }

    /**
     * Checks if resources are tracked.
     *
     * @return Boolean true if resources are tracked, false otherwise
     */
    public function isTrackingResources()
    {
        return $this->trackResources;
    }

    /**
     * Sets the instantiator to be used when fetching proxies.
     *
     * @param InstantiatorInterface $proxyInstantiator
     */
    public function setProxyInstantiator(InstantiatorInterface $proxyInstantiator)
    {
        $this->proxyInstantiator = $proxyInstantiator;
    }

    /**
     * Registers an extension.
     *
     * @param ExtensionInterface $extension An extension instance
     *
     * @api
     */
    public function registerExtension(ExtensionInterface $extension)
    {
        $this->extensions[$extension->getAlias()] = $extension;

        if (false !== $extension->getNamespace()) {
            $this->extensionsByNs[$extension->getNamespace()] = $extension;
        }
    }

    /**
     * Returns an extension by alias or namespace.
     *
     * @param string $name An alias or a namespace
     *
     * @return ExtensionInterface An extension instance
     *
     * @throws LogicException if the extension is not registered
     *
     * @api
     */
    public function getExtension($name)
    {
        if (isset($this->extensions[$name])) {
            return $this->extensions[$name];
        }

        if (isset($this->extensionsByNs[$name])) {
            return $this->extensionsByNs[$name];
        }

        throw new LogicException(sprintf('Container extension "%s" is not registered', $name));
    }

    /**
     * Returns all registered extensions.
     *
     * @return ExtensionInterface[] An array of ExtensionInterface
     *
     * @api
     */
    public function getExtensions()
    {
        return $this->extensions;
    }

    /**
     * Checks if we have an extension.
     *
     * @param string $name The name of the extension
     *
     * @return Boolean If the extension exists
     *
     * @api
     */
    public function hasExtension($name)
    {
        return isset($this->extensions[$name]) || isset($this->extensionsByNs[$name]);
    }

    /**
     * Returns an array of resources loaded to build this configuration.
     *
     * @return ResourceInterface[] An array of resources
     *
     * @api
     */
    public function getResources()
    {
        return array_unique($this->resources);
    }

    /**
     * Adds a resource for this configuration.
     *
     * @param ResourceInterface $resource A resource instance
     *
     * @return ContainerBuilder The current instance
     *
     * @api
     */
    public function addResource(ResourceInterface $resource)
    {
        if (!$this->trackResources) {
            return $this;
        }

        $this->resources[] = $resource;

        return $this;
    }

    /**
     * Sets the resources for this configuration.
     *
     * @param ResourceInterface[] $resources An array of resources
     *
     * @return ContainerBuilder The current instance
     *
     * @api
     */
    public function setResources(array $resources)
    {
        if (!$this->trackResources) {
            return $this;
        }

        $this->resources = $resources;

        return $this;
    }

    /**
     * Adds the object class hierarchy as resources.
     *
     * @param object $object An object instance
     *
     * @return ContainerBuilder The current instance
     *
     * @api
     */
    public function addObjectResource($object)
    {
        if ($this->trackResources) {
            $this->addClassResource(new \ReflectionClass($object));
        }

        return $this;
    }

    /**
     * Adds the given class hierarchy as resources.
     *
     * @param \ReflectionClass $class
     *
     * @return ContainerBuilder The current instance
     */
    public function addClassResource(\ReflectionClass $class)
    {
        if (!$this->trackResources) {
            return $this;
        }

        do {
            $this->addResource(new FileResource($class->getFileName()));
        } while ($class = $class->getParentClass());

        return $this;
    }

    /**
     * Loads the configuration for an extension.
     *
     * @param string $extension The extension alias or namespace
     * @param array  $values    An array of values that customizes the extension
     *
     * @return ContainerBuilder The current instance
     * @throws BadMethodCallException When this ContainerBuilder is frozen
     *
     * @throws \LogicException if the container is frozen
     *
     * @api
     */
    public function loadFromExtension($extension, array $values = array())
    {
        if ($this->isFrozen()) {
            throw new BadMethodCallException('Cannot load from an extension on a frozen container.');
        }

        $namespace = $this->getExtension($extension)->getAlias();

        $this->extensionConfigs[$namespace][] = $values;

        return $this;
    }

    /**
     * Adds a compiler pass.
     *
     * @param CompilerPassInterface $pass A compiler pass
     * @param string                $type The type of compiler pass
     *
     * @return ContainerBuilder The current instance
     *
     * @api
     */
    public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION)
    {
        if (null === $this->compiler) {
            $this->compiler = new Compiler();
        }

        $this->compiler->addPass($pass, $type);

        $this->addObjectResource($pass);

        return $this;
    }

    /**
     * Returns the compiler pass config which can then be modified.
     *
     * @return PassConfig The compiler pass config
     *
     * @api
     */
    public function getCompilerPassConfig()
    {
        if (null === $this->compiler) {
            $this->compiler = new Compiler();
        }

        return $this->compiler->getPassConfig();
    }

    /**
     * Returns the compiler.
     *
     * @return Compiler The compiler
     *
     * @api
     */
    public function getCompiler()
    {
        if (null === $this->compiler) {
            $this->compiler = new Compiler();
        }

        return $this->compiler;
    }

    /**
     * Returns all Scopes.
     *
     * @return array An array of scopes
     *
     * @api
     */
    public function getScopes()
    {
        return $this->scopes;
    }

    /**
     * Returns all Scope children.
     *
     * @return array An array of scope children.
     *
     * @api
     */
    public function getScopeChildren()
    {
        return $this->scopeChildren;
    }

    /**
     * Sets a service.
     *
     * @param string $id      The service identifier
     * @param object $service The service instance
     * @param string $scope   The scope
     *
     * @throws BadMethodCallException When this ContainerBuilder is frozen
     *
     * @api
     */
    public function set($id, $service, $scope = self::SCOPE_CONTAINER)
    {
        $id = strtolower($id);

        if ($this->isFrozen()) {
            // setting a synthetic service on a frozen container is alright
            if (
                (!isset($this->definitions[$id]) && !isset($this->obsoleteDefinitions[$id]))
                    ||
                (isset($this->definitions[$id]) && !$this->definitions[$id]->isSynthetic())
                    ||
                (isset($this->obsoleteDefinitions[$id]) && !$this->obsoleteDefinitions[$id]->isSynthetic())
            ) {
                throw new BadMethodCallException(sprintf('Setting service "%s" on a frozen container is not allowed.', $id));
            }
        }

        if (isset($this->definitions[$id])) {
            $this->obsoleteDefinitions[$id] = $this->definitions[$id];
        }

        unset($this->definitions[$id], $this->aliases[$id]);

        parent::set($id, $service, $scope);

        if (isset($this->obsoleteDefinitions[$id]) && $this->obsoleteDefinitions[$id]->isSynchronized()) {
            $this->synchronize($id);
        }
    }

    /**
     * Removes a service definition.
     *
     * @param string $id The service identifier
     *
     * @api
     */
    public function removeDefinition($id)
    {
        unset($this->definitions[strtolower($id)]);
    }

    /**
     * Returns true if the given service is defined.
     *
     * @param string $id The service identifier
     *
     * @return Boolean true if the service is defined, false otherwise
     *
     * @api
     */
    public function has($id)
    {
        $id = strtolower($id);

        return isset($this->definitions[$id]) || isset($this->aliases[$id]) || parent::has($id);
    }

    /**
     * Gets a service.
     *
     * @param string  $id              The service identifier
     * @param integer $invalidBehavior The behavior when the service does not exist
     *
     * @return object The associated service
     *
     * @throws InvalidArgumentException when no definitions are available
     * @throws InactiveScopeException   when the current scope is not active
     * @throws LogicException           when a circular dependency is detected
     * @throws \Exception
     *
     * @see Reference
     *
     * @api
     */
    public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
    {
        $id = strtolower($id);

        try {
            return parent::get($id, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE);
        } catch (InactiveScopeException $e) {
            if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
                return null;
            }

            throw $e;
        } catch (InvalidArgumentException $e) {
            if (isset($this->loading[$id])) {
                throw new LogicException(sprintf('The service "%s" has a circular reference to itself.', $id), 0, $e);
            }

            if (!$this->hasDefinition($id) && isset($this->aliases[$id])) {
                return $this->get($this->aliases[$id]);
            }

            try {
                $definition = $this->getDefinition($id);
            } catch (InvalidArgumentException $e) {
                if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
                    return null;
                }

                throw $e;
            }

            $this->loading[$id] = true;

            try {
                $service = $this->createService($definition, $id);
            } catch (\Exception $e) {
                unset($this->loading[$id]);

                if ($e instanceof InactiveScopeException && self::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
                    return null;
                }

                throw $e;
            }

            unset($this->loading[$id]);

            return $service;
        }
    }

    /**
     * Merges a ContainerBuilder with the current ContainerBuilder configuration.
     *
     * Service definitions overrides the current defined ones.
     *
     * But for parameters, they are overridden by the current ones. It allows
     * the parameters passed to the container constructor to have precedence
     * over the loaded ones.
     *
     * $container = new ContainerBuilder(array('foo' => 'bar'));
     * $loader = new LoaderXXX($container);
     * $loader->load('resource_name');
     * $container->register('foo', new stdClass());
     *
     * In the above example, even if the loaded resource defines a foo
     * parameter, the value will still be 'bar' as defined in the ContainerBuilder
     * constructor.
     *
     * @param ContainerBuilder $container The ContainerBuilder instance to merge.
     *
     *
     * @throws BadMethodCallException When this ContainerBuilder is frozen
     *
     * @api
     */
    public function merge(ContainerBuilder $container)
    {
        if ($this->isFrozen()) {
            throw new BadMethodCallException('Cannot merge on a frozen container.');
        }

        $this->addDefinitions($container->getDefinitions());
        $this->addAliases($container->getAliases());
        $this->getParameterBag()->add($container->getParameterBag()->all());

        if ($this->trackResources) {
            foreach ($container->getResources() as $resource) {
                $this->addResource($resource);
            }
        }

        foreach ($this->extensions as $name => $extension) {
            if (!isset($this->extensionConfigs[$name])) {
                $this->extensionConfigs[$name] = array();
            }

            $this->extensionConfigs[$name] = array_merge($this->extensionConfigs[$name], $container->getExtensionConfig($name));
        }
    }

    /**
     * Returns the configuration array for the given extension.
     *
     * @param string $name The name of the extension
     *
     * @return array An array of configuration
     *
     * @api
     */
    public function getExtensionConfig($name)
    {
        if (!isset($this->extensionConfigs[$name])) {
            $this->extensionConfigs[$name] = array();
        }

        return $this->extensionConfigs[$name];
    }

    /**
     * Prepends a config array to the configs of the given extension.
     *
     * @param string $name    The name of the extension
     * @param array  $config  The config to set
     */
    public function prependExtensionConfig($name, array $config)
    {
        if (!isset($this->extensionConfigs[$name])) {
            $this->extensionConfigs[$name] = array();
        }

        array_unshift($this->extensionConfigs[$name], $config);
    }

    /**
     * Compiles the container.
     *
     * This method passes the container to compiler
     * passes whose job is to manipulate and optimize
     * the container.
     *
     * The main compiler passes roughly do four things:
     *
     *  * The extension configurations are merged;
     *  * Parameter values are resolved;
     *  * The parameter bag is frozen;
     *  * Extension loading is disabled.
     *
     * @api
     */
    public function compile()
    {
        if (null === $this->compiler) {
            $this->compiler = new Compiler();
        }

        if ($this->trackResources) {
            foreach ($this->compiler->getPassConfig()->getPasses() as $pass) {
                $this->addObjectResource($pass);
            }

            foreach ($this->definitions as $definition) {
                if ($definition->isLazy() && ($class = $definition->getClass()) && class_exists($class)) {
                    $this->addClassResource(new \ReflectionClass($class));
                }
            }
        }

        $this->compiler->compile($this);

        $this->extensionConfigs = array();

        parent::compile();
    }

    /**
     * Gets all service ids.
     *
     * @return array An array of all defined service ids
     */
    public function getServiceIds()
    {
        return array_unique(array_merge(array_keys($this->getDefinitions()), array_keys($this->aliases), parent::getServiceIds()));
    }

    /**
     * Adds the service aliases.
     *
     * @param array $aliases An array of aliases
     *
     * @api
     */
    public function addAliases(array $aliases)
    {
        foreach ($aliases as $alias => $id) {
            $this->setAlias($alias, $id);
        }
    }

    /**
     * Sets the service aliases.
     *
     * @param array $aliases An array of aliases
     *
     * @api
     */
    public function setAliases(array $aliases)
    {
        $this->aliases = array();
        $this->addAliases($aliases);
    }

    /**
     * Sets an alias for an existing service.
     *
     * @param string        $alias The alias to create
     * @param string|Alias  $id    The service to alias
     *
     * @throws InvalidArgumentException if the id is not a string or an Alias
     * @throws InvalidArgumentException if the alias is for itself
     *
     * @api
     */
    public function setAlias($alias, $id)
    {
        $alias = strtolower($alias);

        if (is_string($id)) {
            $id = new Alias($id);
        } elseif (!$id instanceof Alias) {
            throw new InvalidArgumentException('$id must be a string, or an Alias object.');
        }

        if ($alias === strtolower($id)) {
            throw new InvalidArgumentException(sprintf('An alias can not reference itself, got a circular reference on "%s".', $alias));
        }

        unset($this->definitions[$alias]);

        $this->aliases[$alias] = $id;
    }

    /**
     * Removes an alias.
     *
     * @param string $alias The alias to remove
     *
     * @api
     */
    public function removeAlias($alias)
    {
        unset($this->aliases[strtolower($alias)]);
    }

    /**
     * Returns true if an alias exists under the given identifier.
     *
     * @param string $id The service identifier
     *
     * @return Boolean true if the alias exists, false otherwise
     *
     * @api
     */
    public function hasAlias($id)
    {
        return isset($this->aliases[strtolower($id)]);
    }

    /**
     * Gets all defined aliases.
     *
     * @return Alias[] An array of aliases
     *
     * @api
     */
    public function getAliases()
    {
        return $this->aliases;
    }

    /**
     * Gets an alias.
     *
     * @param string $id The service identifier
     *
     * @return Alias An Alias instance
     *
     * @throws InvalidArgumentException if the alias does not exist
     *
     * @api
     */
    public function getAlias($id)
    {
        $id = strtolower($id);

        if (!$this->hasAlias($id)) {
            throw new InvalidArgumentException(sprintf('The service alias "%s" does not exist.', $id));
        }

        return $this->aliases[$id];
    }

    /**
     * Registers a service definition.
     *
     * This methods allows for simple registration of service definition
     * with a fluid interface.
     *
     * @param string $id    The service identifier
     * @param string $class The service class
     *
     * @return Definition A Definition instance
     *
     * @api
     */
    public function register($id, $class = null)
    {
        return $this->setDefinition(strtolower($id), new Definition($class));
    }

    /**
     * Adds the service definitions.
     *
     * @param Definition[] $definitions An array of service definitions
     *
     * @api
     */
    public function addDefinitions(array $definitions)
    {
        foreach ($definitions as $id => $definition) {
            $this->setDefinition($id, $definition);
        }
    }

    /**
     * Sets the service definitions.
     *
     * @param Definition[] $definitions An array of service definitions
     *
     * @api
     */
    public function setDefinitions(array $definitions)
    {
        $this->definitions = array();
        $this->addDefinitions($definitions);
    }

    /**
     * Gets all service definitions.
     *
     * @return Definition[] An array of Definition instances
     *
     * @api
     */
    public function getDefinitions()
    {
        return $this->definitions;
    }

    /**
     * Sets a service definition.
     *
     * @param string     $id         The service identifier
     * @param Definition $definition A Definition instance
     *
     * @return Definition the service definition
     *
     * @throws BadMethodCallException When this ContainerBuilder is frozen
     *
     * @api
     */
    public function setDefinition($id, Definition $definition)
    {
        if ($this->isFrozen()) {
            throw new BadMethodCallException('Adding definition to a frozen container is not allowed');
        }

        $id = strtolower($id);

        unset($this->aliases[$id]);

        return $this->definitions[$id] = $definition;
    }

    /**
     * Returns true if a service definition exists under the given identifier.
     *
     * @param string $id The service identifier
     *
     * @return Boolean true if the service definition exists, false otherwise
     *
     * @api
     */
    public function hasDefinition($id)
    {
        return array_key_exists(strtolower($id), $this->definitions);
    }

    /**
     * Gets a service definition.
     *
     * @param string $id The service identifier
     *
     * @return Definition A Definition instance
     *
     * @throws InvalidArgumentException if the service definition does not exist
     *
     * @api
     */
    public function getDefinition($id)
    {
        $id = strtolower($id);

        if (!$this->hasDefinition($id)) {
            throw new InvalidArgumentException(sprintf('The service definition "%s" does not exist.', $id));
        }

        return $this->definitions[$id];
    }

    /**
     * Gets a service definition by id or alias.
     *
     * The method "unaliases" recursively to return a Definition instance.
     *
     * @param string $id The service identifier or alias
     *
     * @return Definition A Definition instance
     *
     * @throws InvalidArgumentException if the service definition does not exist
     *
     * @api
     */
    public function findDefinition($id)
    {
        while ($this->hasAlias($id)) {
            $id = (string) $this->getAlias($id);
        }

        return $this->getDefinition($id);
    }

    /**
     * Creates a service for a service definition.
     *
     * @param Definition $definition A service definition instance
     * @param string     $id         The service identifier
     * @param Boolean    $tryProxy   Whether to try proxying the service with a lazy proxy
     *
     * @return object The service described by the service definition
     *
     * @throws RuntimeException When the scope is inactive
     * @throws RuntimeException When the factory definition is incomplete
     * @throws RuntimeException When the service is a synthetic service
     * @throws InvalidArgumentException When configure callable is not callable
     *
     * @internal this method is public because of PHP 5.3 limitations, do not use it explicitly in your code
     */
    public function createService(Definition $definition, $id, $tryProxy = true)
    {
        if ($definition->isSynthetic()) {
            throw new RuntimeException(sprintf('You have requested a synthetic service ("%s"). The DIC does not know how to construct this service.', $id));
        }

        if ($tryProxy && $definition->isLazy()) {
            $container = $this;

            $proxy = $this
                ->getProxyInstantiator()
                ->instantiateProxy(
                    $container,
                    $definition,
                    $id, function () use ($definition, $id, $container) {
                        return $container->createService($definition, $id, false);
                    }
                );
            $this->shareService($definition, $proxy, $id);

            return $proxy;
        }

        $parameterBag = $this->getParameterBag();

        if (null !== $definition->getFile()) {
            require_once $parameterBag->resolveValue($definition->getFile());
        }

        $arguments = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())));

        if (null !== $definition->getFactoryMethod()) {
            if (null !== $definition->getFactoryClass()) {
                $factory = $parameterBag->resolveValue($definition->getFactoryClass());
            } elseif (null !== $definition->getFactoryService()) {
                $factory = $this->get($parameterBag->resolveValue($definition->getFactoryService()));
            } else {
                throw new RuntimeException(sprintf('Cannot create service "%s" from factory method without a factory service or factory class.', $id));
            }

            $service = call_user_func_array(array($factory, $definition->getFactoryMethod()), $arguments);
        } else {
            $r = new \ReflectionClass($parameterBag->resolveValue($definition->getClass()));

            $service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs($arguments);
        }

        if ($tryProxy || !$definition->isLazy()) {
            // share only if proxying failed, or if not a proxy
            $this->shareService($definition, $service, $id);
        }

        foreach ($definition->getMethodCalls() as $call) {
            $this->callMethod($service, $call);
        }

        $properties = $this->resolveServices($parameterBag->resolveValue($definition->getProperties()));
        foreach ($properties as $name => $value) {
            $service->$name = $value;
        }

        if ($callable = $definition->getConfigurator()) {
            if (is_array($callable)) {
                $callable[0] = $callable[0] instanceof Reference ? $this->get((string) $callable[0]) : $parameterBag->resolveValue($callable[0]);
            }

            if (!is_callable($callable)) {
                throw new InvalidArgumentException(sprintf('The configure callable for class "%s" is not a callable.', get_class($service)));
            }

            call_user_func($callable, $service);
        }

        return $service;
    }

    /**
     * Replaces service references by the real service instance.
     *
     * @param mixed $value A value
     *
     * @return mixed The same value with all service references replaced by the real service instances
     */
    public function resolveServices($value)
    {
        if (is_array($value)) {
            foreach ($value as &$v) {
                $v = $this->resolveServices($v);
            }
        } elseif ($value instanceof Reference) {
            $value = $this->get((string) $value, $value->getInvalidBehavior());
        } elseif ($value instanceof Definition) {
            $value = $this->createService($value, null);
        }

        return $value;
    }

    /**
     * Returns service ids for a given tag.
     *
     * Example:
     *
     * $container->register('foo')->addTag('my.tag', array('hello' => 'world'));
     *
     * $serviceIds = $container->findTaggedServiceIds('my.tag');
     * foreach ($serviceIds as $serviceId => $tags) {
     *     foreach ($tags as $tag) {
     *         echo $tag['hello'];
     *     }
     * }
     *
     * @param string $name The tag name
     *
     * @return array An array of tags with the tagged service as key, holding a list of attribute arrays.
     *
     * @api
     */
    public function findTaggedServiceIds($name)
    {
        $tags = array();
        foreach ($this->getDefinitions() as $id => $definition) {
            if ($definition->hasTag($name)) {
                $tags[$id] = $definition->getTag($name);
            }
        }

        return $tags;
    }

    /**
     * Returns all tags the defined services use.
     *
     * @return array An array of tags
     */
    public function findTags()
    {
        $tags = array();
        foreach ($this->getDefinitions() as $id => $definition) {
            $tags = array_merge(array_keys($definition->getTags()), $tags);
        }

        return array_unique($tags);
    }

    /**
     * Returns the Service Conditionals.
     *
     * @param mixed $value An array of conditionals to return.
     *
     * @return array An array of Service conditionals
     */
    public static function getServiceConditionals($value)
    {
        $services = array();

        if (is_array($value)) {
            foreach ($value as $v) {
                $services = array_unique(array_merge($services, self::getServiceConditionals($v)));
            }
        } elseif ($value instanceof Reference && $value->getInvalidBehavior() === ContainerInterface::IGNORE_ON_INVALID_REFERENCE) {
            $services[] = (string) $value;
        }

        return $services;
    }

    /**
     * Retrieves the currently set proxy instantiator or instantiates one.
     *
     * @return InstantiatorInterface
     */
    private function getProxyInstantiator()
    {
        if (!$this->proxyInstantiator) {
            $this->proxyInstantiator = new RealServiceInstantiator();
        }

        return $this->proxyInstantiator;
    }

    /**
     * Synchronizes a service change.
     *
     * This method updates all services that depend on the given
     * service by calling all methods referencing it.
     *
     * @param string $id A service id
     */
    private function synchronize($id)
    {
        foreach ($this->definitions as $definitionId => $definition) {
            // only check initialized services
            if (!$this->initialized($definitionId)) {
                continue;
            }

            foreach ($definition->getMethodCalls() as $call) {
                foreach ($call[1] as $argument) {
                    if ($argument instanceof Reference && $id == (string) $argument) {
                        $this->callMethod($this->get($definitionId), $call);
                    }
                }
            }
        }
    }

    private function callMethod($service, $call)
    {
        $services = self::getServiceConditionals($call[1]);

        foreach ($services as $s) {
            if (!$this->has($s)) {
                return;
            }
        }

        call_user_func_array(array($service, $call[0]), $this->resolveServices($this->getParameterBag()->resolveValue($call[1])));
    }

    /**
     * Shares a given service in the container
     *
     * @param Definition $definition
     * @param mixed      $service
     * @param string     $id
     *
     * @throws InactiveScopeException
     */
    private function shareService(Definition $definition, $service, $id)
    {
        if (self::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) {
            if (self::SCOPE_CONTAINER !== $scope && !isset($this->scopedServices[$scope])) {
                throw new InactiveScopeException($id, $scope);
            }

            $this->services[$lowerId = strtolower($id)] = $service;

            if (self::SCOPE_CONTAINER !== $scope) {
                $this->scopedServices[$scope][$lowerId] = $service;
            }
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection;

/**
 * A simple implementation of ContainerAwareInterface.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @api
 */
abstract class ContainerAware implements ContainerAwareInterface
{
    /**
     * @var ContainerInterface
     *
     * @api
     */
    protected $container;

    /**
     * Sets the Container associated with this Controller.
     *
     * @param ContainerInterface $container A ContainerInterface instance
     *
     * @api
     */
    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection;

/**
 * Scope class.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 *
 * @api
 */
class Scope implements ScopeInterface
{
    private $name;
    private $parentName;

    /**
     * @api
     */
    public function __construct($name, $parentName = ContainerInterface::SCOPE_CONTAINER)
    {
        $this->name = $name;
        $this->parentName = $parentName;
    }

    /**
     * @api
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @api
     */
    public function getParentName()
    {
        return $this->parentName;
    }
}
<?xml version="1.0" encoding="UTF-8"?>

<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false"
         syntaxCheck="false"
         bootstrap="vendor/autoload.php"
>
    <testsuites>
        <testsuite name="Symfony DependencyInjection Component Test Suite">
            <directory>./Tests/</directory>
        </testsuite>
    </testsuites>

    <filter>
        <whitelist>
            <directory>./</directory>
            <exclude>
                <directory>./Resources</directory>
                <directory>./Tests</directory>
                <directory>./vendor</directory>
            </exclude>
        </whitelist>
    </filter>
</phpunit>
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
 * Interface that must be implemented by compilation passes
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 *
 * @api
 */
interface CompilerPassInterface
{
    /**
     * You can modify the container here before it is dumped to PHP code.
     *
     * @param ContainerBuilder $container
     *
     * @api
     */
    public function process(ContainerBuilder $container);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;

/**
 * This is a directed graph of your services.
 *
 * This information can be used by your compiler passes instead of collecting
 * it themselves which improves performance quite a lot.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ServiceReferenceGraph
{
    /**
     * @var ServiceReferenceGraphNode[]
     */
    private $nodes;

    /**
     * Constructor.
     */
    public function __construct()
    {
        $this->nodes = array();
    }

    /**
     * Checks if the graph has a specific node.
     *
     * @param string $id Id to check
     *
     * @return Boolean
     */
    public function hasNode($id)
    {
        return isset($this->nodes[$id]);
    }

    /**
     * Gets a node by identifier.
     *
     * @param string $id The id to retrieve
     *
     * @return ServiceReferenceGraphNode The node matching the supplied identifier
     *
     * @throws InvalidArgumentException if no node matches the supplied identifier
     */
    public function getNode($id)
    {
        if (!isset($this->nodes[$id])) {
            throw new InvalidArgumentException(sprintf('There is no node with id "%s".', $id));
        }

        return $this->nodes[$id];
    }

    /**
     * Returns all nodes.
     *
     * @return ServiceReferenceGraphNode[] An array of all ServiceReferenceGraphNode objects
     */
    public function getNodes()
    {
        return $this->nodes;
    }

    /**
     * Clears all nodes.
     */
    public function clear()
    {
        $this->nodes = array();
    }

    /**
     * Connects 2 nodes together in the Graph.
     *
     * @param string $sourceId
     * @param string $sourceValue
     * @param string $destId
     * @param string $destValue
     * @param string $reference
     */
    public function connect($sourceId, $sourceValue, $destId, $destValue = null, $reference = null)
    {
        $sourceNode = $this->createNode($sourceId, $sourceValue);
        $destNode = $this->createNode($destId, $destValue);
        $edge = new ServiceReferenceGraphEdge($sourceNode, $destNode, $reference);

        $sourceNode->addOutEdge($edge);
        $destNode->addInEdge($edge);
    }

    /**
     * Creates a graph node.
     *
     * @param string $id
     * @param string $value
     *
     * @return ServiceReferenceGraphNode
     */
    private function createNode($id, $value)
    {
        if (isset($this->nodes[$id]) && $this->nodes[$id]->getValue() === $value) {
            return $this->nodes[$id];
        }

        return $this->nodes[$id] = new ServiceReferenceGraphNode($id, $value);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
 * Removes unused service definitions from the container.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class RemoveUnusedDefinitionsPass implements RepeatablePassInterface
{
    private $repeatedPass;

    /**
     * {@inheritDoc}
     */
    public function setRepeatedPass(RepeatedPass $repeatedPass)
    {
        $this->repeatedPass = $repeatedPass;
    }

    /**
     * Processes the ContainerBuilder to remove unused definitions.
     *
     * @param ContainerBuilder $container
     */
    public function process(ContainerBuilder $container)
    {
        $compiler = $container->getCompiler();
        $formatter = $compiler->getLoggingFormatter();
        $graph = $compiler->getServiceReferenceGraph();

        $hasChanged = false;
        foreach ($container->getDefinitions() as $id => $definition) {
            if ($definition->isPublic()) {
                continue;
            }

            if ($graph->hasNode($id)) {
                $edges = $graph->getNode($id)->getInEdges();
                $referencingAliases = array();
                $sourceIds = array();
                foreach ($edges as $edge) {
                    $node = $edge->getSourceNode();
                    $sourceIds[] = $node->getId();

                    if ($node->isAlias()) {
                        $referencingAliases[] = $node->getValue();
                    }
                }
                $isReferenced = (count(array_unique($sourceIds)) - count($referencingAliases)) > 0;
            } else {
                $referencingAliases = array();
                $isReferenced = false;
            }

            if (1 === count($referencingAliases) && false === $isReferenced) {
                $container->setDefinition((string) reset($referencingAliases), $definition);
                $definition->setPublic(true);
                $container->removeDefinition($id);
                $compiler->addLogMessage($formatter->formatRemoveService($this, $id, 'replaces alias '.reset($referencingAliases)));
            } elseif (0 === count($referencingAliases) && false === $isReferenced) {
                $container->removeDefinition($id);
                $compiler->addLogMessage($formatter->formatRemoveService($this, $id, 'unused'));
                $hasChanged = true;
            }
        }

        if ($hasChanged) {
            $this->repeatedPass->setRepeat();
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
 * Remove private aliases from the container. They were only used to establish
 * dependencies between services, and these dependencies have been resolved in
 * one of the previous passes.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class RemovePrivateAliasesPass implements CompilerPassInterface
{
    /**
     * Removes private aliases from the ContainerBuilder
     *
     * @param ContainerBuilder $container
     */
    public function process(ContainerBuilder $container)
    {
        $compiler = $container->getCompiler();
        $formatter = $compiler->getLoggingFormatter();

        foreach ($container->getAliases() as $id => $alias) {
            if ($alias->isPublic()) {
                continue;
            }

            $container->removeAlias($id);
            $compiler->addLogMessage($formatter->formatRemoveService($this, $id, 'private alias'));
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Definition;

use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
 * Checks that all references are pointing to a valid service.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class CheckExceptionOnInvalidReferenceBehaviorPass implements CompilerPassInterface
{
    private $container;
    private $sourceId;

    public function process(ContainerBuilder $container)
    {
        $this->container = $container;

        foreach ($container->getDefinitions() as $id => $definition) {
            $this->sourceId = $id;
            $this->processDefinition($definition);
        }
    }

    private function processDefinition(Definition $definition)
    {
        $this->processReferences($definition->getArguments());
        $this->processReferences($definition->getMethodCalls());
        $this->processReferences($definition->getProperties());
    }

    private function processReferences(array $arguments)
    {
        foreach ($arguments as $argument) {
            if (is_array($argument)) {
                $this->processReferences($argument);
            } elseif ($argument instanceof Definition) {
                $this->processDefinition($argument);
            } elseif ($argument instanceof Reference && ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $argument->getInvalidBehavior()) {
                $destId = (string) $argument;

                if (!$this->container->has($destId)) {
                    throw new ServiceNotFoundException($destId, $this->sourceId);
                }
            }
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;

/**
 * This pass validates each definition individually only taking the information
 * into account which is contained in the definition itself.
 *
 * Later passes can rely on the following, and specifically do not need to
 * perform these checks themselves:
 *
 * - non synthetic, non abstract services always have a class set
 * - synthetic services are always public
 * - synthetic services are always of non-prototype scope
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class CheckDefinitionValidityPass implements CompilerPassInterface
{
    /**
     * Processes the ContainerBuilder to validate the Definition.
     *
     * @param ContainerBuilder $container
     *
     * @throws RuntimeException When the Definition is invalid
     */
    public function process(ContainerBuilder $container)
    {
        foreach ($container->getDefinitions() as $id => $definition) {
            // synthetic service is public
            if ($definition->isSynthetic() && !$definition->isPublic()) {
                throw new RuntimeException(sprintf(
                    'A synthetic service ("%s") must be public.',
                    $id
                ));
            }

            // synthetic service has non-prototype scope
            if ($definition->isSynthetic() && ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope()) {
                throw new RuntimeException(sprintf(
                    'A synthetic service ("%s") cannot be of scope "prototype".',
                    $id
                ));
            }

            // non-synthetic, non-abstract service has class
            if (!$definition->isAbstract() && !$definition->isSynthetic() && !$definition->getClass()) {
                if ($definition->getFactoryClass() || $definition->getFactoryService()) {
                    throw new RuntimeException(sprintf(
                        'Please add the class to service "%s" even if it is constructed by a factory '
                       .'since we might need to add method calls based on compile-time checks.',
                       $id
                    ));
                }

                throw new RuntimeException(sprintf(
                    'The definition for "%s" has no class. If you intend to inject '
                   .'this service dynamically at runtime, please mark it as synthetic=true. '
                   .'If this is an abstract definition solely used by child definitions, '
                   .'please add abstract=true, otherwise specify a class to get rid of this error.',
                   $id
                ));
            }
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;

/**
 * Replaces aliases with actual service definitions, effectively removing these
 * aliases.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ReplaceAliasByActualDefinitionPass implements CompilerPassInterface
{
    private $compiler;
    private $formatter;
    private $sourceId;

    /**
     * Process the Container to replace aliases with service definitions.
     *
     * @param ContainerBuilder $container
     *
     * @throws InvalidArgumentException if the service definition does not exist
     */
    public function process(ContainerBuilder $container)
    {
        $this->compiler = $container->getCompiler();
        $this->formatter = $this->compiler->getLoggingFormatter();

        foreach ($container->getAliases() as $id => $alias) {
            $aliasId = (string) $alias;

            try {
                $definition = $container->getDefinition($aliasId);
            } catch (InvalidArgumentException $e) {
                throw new InvalidArgumentException(sprintf('Unable to replace alias "%s" with "%s".', $alias, $id), null, $e);
            }

            if ($definition->isPublic()) {
                continue;
            }

            $definition->setPublic(true);
            $container->setDefinition($id, $definition);
            $container->removeDefinition($aliasId);

            $this->updateReferences($container, $aliasId, $id);

            // we have to restart the process due to concurrent modification of
            // the container
            $this->process($container);

            break;
        }
    }

    /**
     * Updates references to remove aliases.
     *
     * @param ContainerBuilder $container The container
     * @param string           $currentId The alias identifier being replaced
     * @param string           $newId     The id of the service the alias points to
     */
    private function updateReferences($container, $currentId, $newId)
    {
        foreach ($container->getAliases() as $id => $alias) {
            if ($currentId === (string) $alias) {
                $container->setAlias($id, $newId);
            }
        }

        foreach ($container->getDefinitions() as $id => $definition) {
            $this->sourceId = $id;

            $definition->setArguments(
                $this->updateArgumentReferences($definition->getArguments(), $currentId, $newId)
            );

            $definition->setMethodCalls(
                $this->updateArgumentReferences($definition->getMethodCalls(), $currentId, $newId)
            );

            $definition->setProperties(
                $this->updateArgumentReferences($definition->getProperties(), $currentId, $newId)
            );
        }
    }

    /**
     * Updates argument references.
     *
     * @param array  $arguments An array of Arguments
     * @param string $currentId The alias identifier
     * @param string $newId     The identifier the alias points to
     *
     * @return array
     */
    private function updateArgumentReferences(array $arguments, $currentId, $newId)
    {
        foreach ($arguments as $k => $argument) {
            if (is_array($argument)) {
                $arguments[$k] = $this->updateArgumentReferences($argument, $currentId, $newId);
            } elseif ($argument instanceof Reference) {
                if ($currentId === (string) $argument) {
                    $arguments[$k] = new Reference($newId, $argument->getInvalidBehavior());
                    $this->compiler->addLogMessage($this->formatter->formatUpdateReference($this, $this->sourceId, $currentId, $newId));
                }
            }
        }

        return $arguments;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;

/**
 * Merges extension configs into the container builder
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class MergeExtensionConfigurationPass implements CompilerPassInterface
{
    /**
     * {@inheritDoc}
     */
    public function process(ContainerBuilder $container)
    {
        $parameters = $container->getParameterBag()->all();
        $definitions = $container->getDefinitions();
        $aliases = $container->getAliases();

        foreach ($container->getExtensions() as $extension) {
            if ($extension instanceof PrependExtensionInterface) {
                $extension->prepend($container);
            }
        }

        foreach ($container->getExtensions() as $name => $extension) {
            if (!$config = $container->getExtensionConfig($name)) {
                // this extension was not called
                continue;
            }
            $config = $container->getParameterBag()->resolveValue($config);

            $tmpContainer = new ContainerBuilder($container->getParameterBag());
            $tmpContainer->setResourceTracking($container->isTrackingResources());
            $tmpContainer->addObjectResource($extension);

            $extension->load($config, $tmpContainer);

            $container->merge($tmpContainer);
        }

        $container->addDefinitions($definitions);
        $container->addAliases($aliases);
        $container->getParameterBag()->add($parameters);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
 * Inline service definitions where this is possible.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class InlineServiceDefinitionsPass implements RepeatablePassInterface
{
    private $repeatedPass;
    private $graph;
    private $compiler;
    private $formatter;
    private $currentId;

    /**
     * {@inheritDoc}
     */
    public function setRepeatedPass(RepeatedPass $repeatedPass)
    {
        $this->repeatedPass = $repeatedPass;
    }

    /**
     * Processes the ContainerBuilder for inline service definitions.
     *
     * @param ContainerBuilder $container
     */
    public function process(ContainerBuilder $container)
    {
        $this->compiler = $container->getCompiler();
        $this->formatter = $this->compiler->getLoggingFormatter();
        $this->graph = $this->compiler->getServiceReferenceGraph();

        foreach ($container->getDefinitions() as $id => $definition) {
            $this->currentId = $id;

            $definition->setArguments(
                $this->inlineArguments($container, $definition->getArguments())
            );

            $definition->setMethodCalls(
                $this->inlineArguments($container, $definition->getMethodCalls())
            );

            $definition->setProperties(
                $this->inlineArguments($container, $definition->getProperties())
            );
        }
    }

    /**
     * Processes inline arguments.
     *
     * @param ContainerBuilder $container The ContainerBuilder
     * @param array            $arguments An array of arguments
     *
     * @return array
     */
    private function inlineArguments(ContainerBuilder $container, array $arguments)
    {
        foreach ($arguments as $k => $argument) {
            if (is_array($argument)) {
                $arguments[$k] = $this->inlineArguments($container, $argument);
            } elseif ($argument instanceof Reference) {
                if (!$container->hasDefinition($id = (string) $argument)) {
                    continue;
                }

                if ($this->isInlineableDefinition($container, $id, $definition = $container->getDefinition($id))) {
                    $this->compiler->addLogMessage($this->formatter->formatInlineService($this, $id, $this->currentId));

                    if (ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope()) {
                        $arguments[$k] = $definition;
                    } else {
                        $arguments[$k] = clone $definition;
                    }
                }
            } elseif ($argument instanceof Definition) {
                $argument->setArguments($this->inlineArguments($container, $argument->getArguments()));
                $argument->setMethodCalls($this->inlineArguments($container, $argument->getMethodCalls()));
                $argument->setProperties($this->inlineArguments($container, $argument->getProperties()));
            }
        }

        return $arguments;
    }

    /**
     * Checks if the definition is inlineable.
     *
     * @param ContainerBuilder $container
     * @param string           $id
     * @param Definition       $definition
     *
     * @return Boolean If the definition is inlineable
     */
    private function isInlineableDefinition(ContainerBuilder $container, $id, Definition $definition)
    {
        if (ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope()) {
            return true;
        }

        if ($definition->isPublic()) {
            return false;
        }

        if (!$this->graph->hasNode($id)) {
            return true;
        }

        $ids = array();
        foreach ($this->graph->getNode($id)->getInEdges() as $edge) {
            $ids[] = $edge->getSourceNode()->getId();
        }

        if (count(array_unique($ids)) > 1) {
            return false;
        }

        return $container->getDefinition(reset($ids))->getScope() === $definition->getScope();
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;

/**
 * This class is used to remove circular dependencies between individual passes.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 *
 * @api
 */
class Compiler
{
    private $passConfig;
    private $log;
    private $loggingFormatter;
    private $serviceReferenceGraph;

    /**
     * Constructor.
     */
    public function __construct()
    {
        $this->passConfig = new PassConfig();
        $this->serviceReferenceGraph = new ServiceReferenceGraph();
        $this->loggingFormatter = new LoggingFormatter();
        $this->log = array();
    }

    /**
     * Returns the PassConfig.
     *
     * @return PassConfig The PassConfig instance
     *
     * @api
     */
    public function getPassConfig()
    {
        return $this->passConfig;
    }

    /**
     * Returns the ServiceReferenceGraph.
     *
     * @return ServiceReferenceGraph The ServiceReferenceGraph instance
     *
     * @api
     */
    public function getServiceReferenceGraph()
    {
        return $this->serviceReferenceGraph;
    }

    /**
     * Returns the logging formatter which can be used by compilation passes.
     *
     * @return LoggingFormatter
     */
    public function getLoggingFormatter()
    {
        return $this->loggingFormatter;
    }

    /**
     * Adds a pass to the PassConfig.
     *
     * @param CompilerPassInterface $pass A compiler pass
     * @param string                $type The type of the pass
     *
     * @api
     */
    public function addPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION)
    {
        $this->passConfig->addPass($pass, $type);
    }

    /**
     * Adds a log message.
     *
     * @param string $string The log message
     */
    public function addLogMessage($string)
    {
        $this->log[] = $string;
    }

    /**
     * Returns the log.
     *
     * @return array Log array
     */
    public function getLog()
    {
        return $this->log;
    }

    /**
     * Run the Compiler and process all Passes.
     *
     * @param ContainerBuilder $container
     *
     * @api
     */
    public function compile(ContainerBuilder $container)
    {
        foreach ($this->passConfig->getPasses() as $pass) {
            $pass->process($container);
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;

/**
 * Emulates the invalid behavior if the reference is not found within the
 * container.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ResolveInvalidReferencesPass implements CompilerPassInterface
{
    private $container;

    /**
     * Process the ContainerBuilder to resolve invalid references.
     *
     * @param ContainerBuilder $container
     */
    public function process(ContainerBuilder $container)
    {
        $this->container = $container;
        foreach ($container->getDefinitions() as $definition) {
            if ($definition->isSynthetic() || $definition->isAbstract()) {
                continue;
            }

            $definition->setArguments(
                $this->processArguments($definition->getArguments())
            );

            $calls = array();
            foreach ($definition->getMethodCalls() as $call) {
                try {
                    $calls[] = array($call[0], $this->processArguments($call[1], true));
                } catch (RuntimeException $ignore) {
                    // this call is simply removed
                }
            }
            $definition->setMethodCalls($calls);

            $properties = array();
            foreach ($definition->getProperties() as $name => $value) {
                try {
                    $value = $this->processArguments(array($value), true);
                    $properties[$name] = reset($value);
                } catch (RuntimeException $ignore) {
                    // ignore property
                }
            }
            $definition->setProperties($properties);
        }
    }

    /**
     * Processes arguments to determine invalid references.
     *
     * @param array   $arguments    An array of Reference objects
     * @param Boolean $inMethodCall
     *
     * @return array
     *
     * @throws RuntimeException When the config is invalid
     */
    private function processArguments(array $arguments, $inMethodCall = false)
    {
        foreach ($arguments as $k => $argument) {
            if (is_array($argument)) {
                $arguments[$k] = $this->processArguments($argument, $inMethodCall);
            } elseif ($argument instanceof Reference) {
                $id = (string) $argument;

                $invalidBehavior = $argument->getInvalidBehavior();
                $exists = $this->container->has($id);

                // resolve invalid behavior
                if (!$exists && ContainerInterface::NULL_ON_INVALID_REFERENCE === $invalidBehavior) {
                    $arguments[$k] = null;
                } elseif (!$exists && ContainerInterface::IGNORE_ON_INVALID_REFERENCE === $invalidBehavior) {
                    if ($inMethodCall) {
                        throw new RuntimeException('Method shouldn\'t be called.');
                    }

                    $arguments[$k] = null;
                }
            }
        }

        return $arguments;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
 * Replaces all references to aliases with references to the actual service.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ResolveReferencesToAliasesPass implements CompilerPassInterface
{
    private $container;

    /**
     * Processes the ContainerBuilder to replace references to aliases with actual service references.
     *
     * @param ContainerBuilder $container
     */
    public function process(ContainerBuilder $container)
    {
        $this->container = $container;

        foreach ($container->getDefinitions() as $definition) {
            if ($definition->isSynthetic() || $definition->isAbstract()) {
                continue;
            }

            $definition->setArguments($this->processArguments($definition->getArguments()));
            $definition->setMethodCalls($this->processArguments($definition->getMethodCalls()));
            $definition->setProperties($this->processArguments($definition->getProperties()));
        }

        foreach ($container->getAliases() as $id => $alias) {
            $aliasId = (string) $alias;
            if ($aliasId !== $defId = $this->getDefinitionId($aliasId)) {
                $container->setAlias($id, new Alias($defId, $alias->isPublic()));
            }
        }
    }

    /**
     * Processes the arguments to replace aliases.
     *
     * @param array $arguments An array of References
     *
     * @return array An array of References
     */
    private function processArguments(array $arguments)
    {
        foreach ($arguments as $k => $argument) {
            if (is_array($argument)) {
                $arguments[$k] = $this->processArguments($argument);
            } elseif ($argument instanceof Reference) {
                $defId = $this->getDefinitionId($id = (string) $argument);

                if ($defId !== $id) {
                    $arguments[$k] = new Reference($defId, $argument->getInvalidBehavior(), $argument->isStrict());
                }
            }
        }

        return $arguments;
    }

    /**
     * Resolves an alias into a definition id.
     *
     * @param string $id The definition or alias id to resolve
     *
     * @return string The definition id with aliases resolved
     */
    private function getDefinitionId($id)
    {
        while ($this->container->hasAlias($id)) {
            $id = (string) $this->container->getAlias($id);
        }

        return $id;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Alias;

/**
 * Represents a node in your service graph.
 *
 * Value is typically a definition, or an alias.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ServiceReferenceGraphNode
{
    private $id;
    private $inEdges;
    private $outEdges;
    private $value;

    /**
     * Constructor.
     *
     * @param string $id    The node identifier
     * @param mixed  $value The node value
     */
    public function __construct($id, $value)
    {
        $this->id = $id;
        $this->value = $value;
        $this->inEdges = array();
        $this->outEdges = array();
    }

    /**
     * Adds an in edge to this node.
     *
     * @param ServiceReferenceGraphEdge $edge
     */
    public function addInEdge(ServiceReferenceGraphEdge $edge)
    {
        $this->inEdges[] = $edge;
    }

    /**
     * Adds an out edge to this node.
     *
     * @param ServiceReferenceGraphEdge $edge
     */
    public function addOutEdge(ServiceReferenceGraphEdge $edge)
    {
        $this->outEdges[] = $edge;
    }

    /**
     * Checks if the value of this node is an Alias.
     *
     * @return Boolean True if the value is an Alias instance
     */
    public function isAlias()
    {
        return $this->value instanceof Alias;
    }

    /**
     * Checks if the value of this node is a Definition.
     *
     * @return Boolean True if the value is a Definition instance
     */
    public function isDefinition()
    {
        return $this->value instanceof Definition;
    }

    /**
     * Returns the identifier.
     *
     * @return string
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Returns the in edges.
     *
     * @return array The in ServiceReferenceGraphEdge array
     */
    public function getInEdges()
    {
        return $this->inEdges;
    }

    /**
     * Returns the out edges.
     *
     * @return array The out ServiceReferenceGraphEdge array
     */
    public function getOutEdges()
    {
        return $this->outEdges;
    }

    /**
     * Returns the value of this Node
     *
     * @return mixed The value
     */
    public function getValue()
    {
        return $this->value;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
 * Run this pass before passes that need to know more about the relation of
 * your services.
 *
 * This class will populate the ServiceReferenceGraph with information. You can
 * retrieve the graph in other passes from the compiler.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class AnalyzeServiceReferencesPass implements RepeatablePassInterface
{
    private $graph;
    private $container;
    private $currentId;
    private $currentDefinition;
    private $repeatedPass;
    private $onlyConstructorArguments;

    /**
     * Constructor.
     *
     * @param Boolean $onlyConstructorArguments Sets this Service Reference pass to ignore method calls
     */
    public function __construct($onlyConstructorArguments = false)
    {
        $this->onlyConstructorArguments = (Boolean) $onlyConstructorArguments;
    }

    /**
     * {@inheritDoc}
     */
    public function setRepeatedPass(RepeatedPass $repeatedPass)
    {
        $this->repeatedPass = $repeatedPass;
    }

    /**
     * Processes a ContainerBuilder object to populate the service reference graph.
     *
     * @param ContainerBuilder $container
     */
    public function process(ContainerBuilder $container)
    {
        $this->container = $container;
        $this->graph     = $container->getCompiler()->getServiceReferenceGraph();
        $this->graph->clear();

        foreach ($container->getDefinitions() as $id => $definition) {
            if ($definition->isSynthetic() || $definition->isAbstract()) {
                continue;
            }

            $this->currentId = $id;
            $this->currentDefinition = $definition;
            $this->processArguments($definition->getArguments());

            if (!$this->onlyConstructorArguments) {
                $this->processArguments($definition->getMethodCalls());
                $this->processArguments($definition->getProperties());
                if ($definition->getConfigurator()) {
                    $this->processArguments(array($definition->getConfigurator()));
                }
            }
        }

        foreach ($container->getAliases() as $id => $alias) {
            $this->graph->connect($id, $alias, (string) $alias, $this->getDefinition((string) $alias), null);
        }
    }

    /**
     * Processes service definitions for arguments to find relationships for the service graph.
     *
     * @param array $arguments An array of Reference or Definition objects relating to service definitions
     */
    private function processArguments(array $arguments)
    {
        foreach ($arguments as $argument) {
            if (is_array($argument)) {
                $this->processArguments($argument);
            } elseif ($argument instanceof Reference) {
                $this->graph->connect(
                    $this->currentId,
                    $this->currentDefinition,
                    $this->getDefinitionId((string) $argument),
                    $this->getDefinition((string) $argument),
                    $argument
                );
            } elseif ($argument instanceof Definition) {
                $this->processArguments($argument->getArguments());
                $this->processArguments($argument->getMethodCalls());
                $this->processArguments($argument->getProperties());
            }
        }
    }

    /**
     * Returns a service definition given the full name or an alias.
     *
     * @param string $id A full id or alias for a service definition.
     *
     * @return Definition|null The definition related to the supplied id
     */
    private function getDefinition($id)
    {
        $id = $this->getDefinitionId($id);

        return null === $id ? null : $this->container->getDefinition($id);
    }

    private function getDefinitionId($id)
    {
        while ($this->container->hasAlias($id)) {
            $id = (string) $this->container->getAlias($id);
        }

        if (!$this->container->hasDefinition($id)) {
            return null;
        }

        return $id;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
 * Removes abstract Definitions
 *
 */
class RemoveAbstractDefinitionsPass implements CompilerPassInterface
{
    /**
     * Removes abstract definitions from the ContainerBuilder
     *
     * @param ContainerBuilder $container
     */
    public function process(ContainerBuilder $container)
    {
        $compiler = $container->getCompiler();
        $formatter = $compiler->getLoggingFormatter();

        foreach ($container->getDefinitions() as $id => $definition) {
            if ($definition->isAbstract()) {
                $container->removeDefinition($id);
                $compiler->addLogMessage($formatter->formatRemoveService($this, $id, 'abstract'));
            }
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

/**
 * Used to format logging messages during the compilation.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class LoggingFormatter
{
    public function formatRemoveService(CompilerPassInterface $pass, $id, $reason)
    {
        return $this->format($pass, sprintf('Removed service "%s"; reason: %s', $id, $reason));
    }

    public function formatInlineService(CompilerPassInterface $pass, $id, $target)
    {
        return $this->format($pass, sprintf('Inlined service "%s" to "%s".', $id, $target));
    }

    public function formatUpdateReference(CompilerPassInterface $pass, $serviceId, $oldDestId, $newDestId)
    {
        return $this->format($pass, sprintf('Changed reference of service "%s" previously pointing to "%s" to "%s".', $serviceId, $oldDestId, $newDestId));
    }

    public function formatResolveInheritance(CompilerPassInterface $pass, $childId, $parentId)
    {
        return $this->format($pass, sprintf('Resolving inheritance for "%s" (parent: %s).', $childId, $parentId));
    }

    public function format(CompilerPassInterface $pass, $message)
    {
        return sprintf('%s: %s', get_class($pass), $message);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;

/**
 * Compiler Pass Configuration
 *
 * This class has a default configuration embedded.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 *
 * @api
 */
class PassConfig
{
    const TYPE_AFTER_REMOVING = 'afterRemoving';
    const TYPE_BEFORE_OPTIMIZATION = 'beforeOptimization';
    const TYPE_BEFORE_REMOVING = 'beforeRemoving';
    const TYPE_OPTIMIZE = 'optimization';
    const TYPE_REMOVE = 'removing';

    private $mergePass;
    private $afterRemovingPasses;
    private $beforeOptimizationPasses;
    private $beforeRemovingPasses;
    private $optimizationPasses;
    private $removingPasses;

    /**
     * Constructor.
     */
    public function __construct()
    {
        $this->mergePass = new MergeExtensionConfigurationPass();

        $this->afterRemovingPasses = array();
        $this->beforeOptimizationPasses = array();
        $this->beforeRemovingPasses = array();

        $this->optimizationPasses = array(
            new ResolveDefinitionTemplatesPass(),
            new ResolveParameterPlaceHoldersPass(),
            new CheckDefinitionValidityPass(),
            new ResolveReferencesToAliasesPass(),
            new ResolveInvalidReferencesPass(),
            new AnalyzeServiceReferencesPass(true),
            new CheckCircularReferencesPass(),
            new CheckReferenceValidityPass(),
        );

        $this->removingPasses = array(
            new RemovePrivateAliasesPass(),
            new RemoveAbstractDefinitionsPass(),
            new ReplaceAliasByActualDefinitionPass(),
            new RepeatedPass(array(
                new AnalyzeServiceReferencesPass(),
                new InlineServiceDefinitionsPass(),
                new AnalyzeServiceReferencesPass(),
                new RemoveUnusedDefinitionsPass(),
            )),
            new CheckExceptionOnInvalidReferenceBehaviorPass(),
        );
    }

    /**
     * Returns all passes in order to be processed.
     *
     * @return array An array of all passes to process
     *
     * @api
     */
    public function getPasses()
    {
        return array_merge(
            array($this->mergePass),
            $this->beforeOptimizationPasses,
            $this->optimizationPasses,
            $this->beforeRemovingPasses,
            $this->removingPasses,
            $this->afterRemovingPasses
        );
    }

    /**
     * Adds a pass.
     *
     * @param CompilerPassInterface $pass A Compiler pass
     * @param string                $type The pass type
     *
     * @throws InvalidArgumentException when a pass type doesn't exist
     *
     * @api
     */
    public function addPass(CompilerPassInterface $pass, $type = self::TYPE_BEFORE_OPTIMIZATION)
    {
        $property = $type.'Passes';
        if (!isset($this->$property)) {
            throw new InvalidArgumentException(sprintf('Invalid type "%s".', $type));
        }

        $passes = &$this->$property;
        $passes[] = $pass;
    }

    /**
     * Gets all passes for the AfterRemoving pass.
     *
     * @return array An array of passes
     *
     * @api
     */
    public function getAfterRemovingPasses()
    {
        return $this->afterRemovingPasses;
    }

    /**
     * Gets all passes for the BeforeOptimization pass.
     *
     * @return array An array of passes
     *
     * @api
     */
    public function getBeforeOptimizationPasses()
    {
        return $this->beforeOptimizationPasses;
    }

    /**
     * Gets all passes for the BeforeRemoving pass.
     *
     * @return array An array of passes
     *
     * @api
     */
    public function getBeforeRemovingPasses()
    {
        return $this->beforeRemovingPasses;
    }

    /**
     * Gets all passes for the Optimization pass.
     *
     * @return array An array of passes
     *
     * @api
     */
    public function getOptimizationPasses()
    {
        return $this->optimizationPasses;
    }

    /**
     * Gets all passes for the Removing pass.
     *
     * @return array An array of passes
     *
     * @api
     */
    public function getRemovingPasses()
    {
        return $this->removingPasses;
    }

    /**
     * Gets all passes for the Merge pass.
     *
     * @return array An array of passes
     *
     * @api
     */
    public function getMergePass()
    {
        return $this->mergePass;
    }

    /**
     * Sets the Merge Pass.
     *
     * @param CompilerPassInterface $pass The merge pass
     *
     * @api
     */
    public function setMergePass(CompilerPassInterface $pass)
    {
        $this->mergePass = $pass;
    }

    /**
     * Sets the AfterRemoving passes.
     *
     * @param array $passes An array of passes
     *
     * @api
     */
    public function setAfterRemovingPasses(array $passes)
    {
        $this->afterRemovingPasses = $passes;
    }

    /**
     * Sets the BeforeOptimization passes.
     *
     * @param array $passes An array of passes
     *
     * @api
     */
    public function setBeforeOptimizationPasses(array $passes)
    {
        $this->beforeOptimizationPasses = $passes;
    }

    /**
     * Sets the BeforeRemoving passes.
     *
     * @param array $passes An array of passes
     *
     * @api
     */
    public function setBeforeRemovingPasses(array $passes)
    {
        $this->beforeRemovingPasses = $passes;
    }

    /**
     * Sets the Optimization passes.
     *
     * @param array $passes An array of passes
     *
     * @api
     */
    public function setOptimizationPasses(array $passes)
    {
        $this->optimizationPasses = $passes;
    }

    /**
     * Sets the Removing passes.
     *
     * @param array $passes An array of passes
     *
     * @api
     */
    public function setRemovingPasses(array $passes)
    {
        $this->removingPasses = $passes;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

/**
 * Represents an edge in your service graph.
 *
 * Value is typically a reference.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ServiceReferenceGraphEdge
{
    private $sourceNode;
    private $destNode;
    private $value;

    /**
     * Constructor.
     *
     * @param ServiceReferenceGraphNode $sourceNode
     * @param ServiceReferenceGraphNode $destNode
     * @param string                    $value
     */
    public function __construct(ServiceReferenceGraphNode $sourceNode, ServiceReferenceGraphNode $destNode, $value = null)
    {
        $this->sourceNode = $sourceNode;
        $this->destNode = $destNode;
        $this->value = $value;
    }

    /**
     * Returns the value of the edge
     *
     * @return ServiceReferenceGraphNode
     */
    public function getValue()
    {
        return $this->value;
    }

    /**
     * Returns the source node
     *
     * @return ServiceReferenceGraphNode
     */
    public function getSourceNode()
    {
        return $this->sourceNode;
    }

    /**
     * Returns the destination node
     *
     * @return ServiceReferenceGraphNode
     */
    public function getDestNode()
    {
        return $this->destNode;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;

/**
 * Resolves all parameter placeholders "%somevalue%" to their real values.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ResolveParameterPlaceHoldersPass implements CompilerPassInterface
{
    /**
     * Processes the ContainerBuilder to resolve parameter placeholders.
     *
     * @param ContainerBuilder $container
     *
     * @throws ParameterNotFoundException
     */
    public function process(ContainerBuilder $container)
    {
        $parameterBag = $container->getParameterBag();

        foreach ($container->getDefinitions() as $id => $definition) {
            try {
                $definition->setClass($parameterBag->resolveValue($definition->getClass()));
                $definition->setFile($parameterBag->resolveValue($definition->getFile()));
                $definition->setArguments($parameterBag->resolveValue($definition->getArguments()));

                $calls = array();
                foreach ($definition->getMethodCalls() as $name => $arguments) {
                    $calls[$parameterBag->resolveValue($name)] = $parameterBag->resolveValue($arguments);
                }
                $definition->setMethodCalls($calls);

                $definition->setProperties($parameterBag->resolveValue($definition->getProperties()));
            } catch (ParameterNotFoundException $e) {
                $e->setSourceId($id);

                throw $e;
            }
        }

        $aliases = array();
        foreach ($container->getAliases() as $name => $target) {
            $aliases[$parameterBag->resolveValue($name)] = $parameterBag->resolveValue($target);
        }
        $container->setAliases($aliases);

        $parameterBag->resolve();
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Exception\ScopeCrossingInjectionException;
use Symfony\Component\DependencyInjection\Exception\ScopeWideningInjectionException;

/**
 * Checks the validity of references
 *
 * The following checks are performed by this pass:
 * - target definitions are not abstract
 * - target definitions are of equal or wider scope
 * - target definitions are in the same scope hierarchy
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class CheckReferenceValidityPass implements CompilerPassInterface
{
    private $container;
    private $currentId;
    private $currentDefinition;
    private $currentScope;
    private $currentScopeAncestors;
    private $currentScopeChildren;

    /**
     * Processes the ContainerBuilder to validate References.
     *
     * @param ContainerBuilder $container
     */
    public function process(ContainerBuilder $container)
    {
        $this->container = $container;

        $children = $this->container->getScopeChildren();
        $ancestors = array();

        $scopes = $this->container->getScopes();
        foreach ($scopes as $name => $parent) {
            $ancestors[$name] = array($parent);

            while (isset($scopes[$parent])) {
                $ancestors[$name][] = $parent = $scopes[$parent];
            }
        }

        foreach ($container->getDefinitions() as $id => $definition) {
            if ($definition->isSynthetic() || $definition->isAbstract()) {
                continue;
            }

            $this->currentId = $id;
            $this->currentDefinition = $definition;
            $this->currentScope = $scope = $definition->getScope();

            if (ContainerInterface::SCOPE_CONTAINER === $scope) {
                $this->currentScopeChildren = array_keys($scopes);
                $this->currentScopeAncestors = array();
            } elseif (ContainerInterface::SCOPE_PROTOTYPE !== $scope) {
                $this->currentScopeChildren = isset($children[$scope]) ? $children[$scope] : array();
                $this->currentScopeAncestors = isset($ancestors[$scope]) ? $ancestors[$scope] : array();
            }

            $this->validateReferences($definition->getArguments());
            $this->validateReferences($definition->getMethodCalls());
            $this->validateReferences($definition->getProperties());
        }
    }

    /**
     * Validates an array of References.
     *
     * @param array $arguments An array of Reference objects
     *
     * @throws RuntimeException when there is a reference to an abstract definition.
     */
    private function validateReferences(array $arguments)
    {
        foreach ($arguments as $argument) {
            if (is_array($argument)) {
                $this->validateReferences($argument);
            } elseif ($argument instanceof Reference) {
                $targetDefinition = $this->getDefinition((string) $argument);

                if (null !== $targetDefinition && $targetDefinition->isAbstract()) {
                    throw new RuntimeException(sprintf(
                        'The definition "%s" has a reference to an abstract definition "%s". '
                       .'Abstract definitions cannot be the target of references.',
                       $this->currentId,
                       $argument
                    ));
                }

                $this->validateScope($argument, $targetDefinition);
            }
        }
    }

    /**
     * Validates the scope of a single Reference.
     *
     * @param Reference  $reference
     * @param Definition $definition
     *
     * @throws ScopeWideningInjectionException when the definition references a service of a narrower scope
     * @throws ScopeCrossingInjectionException when the definition references a service of another scope hierarchy
     */
    private function validateScope(Reference $reference, Definition $definition = null)
    {
        if (ContainerInterface::SCOPE_PROTOTYPE === $this->currentScope) {
            return;
        }

        if (!$reference->isStrict()) {
            return;
        }

        if (null === $definition) {
            return;
        }

        if ($this->currentScope === $scope = $definition->getScope()) {
            return;
        }

        $id = (string) $reference;

        if (in_array($scope, $this->currentScopeChildren, true)) {
            throw new ScopeWideningInjectionException($this->currentId, $this->currentScope, $id, $scope);
        }

        if (!in_array($scope, $this->currentScopeAncestors, true)) {
            throw new ScopeCrossingInjectionException($this->currentId, $this->currentScope, $id, $scope);
        }
    }

    /**
     * Returns the Definition given an id.
     *
     * @param string $id Definition identifier
     *
     * @return Definition
     */
    private function getDefinition($id)
    {
        if (!$this->container->hasDefinition($id)) {
            return null;
        }

        return $this->container->getDefinition($id);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;

/**
 * A pass that might be run repeatedly.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class RepeatedPass implements CompilerPassInterface
{
    /**
     * @var Boolean
     */
    private $repeat = false;

    /**
     * @var RepeatablePassInterface[]
     */
    private $passes;

    /**
     * Constructor.
     *
     * @param RepeatablePassInterface[] $passes An array of RepeatablePassInterface objects
     *
     * @throws InvalidArgumentException when the passes don't implement RepeatablePassInterface
     */
    public function __construct(array $passes)
    {
        foreach ($passes as $pass) {
            if (!$pass instanceof RepeatablePassInterface) {
                throw new InvalidArgumentException('$passes must be an array of RepeatablePassInterface.');
            }

            $pass->setRepeatedPass($this);
        }

        $this->passes = $passes;
    }

    /**
     * Process the repeatable passes that run more than once.
     *
     * @param ContainerBuilder $container
     */
    public function process(ContainerBuilder $container)
    {
        $this->repeat = false;
        foreach ($this->passes as $pass) {
            $pass->process($container);
        }

        if ($this->repeat) {
            $this->process($container);
        }
    }

    /**
     * Sets if the pass should repeat
     */
    public function setRepeat()
    {
        $this->repeat = true;
    }

    /**
     * Returns the passes
     *
     * @return RepeatablePassInterface[] An array of RepeatablePassInterface objects
     */
    public function getPasses()
    {
        return $this->passes;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;

/**
 * This replaces all DefinitionDecorator instances with their equivalent fully
 * merged Definition instance.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ResolveDefinitionTemplatesPass implements CompilerPassInterface
{
    private $container;
    private $compiler;
    private $formatter;

    /**
     * Process the ContainerBuilder to replace DefinitionDecorator instances with their real Definition instances.
     *
     * @param ContainerBuilder $container
     */
    public function process(ContainerBuilder $container)
    {
        $this->container = $container;
        $this->compiler = $container->getCompiler();
        $this->formatter = $this->compiler->getLoggingFormatter();

        foreach (array_keys($container->getDefinitions()) as $id) {
            // yes, we are specifically fetching the definition from the
            // container to ensure we are not operating on stale data
            $definition = $container->getDefinition($id);
            if (!$definition instanceof DefinitionDecorator || $definition->isAbstract()) {
                continue;
            }

            $this->resolveDefinition($id, $definition);
        }
    }

    /**
     * Resolves the definition
     *
     * @param string              $id         The definition identifier
     * @param DefinitionDecorator $definition
     *
     * @return Definition
     *
     * @throws \RuntimeException When the definition is invalid
     */
    private function resolveDefinition($id, DefinitionDecorator $definition)
    {
        if (!$this->container->hasDefinition($parent = $definition->getParent())) {
            throw new RuntimeException(sprintf('The parent definition "%s" defined for definition "%s" does not exist.', $parent, $id));
        }

        $parentDef = $this->container->getDefinition($parent);
        if ($parentDef instanceof DefinitionDecorator) {
            $parentDef = $this->resolveDefinition($parent, $parentDef);
        }

        $this->compiler->addLogMessage($this->formatter->formatResolveInheritance($this, $id, $parent));
        $def = new Definition();

        // merge in parent definition
        // purposely ignored attributes: scope, abstract, tags
        $def->setClass($parentDef->getClass());
        $def->setArguments($parentDef->getArguments());
        $def->setMethodCalls($parentDef->getMethodCalls());
        $def->setProperties($parentDef->getProperties());
        $def->setFactoryClass($parentDef->getFactoryClass());
        $def->setFactoryMethod($parentDef->getFactoryMethod());
        $def->setFactoryService($parentDef->getFactoryService());
        $def->setConfigurator($parentDef->getConfigurator());
        $def->setFile($parentDef->getFile());
        $def->setPublic($parentDef->isPublic());

        // overwrite with values specified in the decorator
        $changes = $definition->getChanges();
        if (isset($changes['class'])) {
            $def->setClass($definition->getClass());
        }
        if (isset($changes['factory_class'])) {
            $def->setFactoryClass($definition->getFactoryClass());
        }
        if (isset($changes['factory_method'])) {
            $def->setFactoryMethod($definition->getFactoryMethod());
        }
        if (isset($changes['factory_service'])) {
            $def->setFactoryService($definition->getFactoryService());
        }
        if (isset($changes['configurator'])) {
            $def->setConfigurator($definition->getConfigurator());
        }
        if (isset($changes['file'])) {
            $def->setFile($definition->getFile());
        }
        if (isset($changes['public'])) {
            $def->setPublic($definition->isPublic());
        }

        // merge arguments
        foreach ($definition->getArguments() as $k => $v) {
            if (is_numeric($k)) {
                $def->addArgument($v);
                continue;
            }

            if (0 !== strpos($k, 'index_')) {
                throw new RuntimeException(sprintf('Invalid argument key "%s" found.', $k));
            }

            $index = (integer) substr($k, strlen('index_'));
            $def->replaceArgument($index, $v);
        }

        // merge properties
        foreach ($definition->getProperties() as $k => $v) {
            $def->setProperty($k, $v);
        }

        // append method calls
        if (count($calls = $definition->getMethodCalls()) > 0) {
            $def->setMethodCalls(array_merge($def->getMethodCalls(), $calls));
        }

        // these attributes are always taken from the child
        $def->setAbstract($definition->isAbstract());
        $def->setScope($definition->getScope());
        $def->setTags($definition->getTags());

        // set new definition on container
        $this->container->setDefinition($id, $def);

        return $def;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

/**
 * Interface that must be implemented by passes that are run as part of an
 * RepeatedPass.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
interface RepeatablePassInterface extends CompilerPassInterface
{
    /**
     * Sets the RepeatedPass interface.
     *
     * @param RepeatedPass $repeatedPass
     */
    public function setRepeatedPass(RepeatedPass $repeatedPass);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
 * Checks your services for circular references
 *
 * References from method calls are ignored since we might be able to resolve
 * these references depending on the order in which services are called.
 *
 * Circular reference from method calls will only be detected at run-time.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class CheckCircularReferencesPass implements CompilerPassInterface
{
    private $currentId;
    private $currentPath;

    /**
     * Checks the ContainerBuilder object for circular references.
     *
     * @param ContainerBuilder $container The ContainerBuilder instances
     */
    public function process(ContainerBuilder $container)
    {
        $graph = $container->getCompiler()->getServiceReferenceGraph();

        foreach ($graph->getNodes() as $id => $node) {
            $this->currentId = $id;
            $this->currentPath = array($id);

            $this->checkOutEdges($node->getOutEdges());
        }
    }

    /**
     * Checks for circular references.
     *
     * @param ServiceReferenceGraphEdge[] $edges An array of Edges
     *
     * @throws ServiceCircularReferenceException When a circular reference is found.
     */
    private function checkOutEdges(array $edges)
    {
        foreach ($edges as $edge) {
            $node      = $edge->getDestNode();
            $id        = $node->getId();
            $searchKey = array_search($id, $this->currentPath);
            $this->currentPath[] = $id;

            if (false !== $searchKey) {
                throw new ServiceCircularReferenceException($id, array_slice($this->currentPath, $searchKey));
            }

            $this->checkOutEdges($node->getOutEdges());
            array_pop($this->currentPath);
        }
    }
}
{
    "name": "symfony/dependency-injection",
    "type": "library",
    "description": "Symfony DependencyInjection Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3"
    },
    "require-dev": {
        "symfony/yaml": "~2.0",
        "symfony/config": "~2.2"
    },
    "suggest": {
        "symfony/yaml": "",
        "symfony/config": "",
        "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\DependencyInjection\\": "" }
    },
    "target-dir": "Symfony/Component/DependencyInjection",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.3-dev"
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\LazyProxy\PhpDumper;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;

/**
 * Null dumper, negates any proxy code generation for any given service definition.
 *
 * @author Marco Pivetta <ocramius@gmail.com>
 */
class NullDumper implements DumperInterface
{
    /**
     * {@inheritDoc}
     */
    public function isProxyCandidate(Definition $definition)
    {
        return false;
    }

    /**
     * {@inheritDoc}
     */
    public function getProxyFactoryCode(Definition $definition, $id)
    {
        return '';
    }

    /**
     * {@inheritDoc}
     */
    public function getProxyCode(Definition $definition)
    {
        return '';
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\LazyProxy\PhpDumper;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;

/**
 * Lazy proxy dumper capable of generating the instantiation logic php code for proxied services.
 *
 * @author Marco Pivetta <ocramius@gmail.com>
 */
interface DumperInterface
{
    /**
     * Inspects whether the given definitions should produce proxy instantiation logic in the dumped container.
     *
     * @param Definition $definition
     *
     * @return bool
     */
    public function isProxyCandidate(Definition $definition);

    /**
     * Generates the code to be used to instantiate a proxy in the dumped factory code.
     *
     * @param Definition $definition
     * @param string     $id         service identifier
     *
     * @return string
     */
    public function getProxyFactoryCode(Definition $definition, $id);

    /**
     * Generates the code for the lazy proxy.
     *
     * @param Definition $definition
     *
     * @return string
     */
    public function getProxyCode(Definition $definition);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\LazyProxy\Instantiator;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;

/**
 * {@inheritDoc}
 *
 * Noop proxy instantiator - simply produces the real service instead of a proxy instance.
 *
 * @author Marco Pivetta <ocramius@gmail.com>
 */
class RealServiceInstantiator implements InstantiatorInterface
{
    /**
     * {@inheritDoc}
     */
    public function instantiateProxy(ContainerInterface $container, Definition $definition, $id, $realInstantiator)
    {
        return call_user_func($realInstantiator);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\LazyProxy\Instantiator;

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;

/**
 * Lazy proxy instantiator, capable of instantiating a proxy given a container, the
 * service definitions and a callback that produces the real service instance.
 *
 * @author Marco Pivetta <ocramius@gmail.com>
 */
interface InstantiatorInterface
{
    /**
     * Instantiates a proxy object.
     *
     * @param ContainerInterface $container        the container from which the service is being requested
     * @param Definition         $definition       the definition of the requested service
     * @param string             $id               identifier of the requested service
     * @param callable           $realInstantiator zero-argument callback that is capable of producing the real
     *                                             service instance
     *
     * @return object
     */
    public function instantiateProxy(ContainerInterface $container, Definition $definition, $id, $realInstantiator);
}
Copyright (c) 2004-2013 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection;

use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;

/**
 * Container is a dependency injection container.
 *
 * It gives access to object instances (services).
 *
 * Services and parameters are simple key/pair stores.
 *
 * Parameter and service keys are case insensitive.
 *
 * A service id can contain lowercased letters, digits, underscores, and dots.
 * Underscores are used to separate words, and dots to group services
 * under namespaces:
 *
 * <ul>
 *   <li>request</li>
 *   <li>mysql_session_storage</li>
 *   <li>symfony.mysql_session_storage</li>
 * </ul>
 *
 * A service can also be defined by creating a method named
 * getXXXService(), where XXX is the camelized version of the id:
 *
 * <ul>
 *   <li>request -> getRequestService()</li>
 *   <li>mysql_session_storage -> getMysqlSessionStorageService()</li>
 *   <li>symfony.mysql_session_storage -> getSymfony_MysqlSessionStorageService()</li>
 * </ul>
 *
 * The container can have three possible behaviors when a service does not exist:
 *
 *  * EXCEPTION_ON_INVALID_REFERENCE: Throws an exception (the default)
 *  * NULL_ON_INVALID_REFERENCE:      Returns null
 *  * IGNORE_ON_INVALID_REFERENCE:    Ignores the wrapping command asking for the reference
 *                                    (for instance, ignore a setter if the service does not exist)
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 *
 * @api
 */
class Container implements IntrospectableContainerInterface
{
    /**
     * @var ParameterBagInterface
     */
    protected $parameterBag;

    protected $services;
    protected $methodMap;
    protected $scopes;
    protected $scopeChildren;
    protected $scopedServices;
    protected $scopeStacks;
    protected $loading = array();

    /**
     * Constructor.
     *
     * @param ParameterBagInterface $parameterBag A ParameterBagInterface instance
     *
     * @api
     */
    public function __construct(ParameterBagInterface $parameterBag = null)
    {
        $this->parameterBag = null === $parameterBag ? new ParameterBag() : $parameterBag;

        $this->services       = array();
        $this->scopes         = array();
        $this->scopeChildren  = array();
        $this->scopedServices = array();
        $this->scopeStacks    = array();

        $this->set('service_container', $this);
    }

    /**
     * Compiles the container.
     *
     * This method does two things:
     *
     *  * Parameter values are resolved;
     *  * The parameter bag is frozen.
     *
     * @api
     */
    public function compile()
    {
        $this->parameterBag->resolve();

        $this->parameterBag = new FrozenParameterBag($this->parameterBag->all());
    }

    /**
     * Returns true if the container parameter bag are frozen.
     *
     * @return Boolean true if the container parameter bag are frozen, false otherwise
     *
     * @api
     */
    public function isFrozen()
    {
        return $this->parameterBag instanceof FrozenParameterBag;
    }

    /**
     * Gets the service container parameter bag.
     *
     * @return ParameterBagInterface A ParameterBagInterface instance
     *
     * @api
     */
    public function getParameterBag()
    {
        return $this->parameterBag;
    }

    /**
     * Gets a parameter.
     *
     * @param string $name The parameter name
     *
     * @return mixed  The parameter value
     *
     * @throws InvalidArgumentException if the parameter is not defined
     *
     * @api
     */
    public function getParameter($name)
    {
        return $this->parameterBag->get($name);
    }

    /**
     * Checks if a parameter exists.
     *
     * @param string $name The parameter name
     *
     * @return Boolean The presence of parameter in container
     *
     * @api
     */
    public function hasParameter($name)
    {
        return $this->parameterBag->has($name);
    }

    /**
     * Sets a parameter.
     *
     * @param string $name  The parameter name
     * @param mixed  $value The parameter value
     *
     * @api
     */
    public function setParameter($name, $value)
    {
        $this->parameterBag->set($name, $value);
    }

    /**
     * Sets a service.
     *
     * @param string $id      The service identifier
     * @param object $service The service instance
     * @param string $scope   The scope of the service
     *
     * @throws RuntimeException When trying to set a service in an inactive scope
     * @throws InvalidArgumentException When trying to set a service in the prototype scope
     *
     * @api
     */
    public function set($id, $service, $scope = self::SCOPE_CONTAINER)
    {
        if (self::SCOPE_PROTOTYPE === $scope) {
            throw new InvalidArgumentException(sprintf('You cannot set service "%s" of scope "prototype".', $id));
        }

        $id = strtolower($id);

        if (self::SCOPE_CONTAINER !== $scope) {
            if (!isset($this->scopedServices[$scope])) {
                throw new RuntimeException(sprintf('You cannot set service "%s" of inactive scope.', $id));
            }

            $this->scopedServices[$scope][$id] = $service;
        }

        $this->services[$id] = $service;

        if (method_exists($this, $method = 'synchronize'.strtr($id, array('_' => '', '.' => '_')).'Service')) {
            $this->$method();
        }
    }

    /**
     * Returns true if the given service is defined.
     *
     * @param string $id The service identifier
     *
     * @return Boolean true if the service is defined, false otherwise
     *
     * @api
     */
    public function has($id)
    {
        $id = strtolower($id);

        return array_key_exists($id, $this->services) || method_exists($this, 'get'.strtr($id, array('_' => '', '.' => '_')).'Service');
    }

    /**
     * Gets a service.
     *
     * If a service is defined both through a set() method and
     * with a get{$id}Service() method, the former has always precedence.
     *
     * @param string  $id              The service identifier
     * @param integer $invalidBehavior The behavior when the service does not exist
     *
     * @return object The associated service
     *
     * @throws InvalidArgumentException if the service is not defined
     * @throws ServiceCircularReferenceException When a circular reference is detected
     * @throws ServiceNotFoundException When the service is not defined
     *
     * @see Reference
     *
     * @api
     */
    public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE)
    {
        $id = strtolower($id);

        if (array_key_exists($id, $this->services)) {
            return $this->services[$id];
        }

        if (isset($this->loading[$id])) {
            throw new ServiceCircularReferenceException($id, array_keys($this->loading));
        }

        if (isset($this->methodMap[$id])) {
            $method = $this->methodMap[$id];
        } elseif (method_exists($this, $method = 'get'.strtr($id, array('_' => '', '.' => '_')).'Service')) {
        } else {
            if (self::EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior) {
                if (!$id) {
                    throw new ServiceNotFoundException($id);
                }

                $alternatives = array();
                foreach (array_keys($this->services) as $key) {
                    $lev = levenshtein($id, $key);
                    if ($lev <= strlen($id) / 3 || false !== strpos($key, $id)) {
                        $alternatives[] = $key;
                    }
                }

                throw new ServiceNotFoundException($id, null, null, $alternatives);
            }

            return null;
        }

        $this->loading[$id] = true;

        try {
            $service = $this->$method();
        } catch (\Exception $e) {
            unset($this->loading[$id]);

            if (array_key_exists($id, $this->services)) {
                unset($this->services[$id]);
            }

            if ($e instanceof InactiveScopeException && self::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
                return null;
            }

            throw $e;
        }

        unset($this->loading[$id]);

        return $service;
    }

    /**
     * Returns true if the given service has actually been initialized
     *
     * @param string $id The service identifier
     *
     * @return Boolean true if service has already been initialized, false otherwise
     */
    public function initialized($id)
    {
        return array_key_exists(strtolower($id), $this->services);
    }

    /**
     * Gets all service ids.
     *
     * @return array An array of all defined service ids
     */
    public function getServiceIds()
    {
        $ids = array();
        $r = new \ReflectionClass($this);
        foreach ($r->getMethods() as $method) {
            if (preg_match('/^get(.+)Service$/', $method->name, $match)) {
                $ids[] = self::underscore($match[1]);
            }
        }

        return array_unique(array_merge($ids, array_keys($this->services)));
    }

    /**
     * This is called when you enter a scope
     *
     * @param string $name
     *
     * @throws RuntimeException         When the parent scope is inactive
     * @throws InvalidArgumentException When the scope does not exist
     *
     * @api
     */
    public function enterScope($name)
    {
        if (!isset($this->scopes[$name])) {
            throw new InvalidArgumentException(sprintf('The scope "%s" does not exist.', $name));
        }

        if (self::SCOPE_CONTAINER !== $this->scopes[$name] && !isset($this->scopedServices[$this->scopes[$name]])) {
            throw new RuntimeException(sprintf('The parent scope "%s" must be active when entering this scope.', $this->scopes[$name]));
        }

        // check if a scope of this name is already active, if so we need to
        // remove all services of this scope, and those of any of its child
        // scopes from the global services map
        if (isset($this->scopedServices[$name])) {
            $services = array($this->services, $name => $this->scopedServices[$name]);
            unset($this->scopedServices[$name]);

            foreach ($this->scopeChildren[$name] as $child) {
                if (isset($this->scopedServices[$child])) {
                    $services[$child] = $this->scopedServices[$child];
                    unset($this->scopedServices[$child]);
                }
            }

            // update global map
            $this->services = call_user_func_array('array_diff_key', $services);
            array_shift($services);

            // add stack entry for this scope so we can restore the removed services later
            if (!isset($this->scopeStacks[$name])) {
                $this->scopeStacks[$name] = new \SplStack();
            }
            $this->scopeStacks[$name]->push($services);
        }

        $this->scopedServices[$name] = array();
    }

    /**
     * This is called to leave the current scope, and move back to the parent
     * scope.
     *
     * @param string $name The name of the scope to leave
     *
     * @throws InvalidArgumentException if the scope is not active
     *
     * @api
     */
    public function leaveScope($name)
    {
        if (!isset($this->scopedServices[$name])) {
            throw new InvalidArgumentException(sprintf('The scope "%s" is not active.', $name));
        }

        // remove all services of this scope, or any of its child scopes from
        // the global service map
        $services = array($this->services, $this->scopedServices[$name]);
        unset($this->scopedServices[$name]);
        foreach ($this->scopeChildren[$name] as $child) {
            if (!isset($this->scopedServices[$child])) {
                continue;
            }

            $services[] = $this->scopedServices[$child];
            unset($this->scopedServices[$child]);
        }
        $this->services = call_user_func_array('array_diff_key', $services);

        // check if we need to restore services of a previous scope of this type
        if (isset($this->scopeStacks[$name]) && count($this->scopeStacks[$name]) > 0) {
            $services = $this->scopeStacks[$name]->pop();
            $this->scopedServices += $services;

            foreach ($services as $array) {
                foreach ($array as $id => $service) {
                    $this->set($id, $service, $name);
                }
            }
        }
    }

    /**
     * Adds a scope to the container.
     *
     * @param ScopeInterface $scope
     *
     * @throws InvalidArgumentException
     *
     * @api
     */
    public function addScope(ScopeInterface $scope)
    {
        $name = $scope->getName();
        $parentScope = $scope->getParentName();

        if (self::SCOPE_CONTAINER === $name || self::SCOPE_PROTOTYPE === $name) {
            throw new InvalidArgumentException(sprintf('The scope "%s" is reserved.', $name));
        }
        if (isset($this->scopes[$name])) {
            throw new InvalidArgumentException(sprintf('A scope with name "%s" already exists.', $name));
        }
        if (self::SCOPE_CONTAINER !== $parentScope && !isset($this->scopes[$parentScope])) {
            throw new InvalidArgumentException(sprintf('The parent scope "%s" does not exist, or is invalid.', $parentScope));
        }

        $this->scopes[$name] = $parentScope;
        $this->scopeChildren[$name] = array();

        // normalize the child relations
        while ($parentScope !== self::SCOPE_CONTAINER) {
            $this->scopeChildren[$parentScope][] = $name;
            $parentScope = $this->scopes[$parentScope];
        }
    }

    /**
     * Returns whether this container has a certain scope
     *
     * @param string $name The name of the scope
     *
     * @return Boolean
     *
     * @api
     */
    public function hasScope($name)
    {
        return isset($this->scopes[$name]);
    }

    /**
     * Returns whether this scope is currently active
     *
     * This does not actually check if the passed scope actually exists.
     *
     * @param string $name
     *
     * @return Boolean
     *
     * @api
     */
    public function isScopeActive($name)
    {
        return isset($this->scopedServices[$name]);
    }

    /**
     * Camelizes a string.
     *
     * @param string $id A string to camelize
     *
     * @return string The camelized string
     */
    public static function camelize($id)
    {
        return preg_replace_callback('/(^|_|\.)+(.)/', function ($match) { return ('.' === $match[1] ? '_' : '').strtoupper($match[2]); }, $id);
    }

    /**
     * A string to underscore.
     *
     * @param string $id The string to underscore
     *
     * @return string The underscored string
     */
    public static function underscore($id)
    {
        return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), array('\\1_\\2', '\\1_\\2'), strtr($id, '_', '.')));
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Loader;

use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Yaml\Parser as YamlParser;

/**
 * YamlFileLoader loads YAML files service definitions.
 *
 * The YAML format does not support anonymous services (cf. the XML loader).
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class YamlFileLoader extends FileLoader
{
    private $yamlParser;

    /**
     * Loads a Yaml file.
     *
     * @param mixed  $file The resource
     * @param string $type The resource type
     */
    public function load($file, $type = null)
    {
        $path = $this->locator->locate($file);

        $content = $this->loadFile($path);

        $this->container->addResource(new FileResource($path));

        // empty file
        if (null === $content) {
            return;
        }

        // imports
        $this->parseImports($content, $file);

        // parameters
        if (isset($content['parameters'])) {
            foreach ($content['parameters'] as $key => $value) {
                $this->container->setParameter($key, $this->resolveServices($value));
            }
        }

        // extensions
        $this->loadFromExtensions($content);

        // services
        $this->parseDefinitions($content, $file);
    }

    /**
     * Returns true if this class supports the given resource.
     *
     * @param mixed  $resource A resource
     * @param string $type     The resource type
     *
     * @return Boolean true if this class supports the given resource, false otherwise
     */
    public function supports($resource, $type = null)
    {
        return is_string($resource) && 'yml' === pathinfo($resource, PATHINFO_EXTENSION);
    }

    /**
     * Parses all imports
     *
     * @param array  $content
     * @param string $file
     */
    private function parseImports($content, $file)
    {
        if (!isset($content['imports'])) {
            return;
        }

        foreach ($content['imports'] as $import) {
            $this->setCurrentDir(dirname($file));
            $this->import($import['resource'], null, isset($import['ignore_errors']) ? (Boolean) $import['ignore_errors'] : false, $file);
        }
    }

    /**
     * Parses definitions
     *
     * @param array  $content
     * @param string $file
     */
    private function parseDefinitions($content, $file)
    {
        if (!isset($content['services'])) {
            return;
        }

        foreach ($content['services'] as $id => $service) {
            $this->parseDefinition($id, $service, $file);
        }
    }

    /**
     * Parses a definition.
     *
     * @param string $id
     * @param array  $service
     * @param string $file
     *
     * @throws InvalidArgumentException When tags are invalid
     */
    private function parseDefinition($id, $service, $file)
    {
        if (is_string($service) && 0 === strpos($service, '@')) {
            $this->container->setAlias($id, substr($service, 1));

            return;
        } elseif (isset($service['alias'])) {
            $public = !array_key_exists('public', $service) || (Boolean) $service['public'];
            $this->container->setAlias($id, new Alias($service['alias'], $public));

            return;
        }

        if (isset($service['parent'])) {
            $definition = new DefinitionDecorator($service['parent']);
        } else {
            $definition = new Definition();
        }

        if (isset($service['class'])) {
            $definition->setClass($service['class']);
        }

        if (isset($service['scope'])) {
            $definition->setScope($service['scope']);
        }

        if (isset($service['synthetic'])) {
            $definition->setSynthetic($service['synthetic']);
        }

        if (isset($service['synchronized'])) {
            $definition->setSynchronized($service['synchronized']);
        }

        if (isset($service['lazy'])) {
            $definition->setLazy($service['lazy']);
        }

        if (isset($service['public'])) {
            $definition->setPublic($service['public']);
        }

        if (isset($service['abstract'])) {
            $definition->setAbstract($service['abstract']);
        }

        if (isset($service['factory_class'])) {
            $definition->setFactoryClass($service['factory_class']);
        }

        if (isset($service['factory_method'])) {
            $definition->setFactoryMethod($service['factory_method']);
        }

        if (isset($service['factory_service'])) {
            $definition->setFactoryService($service['factory_service']);
        }

        if (isset($service['file'])) {
            $definition->setFile($service['file']);
        }

        if (isset($service['arguments'])) {
            $definition->setArguments($this->resolveServices($service['arguments']));
        }

        if (isset($service['properties'])) {
            $definition->setProperties($this->resolveServices($service['properties']));
        }

        if (isset($service['configurator'])) {
            if (is_string($service['configurator'])) {
                $definition->setConfigurator($service['configurator']);
            } else {
                $definition->setConfigurator(array($this->resolveServices($service['configurator'][0]), $service['configurator'][1]));
            }
        }

        if (isset($service['calls'])) {
            foreach ($service['calls'] as $call) {
                $args = isset($call[1]) ? $this->resolveServices($call[1]) : array();
                $definition->addMethodCall($call[0], $args);
            }
        }

        if (isset($service['tags'])) {
            if (!is_array($service['tags'])) {
                throw new InvalidArgumentException(sprintf('Parameter "tags" must be an array for service "%s" in %s.', $id, $file));
            }

            foreach ($service['tags'] as $tag) {
                if (!isset($tag['name'])) {
                    throw new InvalidArgumentException(sprintf('A "tags" entry is missing a "name" key for service "%s" in %s.', $id, $file));
                }

                $name = $tag['name'];
                unset($tag['name']);

                foreach ($tag as $attribute => $value) {
                    if (!is_scalar($value)) {
                        throw new InvalidArgumentException(sprintf('A "tags" attribute must be of a scalar-type for service "%s", tag "%s" in %s.', $id, $name, $file));
                    }
                }

                $definition->addTag($name, $tag);
            }
        }

        $this->container->setDefinition($id, $definition);
    }

    /**
     * Loads a YAML file.
     *
     * @param string $file
     *
     * @return array The file content
     */
    protected function loadFile($file)
    {
        if (!stream_is_local($file)) {
            throw new InvalidArgumentException(sprintf('This is not a local file "%s".', $file));
        }

        if (!file_exists($file)) {
            throw new InvalidArgumentException(sprintf('The service file "%s" is not valid.', $file));
        }

        if (null === $this->yamlParser) {
            $this->yamlParser = new YamlParser();
        }

        return $this->validate($this->yamlParser->parse(file_get_contents($file)), $file);
    }

    /**
     * Validates a YAML file.
     *
     * @param mixed  $content
     * @param string $file
     *
     * @return array
     *
     * @throws InvalidArgumentException When service file is not valid
     */
    private function validate($content, $file)
    {
        if (null === $content) {
            return $content;
        }

        if (!is_array($content)) {
            throw new InvalidArgumentException(sprintf('The service file "%s" is not valid.', $file));
        }

        foreach (array_keys($content) as $namespace) {
            if (in_array($namespace, array('imports', 'parameters', 'services'))) {
                continue;
            }

            if (!$this->container->hasExtension($namespace)) {
                $extensionNamespaces = array_filter(array_map(function ($ext) { return $ext->getAlias(); }, $this->container->getExtensions()));
                throw new InvalidArgumentException(sprintf(
                    'There is no extension able to load the configuration for "%s" (in %s). Looked for namespace "%s", found %s',
                    $namespace,
                    $file,
                    $namespace,
                    $extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none'
                ));
            }
        }

        return $content;
    }

    /**
     * Resolves services.
     *
     * @param string $value
     *
     * @return Reference
     */
    private function resolveServices($value)
    {
        if (is_array($value)) {
            $value = array_map(array($this, 'resolveServices'), $value);
        } elseif (is_string($value) &&  0 === strpos($value, '@')) {
            if (0 === strpos($value, '@@')) {
                $value = substr($value, 1);
                $invalidBehavior = null;
            } elseif (0 === strpos($value, '@?')) {
                $value = substr($value, 2);
                $invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
            } else {
                $value = substr($value, 1);
                $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
            }

            if ('=' === substr($value, -1)) {
                $value = substr($value, 0, -1);
                $strict = false;
            } else {
                $strict = true;
            }

            if (null !== $invalidBehavior) {
                $value = new Reference($value, $invalidBehavior, $strict);
            }
        }

        return $value;
    }

    /**
     * Loads from Extensions
     *
     * @param array $content
     */
    private function loadFromExtensions($content)
    {
        foreach ($content as $namespace => $values) {
            if (in_array($namespace, array('imports', 'parameters', 'services'))) {
                continue;
            }

            if (!is_array($values)) {
                $values = array();
            }

            $this->container->loadFromExtension($namespace, $values);
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Loader;

use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Config\Util\XmlUtils;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\SimpleXMLElement;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;

/**
 * XmlFileLoader loads XML files service definitions.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class XmlFileLoader extends FileLoader
{
    /**
     * Loads an XML file.
     *
     * @param mixed  $file The resource
     * @param string $type The resource type
     */
    public function load($file, $type = null)
    {
        $path = $this->locator->locate($file);

        $xml = $this->parseFile($path);
        $xml->registerXPathNamespace('container', 'http://symfony.com/schema/dic/services');

        $this->container->addResource(new FileResource($path));

        // anonymous services
        $this->processAnonymousServices($xml, $path);

        // imports
        $this->parseImports($xml, $path);

        // parameters
        $this->parseParameters($xml, $path);

        // extensions
        $this->loadFromExtensions($xml);

        // services
        $this->parseDefinitions($xml, $path);
    }

    /**
     * Returns true if this class supports the given resource.
     *
     * @param mixed  $resource A resource
     * @param string $type     The resource type
     *
     * @return Boolean true if this class supports the given resource, false otherwise
     */
    public function supports($resource, $type = null)
    {
        return is_string($resource) && 'xml' === pathinfo($resource, PATHINFO_EXTENSION);
    }

    /**
     * Parses parameters
     *
     * @param SimpleXMLElement $xml
     * @param string           $file
     */
    private function parseParameters(SimpleXMLElement $xml, $file)
    {
        if (!$xml->parameters) {
            return;
        }

        $this->container->getParameterBag()->add($xml->parameters->getArgumentsAsPhp('parameter'));
    }

    /**
     * Parses imports
     *
     * @param SimpleXMLElement $xml
     * @param string           $file
     */
    private function parseImports(SimpleXMLElement $xml, $file)
    {
        if (false === $imports = $xml->xpath('//container:imports/container:import')) {
            return;
        }

        foreach ($imports as $import) {
            $this->setCurrentDir(dirname($file));
            $this->import((string) $import['resource'], null, (Boolean) $import->getAttributeAsPhp('ignore-errors'), $file);
        }
    }

    /**
     * Parses multiple definitions
     *
     * @param SimpleXMLElement $xml
     * @param string           $file
     */
    private function parseDefinitions(SimpleXMLElement $xml, $file)
    {
        if (false === $services = $xml->xpath('//container:services/container:service')) {
            return;
        }

        foreach ($services as $service) {
            $this->parseDefinition((string) $service['id'], $service, $file);
        }
    }

    /**
     * Parses an individual Definition
     *
     * @param string           $id
     * @param SimpleXMLElement $service
     * @param string           $file
     */
    private function parseDefinition($id, $service, $file)
    {
        if ((string) $service['alias']) {
            $public = true;
            if (isset($service['public'])) {
                $public = $service->getAttributeAsPhp('public');
            }
            $this->container->setAlias($id, new Alias((string) $service['alias'], $public));

            return;
        }

        if (isset($service['parent'])) {
            $definition = new DefinitionDecorator((string) $service['parent']);
        } else {
            $definition = new Definition();
        }

        foreach (array('class', 'scope', 'public', 'factory-class', 'factory-method', 'factory-service', 'synthetic', 'synchronized', 'lazy', 'abstract') as $key) {
            if (isset($service[$key])) {
                $method = 'set'.str_replace('-', '', $key);
                $definition->$method((string) $service->getAttributeAsPhp($key));
            }
        }

        if ($service->file) {
            $definition->setFile((string) $service->file);
        }

        $definition->setArguments($service->getArgumentsAsPhp('argument'));
        $definition->setProperties($service->getArgumentsAsPhp('property'));

        if (isset($service->configurator)) {
            if (isset($service->configurator['function'])) {
                $definition->setConfigurator((string) $service->configurator['function']);
            } else {
                if (isset($service->configurator['service'])) {
                    $class = new Reference((string) $service->configurator['service'], ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false);
                } else {
                    $class = (string) $service->configurator['class'];
                }

                $definition->setConfigurator(array($class, (string) $service->configurator['method']));
            }
        }

        foreach ($service->call as $call) {
            $definition->addMethodCall((string) $call['method'], $call->getArgumentsAsPhp('argument'));
        }

        foreach ($service->tag as $tag) {
            $parameters = array();
            foreach ($tag->attributes() as $name => $value) {
                if ('name' === $name) {
                    continue;
                }

                $parameters[$name] = SimpleXMLElement::phpize($value);
            }

            $definition->addTag((string) $tag['name'], $parameters);
        }

        $this->container->setDefinition($id, $definition);
    }

    /**
     * Parses a XML file.
     *
     * @param string $file Path to a file
     *
     * @return SimpleXMLElement
     *
     * @throws InvalidArgumentException When loading of XML file returns error
     */
    protected function parseFile($file)
    {
        try {
            $dom = XmlUtils::loadFile($file, array($this, 'validateSchema'));
        } catch (\InvalidArgumentException $e) {
            throw new InvalidArgumentException(sprintf('Unable to parse file "%s".', $file), $e->getCode(), $e);
        }

        $this->validateExtensions($dom, $file);

        return simplexml_import_dom($dom, 'Symfony\\Component\\DependencyInjection\\SimpleXMLElement');
    }

    /**
     * Processes anonymous services
     *
     * @param SimpleXMLElement $xml
     * @param string           $file
     */
    private function processAnonymousServices(SimpleXMLElement $xml, $file)
    {
        $definitions = array();
        $count = 0;

        // anonymous services as arguments/properties
        if (false !== $nodes = $xml->xpath('//container:argument[@type="service"][not(@id)]|//container:property[@type="service"][not(@id)]')) {
            foreach ($nodes as $node) {
                // give it a unique name
                $node['id'] = sprintf('%s_%d', md5($file), ++$count);

                $definitions[(string) $node['id']] = array($node->service, $file, false);
                $node->service['id'] = (string) $node['id'];
            }
        }

        // anonymous services "in the wild"
        if (false !== $nodes = $xml->xpath('//container:services/container:service[not(@id)]')) {
            foreach ($nodes as $node) {
                // give it a unique name
                $node['id'] = sprintf('%s_%d', md5($file), ++$count);

                $definitions[(string) $node['id']] = array($node, $file, true);
                $node->service['id'] = (string) $node['id'];
            }
        }

        // resolve definitions
        krsort($definitions);
        foreach ($definitions as $id => $def) {
            // anonymous services are always private
            $def[0]['public'] = false;

            $this->parseDefinition($id, $def[0], $def[1]);

            $oNode = dom_import_simplexml($def[0]);
            if (true === $def[2]) {
                $nNode = new \DOMElement('_services');
                $oNode->parentNode->replaceChild($nNode, $oNode);
                $nNode->setAttribute('id', $id);
            } else {
                $oNode->parentNode->removeChild($oNode);
            }
        }
    }

    /**
     * Validates a documents XML schema.
     *
     * @param \DOMDocument $dom
     *
     * @return Boolean
     *
     * @throws RuntimeException When extension references a non-existent XSD file
     */
    public function validateSchema(\DOMDocument $dom)
    {
        $schemaLocations = array('http://symfony.com/schema/dic/services' => str_replace('\\', '/', __DIR__.'/schema/dic/services/services-1.0.xsd'));

        if ($element = $dom->documentElement->getAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'schemaLocation')) {
            $items = preg_split('/\s+/', $element);
            for ($i = 0, $nb = count($items); $i < $nb; $i += 2) {
                if (!$this->container->hasExtension($items[$i])) {
                    continue;
                }

                if (($extension = $this->container->getExtension($items[$i])) && false !== $extension->getXsdValidationBasePath()) {
                    $path = str_replace($extension->getNamespace(), str_replace('\\', '/', $extension->getXsdValidationBasePath()).'/', $items[$i + 1]);

                    if (!is_file($path)) {
                        throw new RuntimeException(sprintf('Extension "%s" references a non-existent XSD file "%s"', get_class($extension), $path));
                    }

                    $schemaLocations[$items[$i]] = $path;
                }
            }
        }

        $tmpfiles = array();
        $imports = '';
        foreach ($schemaLocations as $namespace => $location) {
            $parts = explode('/', $location);
            if (0 === stripos($location, 'phar://')) {
                $tmpfile = tempnam(sys_get_temp_dir(), 'sf2');
                if ($tmpfile) {
                    copy($location, $tmpfile);
                    $tmpfiles[] = $tmpfile;
                    $parts = explode('/', str_replace('\\', '/', $tmpfile));
                }
            }
            $drive = '\\' === DIRECTORY_SEPARATOR ? array_shift($parts).'/' : '';
            $location = 'file:///'.$drive.implode('/', array_map('rawurlencode', $parts));

            $imports .= sprintf('  <xsd:import namespace="%s" schemaLocation="%s" />'."\n", $namespace, $location);
        }

        $source = <<<EOF
<?xml version="1.0" encoding="utf-8" ?>
<xsd:schema xmlns="http://symfony.com/schema"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://symfony.com/schema"
    elementFormDefault="qualified">

    <xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
$imports
</xsd:schema>
EOF
        ;

        $valid = @$dom->schemaValidateSource($source);

        foreach ($tmpfiles as $tmpfile) {
            @unlink($tmpfile);
        }

        return $valid;
    }

    /**
     * Validates an extension.
     *
     * @param \DOMDocument $dom
     * @param string       $file
     *
     * @throws InvalidArgumentException When no extension is found corresponding to a tag
     */
    private function validateExtensions(\DOMDocument $dom, $file)
    {
        foreach ($dom->documentElement->childNodes as $node) {
            if (!$node instanceof \DOMElement || 'http://symfony.com/schema/dic/services' === $node->namespaceURI) {
                continue;
            }

            // can it be handled by an extension?
            if (!$this->container->hasExtension($node->namespaceURI)) {
                $extensionNamespaces = array_filter(array_map(function ($ext) { return $ext->getNamespace(); }, $this->container->getExtensions()));
                throw new InvalidArgumentException(sprintf(
                    'There is no extension able to load the configuration for "%s" (in %s). Looked for namespace "%s", found %s',
                    $node->tagName,
                    $file,
                    $node->namespaceURI,
                    $extensionNamespaces ? sprintf('"%s"', implode('", "', $extensionNamespaces)) : 'none'
                ));
            }
        }
    }

    /**
     * Loads from an extension.
     *
     * @param SimpleXMLElement $xml
     */
    private function loadFromExtensions(SimpleXMLElement $xml)
    {
        foreach (dom_import_simplexml($xml)->childNodes as $node) {
            if (!$node instanceof \DOMElement || $node->namespaceURI === 'http://symfony.com/schema/dic/services') {
                continue;
            }

            $values = static::convertDomElementToArray($node);
            if (!is_array($values)) {
                $values = array();
            }

            $this->container->loadFromExtension($node->namespaceURI, $values);
        }
    }

    /**
     * Converts a \DomElement object to a PHP array.
     *
     * The following rules applies during the conversion:
     *
     *  * Each tag is converted to a key value or an array
     *    if there is more than one "value"
     *
     *  * The content of a tag is set under a "value" key (<foo>bar</foo>)
     *    if the tag also has some nested tags
     *
     *  * The attributes are converted to keys (<foo foo="bar"/>)
     *
     *  * The nested-tags are converted to keys (<foo><foo>bar</foo></foo>)
     *
     * @param \DomElement $element A \DomElement instance
     *
     * @return array A PHP array
     */
    public static function convertDomElementToArray(\DomElement $element)
    {
        return XmlUtils::convertDomElementToArray($element);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Loader;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\Loader\FileLoader as BaseFileLoader;
use Symfony\Component\Config\FileLocatorInterface;

/**
 * FileLoader is the abstract class used by all built-in loaders that are file based.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
abstract class FileLoader extends BaseFileLoader
{
    protected $container;

    /**
     * Constructor.
     *
     * @param ContainerBuilder $container A ContainerBuilder instance
     * @param FileLocatorInterface      $locator   A FileLocator instance
     */
    public function __construct(ContainerBuilder $container, FileLocatorInterface $locator)
    {
        $this->container = $container;

        parent::__construct($locator);
    }
}
<?xml version="1.0" encoding="UTF-8" ?>

<xsd:schema xmlns="http://symfony.com/schema/dic/services"
     xmlns:xsd="http://www.w3.org/2001/XMLSchema"
     targetNamespace="http://symfony.com/schema/dic/services"
     elementFormDefault="qualified">

  <xsd:annotation>
    <xsd:documentation><![CDATA[
      Symfony XML Services Schema, version 1.0
      Authors: Fabien Potencier

      This defines a way to describe PHP objects (services) and their
      dependencies.
    ]]></xsd:documentation>
  </xsd:annotation>

  <xsd:element name="container" type="container" />

  <xsd:complexType name="container">
    <xsd:annotation>
      <xsd:documentation><![CDATA[
        The root element of a service file.
      ]]></xsd:documentation>
    </xsd:annotation>
    <xsd:sequence>
      <xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
      <xsd:element name="imports" type="imports" minOccurs="0" maxOccurs="1" />
      <xsd:element name="parameters" type="parameters" minOccurs="0" maxOccurs="1" />
      <xsd:element name="services" type="services" minOccurs="0" maxOccurs="1" />
      <xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
    </xsd:sequence>
  </xsd:complexType>

  <xsd:complexType name="services">
    <xsd:annotation>
      <xsd:documentation><![CDATA[
        Enclosing element for the definition of all services
      ]]></xsd:documentation>
    </xsd:annotation>
    <xsd:choice minOccurs="1" maxOccurs="unbounded">
      <xsd:element name="service" type="service" />
    </xsd:choice>
  </xsd:complexType>

  <xsd:complexType name="imports">
    <xsd:annotation>
      <xsd:documentation><![CDATA[
        Enclosing element for the import elements
      ]]></xsd:documentation>
    </xsd:annotation>
    <xsd:choice minOccurs="1" maxOccurs="unbounded">
      <xsd:element name="import" type="import" />
    </xsd:choice>
  </xsd:complexType>

  <xsd:complexType name="import">
    <xsd:annotation>
      <xsd:documentation><![CDATA[
        Import an external resource defining other services or parameters
      ]]></xsd:documentation>
    </xsd:annotation>
    <xsd:attribute name="resource" type="xsd:string" use="required" />
    <xsd:attribute name="ignore-errors" type="boolean" />
  </xsd:complexType>

  <xsd:complexType name="configurator">
    <xsd:attribute name="id" type="xsd:string" />
    <xsd:attribute name="service" type="xsd:string" />
    <xsd:attribute name="class" type="xsd:string" />
    <xsd:attribute name="method" type="xsd:string" />
    <xsd:attribute name="function" type="xsd:string" />
  </xsd:complexType>

  <xsd:complexType name="service">
    <xsd:choice maxOccurs="unbounded">
      <xsd:element name="file" type="xsd:string" minOccurs="0" maxOccurs="1" />
      <xsd:element name="argument" type="argument" minOccurs="0" maxOccurs="unbounded" />
      <xsd:element name="configurator" type="configurator" minOccurs="0" maxOccurs="1" />
      <xsd:element name="call" type="call" minOccurs="0" maxOccurs="unbounded" />
      <xsd:element name="tag" type="tag" minOccurs="0" maxOccurs="unbounded" />
      <xsd:element name="property" type="property" minOccurs="0" maxOccurs="unbounded" />
    </xsd:choice>
    <xsd:attribute name="id" type="xsd:string" />
    <xsd:attribute name="class" type="xsd:string" />
    <xsd:attribute name="scope" type="xsd:string" />
    <xsd:attribute name="public" type="boolean" />
    <xsd:attribute name="synthetic" type="boolean" />
    <xsd:attribute name="synchronized" type="boolean" />
    <xsd:attribute name="lazy" type="boolean" />
    <xsd:attribute name="abstract" type="boolean" />
    <xsd:attribute name="factory-class" type="xsd:string" />
    <xsd:attribute name="factory-method" type="xsd:string" />
    <xsd:attribute name="factory-service" type="xsd:string" />
    <xsd:attribute name="alias" type="xsd:string" />
    <xsd:attribute name="parent" type="xsd:string" />
  </xsd:complexType>

  <xsd:complexType name="tag">
    <xsd:attribute name="name" type="xsd:string" />
    <xsd:anyAttribute namespace="##any" processContents="lax" />
  </xsd:complexType>

  <xsd:complexType name="parameters">
    <xsd:choice minOccurs="1" maxOccurs="unbounded">
      <xsd:element name="parameter" type="parameter" />
    </xsd:choice>
    <xsd:attribute name="type" type="parameter_type" />
    <xsd:attribute name="key" type="xsd:string" />
  </xsd:complexType>

  <xsd:complexType name="parameter" mixed="true">
    <xsd:choice minOccurs="0" maxOccurs="unbounded">
      <xsd:element name="parameter" type="parameter" />
    </xsd:choice>
    <xsd:attribute name="type" type="parameter_type" />
    <xsd:attribute name="id" type="xsd:string" />
    <xsd:attribute name="key" type="xsd:string" />
    <xsd:attribute name="on-invalid" type="invalid_sequence" />
  </xsd:complexType>

  <xsd:complexType name="property" mixed="true">
    <xsd:choice minOccurs="0" maxOccurs="1">
      <xsd:element name="service" type="service" />
    </xsd:choice>
    <xsd:attribute name="type" type="argument_type" />
    <xsd:attribute name="id" type="xsd:string" />
    <xsd:attribute name="name" type="xsd:string" />
    <xsd:attribute name="on-invalid" type="xsd:string" />
    <xsd:attribute name="strict" type="boolean" />
  </xsd:complexType>

  <xsd:complexType name="argument" mixed="true">
    <xsd:choice maxOccurs="unbounded">
      <xsd:element name="argument" type="argument" minOccurs="0" maxOccurs="unbounded" />
      <xsd:element name="service" type="service" />
    </xsd:choice>
    <xsd:attribute name="type" type="argument_type" />
    <xsd:attribute name="id" type="xsd:string" />
    <xsd:attribute name="key" type="xsd:string" />
    <xsd:attribute name="index" type="xsd:integer" />
    <xsd:attribute name="on-invalid" type="xsd:string" />
    <xsd:attribute name="strict" type="boolean" />
  </xsd:complexType>

  <xsd:complexType name="call" mixed="true">
    <xsd:choice maxOccurs="unbounded">
      <xsd:element name="argument" type="argument" minOccurs="0" maxOccurs="unbounded" />
      <xsd:element name="service" type="service" />
    </xsd:choice>
    <xsd:attribute name="method" type="xsd:string" />
  </xsd:complexType>

  <xsd:simpleType name="parameter_type">
    <xsd:restriction base="xsd:string">
      <xsd:enumeration value="collection" />
      <xsd:enumeration value="service" />
      <xsd:enumeration value="string" />
      <xsd:enumeration value="constant" />
    </xsd:restriction>
  </xsd:simpleType>

  <xsd:simpleType name="argument_type">
    <xsd:restriction base="xsd:string">
      <xsd:enumeration value="collection" />
      <xsd:enumeration value="service" />
      <xsd:enumeration value="string" />
      <xsd:enumeration value="constant" />
    </xsd:restriction>
  </xsd:simpleType>

  <xsd:simpleType name="invalid_sequence">
    <xsd:restriction base="xsd:string">
      <xsd:enumeration value="null" />
      <xsd:enumeration value="ignore" />
      <xsd:enumeration value="exception" />
    </xsd:restriction>
  </xsd:simpleType>

  <xsd:simpleType name="boolean">
    <xsd:restriction base="xsd:string">
      <xsd:pattern value="(%.+%|true|false)" />
    </xsd:restriction>
  </xsd:simpleType>
</xsd:schema>
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Loader;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\Loader\Loader;

/**
 * ClosureLoader loads service definitions from a PHP closure.
 *
 * The Closure has access to the container as its first argument.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ClosureLoader extends Loader
{
    private $container;

    /**
     * Constructor.
     *
     * @param ContainerBuilder $container A ContainerBuilder instance
     */
    public function __construct(ContainerBuilder $container)
    {
        $this->container = $container;
    }

    /**
     * Loads a Closure.
     *
     * @param \Closure $closure The resource
     * @param string   $type    The resource type
     */
    public function load($closure, $type = null)
    {
        call_user_func($closure, $this->container);
    }

    /**
     * Returns true if this class supports the given resource.
     *
     * @param mixed  $resource A resource
     * @param string $type     The resource type
     *
     * @return Boolean true if this class supports the given resource, false otherwise
     */
    public function supports($resource, $type = null)
    {
        return $resource instanceof \Closure;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Loader;

use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;

/**
 * IniFileLoader loads parameters from INI files.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class IniFileLoader extends FileLoader
{
    /**
     * Loads a resource.
     *
     * @param mixed  $file The resource
     * @param string $type The resource type
     *
     * @throws InvalidArgumentException When ini file is not valid
     */
    public function load($file, $type = null)
    {
        $path = $this->locator->locate($file);

        $this->container->addResource(new FileResource($path));

        $result = parse_ini_file($path, true);
        if (false === $result || array() === $result) {
            throw new InvalidArgumentException(sprintf('The "%s" file is not valid.', $file));
        }

        if (isset($result['parameters']) && is_array($result['parameters'])) {
            foreach ($result['parameters'] as $key => $value) {
                $this->container->setParameter($key, $value);
            }
        }
    }

    /**
     * Returns true if this class supports the given resource.
     *
     * @param mixed  $resource A resource
     * @param string $type     The resource type
     *
     * @return Boolean true if this class supports the given resource, false otherwise
     */
    public function supports($resource, $type = null)
    {
        return is_string($resource) && 'ini' === pathinfo($resource, PATHINFO_EXTENSION);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Loader;

use Symfony\Component\Config\Resource\FileResource;

/**
 * PhpFileLoader loads service definitions from a PHP file.
 *
 * The PHP file is required and the $container variable can be
 * used form the file to change the container.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class PhpFileLoader extends FileLoader
{
    /**
     * Loads a PHP file.
     *
     * @param mixed  $file The resource
     * @param string $type The resource type
     */
    public function load($file, $type = null)
    {
        // the container and loader variables are exposed to the included file below
        $container = $this->container;
        $loader = $this;

        $path = $this->locator->locate($file);
        $this->setCurrentDir(dirname($path));
        $this->container->addResource(new FileResource($path));

        include $path;
    }

    /**
     * Returns true if this class supports the given resource.
     *
     * @param mixed  $resource A resource
     * @param string $type     The resource type
     *
     * @return Boolean true if this class supports the given resource, false otherwise
     */
    public function supports($resource, $type = null)
    {
        return is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection;

use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\OutOfBoundsException;

/**
 * Definition represents a service definition.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @api
 */
class Definition
{
    private $class;
    private $file;
    private $factoryClass;
    private $factoryMethod;
    private $factoryService;
    private $scope;
    private $properties;
    private $calls;
    private $configurator;
    private $tags;
    private $public;
    private $synthetic;
    private $abstract;
    private $synchronized;
    private $lazy;

    protected $arguments;

    /**
     * Constructor.
     *
     * @param string $class     The service class
     * @param array  $arguments An array of arguments to pass to the service constructor
     *
     * @api
     */
    public function __construct($class = null, array $arguments = array())
    {
        $this->class = $class;
        $this->arguments = $arguments;
        $this->calls = array();
        $this->scope = ContainerInterface::SCOPE_CONTAINER;
        $this->tags = array();
        $this->public = true;
        $this->synthetic = false;
        $this->synchronized = false;
        $this->lazy = false;
        $this->abstract = false;
        $this->properties = array();
    }

    /**
     * Sets the name of the class that acts as a factory using the factory method,
     * which will be invoked statically.
     *
     * @param string $factoryClass The factory class name
     *
     * @return Definition The current instance
     *
     * @api
     */
    public function setFactoryClass($factoryClass)
    {
        $this->factoryClass = $factoryClass;

        return $this;
    }

    /**
     * Gets the factory class.
     *
     * @return string The factory class name
     *
     * @api
     */
    public function getFactoryClass()
    {
        return $this->factoryClass;
    }

    /**
     * Sets the factory method able to create an instance of this class.
     *
     * @param string $factoryMethod The factory method name
     *
     * @return Definition The current instance
     *
     * @api
     */
    public function setFactoryMethod($factoryMethod)
    {
        $this->factoryMethod = $factoryMethod;

        return $this;
    }

    /**
     * Gets the factory method.
     *
     * @return string The factory method name
     *
     * @api
     */
    public function getFactoryMethod()
    {
        return $this->factoryMethod;
    }

    /**
     * Sets the name of the service that acts as a factory using the factory method.
     *
     * @param string $factoryService The factory service id
     *
     * @return Definition The current instance
     *
     * @api
     */
    public function setFactoryService($factoryService)
    {
        $this->factoryService = $factoryService;

        return $this;
    }

    /**
     * Gets the factory service id.
     *
     * @return string The factory service id
     *
     * @api
     */
    public function getFactoryService()
    {
        return $this->factoryService;
    }

    /**
     * Sets the service class.
     *
     * @param string $class The service class
     *
     * @return Definition The current instance
     *
     * @api
     */
    public function setClass($class)
    {
        $this->class = $class;

        return $this;
    }

    /**
     * Gets the service class.
     *
     * @return string The service class
     *
     * @api
     */
    public function getClass()
    {
        return $this->class;
    }

    /**
     * Sets the arguments to pass to the service constructor/factory method.
     *
     * @param array $arguments An array of arguments
     *
     * @return Definition The current instance
     *
     * @api
     */
    public function setArguments(array $arguments)
    {
        $this->arguments = $arguments;

        return $this;
    }

    /**
     * @api
     */
    public function setProperties(array $properties)
    {
        $this->properties = $properties;

        return $this;
    }

    /**
     * @api
     */
    public function getProperties()
    {
        return $this->properties;
    }

    /**
     * @api
     */
    public function setProperty($name, $value)
    {
        $this->properties[$name] = $value;

        return $this;
    }

    /**
     * Adds an argument to pass to the service constructor/factory method.
     *
     * @param mixed $argument An argument
     *
     * @return Definition The current instance
     *
     * @api
     */
    public function addArgument($argument)
    {
        $this->arguments[] = $argument;

        return $this;
    }

    /**
     * Sets a specific argument
     *
     * @param integer $index
     * @param mixed   $argument
     *
     * @return Definition The current instance
     *
     * @throws OutOfBoundsException When the replaced argument does not exist
     *
     * @api
     */
    public function replaceArgument($index, $argument)
    {
        if ($index < 0 || $index > count($this->arguments) - 1) {
            throw new OutOfBoundsException(sprintf('The index "%d" is not in the range [0, %d].', $index, count($this->arguments) - 1));
        }

        $this->arguments[$index] = $argument;

        return $this;
    }

    /**
     * Gets the arguments to pass to the service constructor/factory method.
     *
     * @return array The array of arguments
     *
     * @api
     */
    public function getArguments()
    {
        return $this->arguments;
    }

    /**
     * Gets an argument to pass to the service constructor/factory method.
     *
     * @param integer $index
     *
     * @return mixed The argument value
     *
     * @throws OutOfBoundsException When the argument does not exist
     *
     * @api
     */
    public function getArgument($index)
    {
        if ($index < 0 || $index > count($this->arguments) - 1) {
            throw new OutOfBoundsException(sprintf('The index "%d" is not in the range [0, %d].', $index, count($this->arguments) - 1));
        }

        return $this->arguments[$index];
    }

    /**
     * Sets the methods to call after service initialization.
     *
     * @param array $calls An array of method calls
     *
     * @return Definition The current instance
     *
     * @api
     */
    public function setMethodCalls(array $calls = array())
    {
        $this->calls = array();
        foreach ($calls as $call) {
            $this->addMethodCall($call[0], $call[1]);
        }

        return $this;
    }

    /**
     * Adds a method to call after service initialization.
     *
     * @param string $method    The method name to call
     * @param array  $arguments An array of arguments to pass to the method call
     *
     * @return Definition The current instance
     *
     * @throws InvalidArgumentException on empty $method param
     *
     * @api
     */
    public function addMethodCall($method, array $arguments = array())
    {
        if (empty($method)) {
            throw new InvalidArgumentException(sprintf('Method name cannot be empty.'));
        }
        $this->calls[] = array($method, $arguments);

        return $this;
    }

    /**
     * Removes a method to call after service initialization.
     *
     * @param string $method The method name to remove
     *
     * @return Definition The current instance
     *
     * @api
     */
    public function removeMethodCall($method)
    {
        foreach ($this->calls as $i => $call) {
            if ($call[0] === $method) {
                unset($this->calls[$i]);
                break;
            }
        }

        return $this;
    }

    /**
     * Check if the current definition has a given method to call after service initialization.
     *
     * @param string $method The method name to search for
     *
     * @return Boolean
     *
     * @api
     */
    public function hasMethodCall($method)
    {
        foreach ($this->calls as $call) {
            if ($call[0] === $method) {
                return true;
            }
        }

        return false;
    }

    /**
     * Gets the methods to call after service initialization.
     *
     * @return array An array of method calls
     *
     * @api
     */
    public function getMethodCalls()
    {
        return $this->calls;
    }

    /**
     * Sets tags for this definition
     *
     * @param array $tags
     *
     * @return Definition the current instance
     *
     * @api
     */
    public function setTags(array $tags)
    {
        $this->tags = $tags;

        return $this;
    }

    /**
     * Returns all tags.
     *
     * @return array An array of tags
     *
     * @api
     */
    public function getTags()
    {
        return $this->tags;
    }

    /**
     * Gets a tag by name.
     *
     * @param string $name The tag name
     *
     * @return array An array of attributes
     *
     * @api
     */
    public function getTag($name)
    {
        return isset($this->tags[$name]) ? $this->tags[$name] : array();
    }

    /**
     * Adds a tag for this definition.
     *
     * @param string $name       The tag name
     * @param array  $attributes An array of attributes
     *
     * @return Definition The current instance
     *
     * @api
     */
    public function addTag($name, array $attributes = array())
    {
        $this->tags[$name][] = $attributes;

        return $this;
    }

    /**
     * Whether this definition has a tag with the given name
     *
     * @param string $name
     *
     * @return Boolean
     *
     * @api
     */
    public function hasTag($name)
    {
        return isset($this->tags[$name]);
    }

    /**
     * Clears all tags for a given name.
     *
     * @param string $name The tag name
     *
     * @return Definition
     */
    public function clearTag($name)
    {
        if (isset($this->tags[$name])) {
            unset($this->tags[$name]);
        }

        return $this;
    }

    /**
     * Clears the tags for this definition.
     *
     * @return Definition The current instance
     *
     * @api
     */
    public function clearTags()
    {
        $this->tags = array();

        return $this;
    }

    /**
     * Sets a file to require before creating the service.
     *
     * @param string $file A full pathname to include
     *
     * @return Definition The current instance
     *
     * @api
     */
    public function setFile($file)
    {
        $this->file = $file;

        return $this;
    }

    /**
     * Gets the file to require before creating the service.
     *
     * @return string The full pathname to include
     *
     * @api
     */
    public function getFile()
    {
        return $this->file;
    }

    /**
     * Sets the scope of the service
     *
     * @param string $scope Whether the service must be shared or not
     *
     * @return Definition The current instance
     *
     * @api
     */
    public function setScope($scope)
    {
        $this->scope = $scope;

        return $this;
    }

    /**
     * Returns the scope of the service
     *
     * @return string
     *
     * @api
     */
    public function getScope()
    {
        return $this->scope;
    }

    /**
     * Sets the visibility of this service.
     *
     * @param Boolean $boolean
     *
     * @return Definition The current instance
     *
     * @api
     */
    public function setPublic($boolean)
    {
        $this->public = (Boolean) $boolean;

        return $this;
    }

    /**
     * Whether this service is public facing
     *
     * @return Boolean
     *
     * @api
     */
    public function isPublic()
    {
        return $this->public;
    }

    /**
     * Sets the synchronized flag of this service.
     *
     * @param Boolean $boolean
     *
     * @return Definition The current instance
     *
     * @api
     */
    public function setSynchronized($boolean)
    {
        $this->synchronized = (Boolean) $boolean;

        return $this;
    }

    /**
     * Whether this service is synchronized.
     *
     * @return Boolean
     *
     * @api
     */
    public function isSynchronized()
    {
        return $this->synchronized;
    }

    /**
     * Sets the lazy flag of this service.
     *
     * @param Boolean $lazy
     *
     * @return Definition The current instance
     */
    public function setLazy($lazy)
    {
        $this->lazy = (Boolean) $lazy;

        return $this;
    }

    /**
     * Whether this service is lazy.
     *
     * @return Boolean
     */
    public function isLazy()
    {
        return $this->lazy;
    }

    /**
     * Sets whether this definition is synthetic, that is not constructed by the
     * container, but dynamically injected.
     *
     * @param Boolean $boolean
     *
     * @return Definition the current instance
     *
     * @api
     */
    public function setSynthetic($boolean)
    {
        $this->synthetic = (Boolean) $boolean;

        return $this;
    }

    /**
     * Whether this definition is synthetic, that is not constructed by the
     * container, but dynamically injected.
     *
     * @return Boolean
     *
     * @api
     */
    public function isSynthetic()
    {
        return $this->synthetic;
    }

    /**
     * Whether this definition is abstract, that means it merely serves as a
     * template for other definitions.
     *
     * @param Boolean $boolean
     *
     * @return Definition the current instance
     *
     * @api
     */
    public function setAbstract($boolean)
    {
        $this->abstract = (Boolean) $boolean;

        return $this;
    }

    /**
     * Whether this definition is abstract, that means it merely serves as a
     * template for other definitions.
     *
     * @return Boolean
     *
     * @api
     */
    public function isAbstract()
    {
        return $this->abstract;
    }

    /**
     * Sets a configurator to call after the service is fully initialized.
     *
     * @param callable $callable A PHP callable
     *
     * @return Definition The current instance
     *
     * @api
     */
    public function setConfigurator($callable)
    {
        $this->configurator = $callable;

        return $this;
    }

    /**
     * Gets the configurator to call after the service is fully initialized.
     *
     * @return callable The PHP callable to call
     *
     * @api
     */
    public function getConfigurator()
    {
        return $this->configurator;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection;

/**
 * Represents a variable.
 *
 *     $var = new Variable('a');
 *
 * will be dumped as
 *
 *     $a
 *
 * by the PHP dumper.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class Variable
{
    private $name;

    /**
     * Constructor
     *
     * @param string $name
     */
    public function __construct($name)
    {
        $this->name = $name;
    }

    /**
     * Converts the object to a string
     *
     * @return string
     */
    public function __toString()
    {
        return $this->name;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection;

/**
 * IntrospectableContainerInterface defines additional introspection functionality
 * for containers, allowing logic to be implemented based on a Container's state.
 *
 * @author Evan Villemez <evillemez@gmail.com>
 *
 */
interface IntrospectableContainerInterface extends ContainerInterface
{
    /**
     * Check for whether or not a service has been initialized.
     *
     * @param string $id
     *
     * @return Boolean true if the service has been initialized, false otherwise
     *
     */
    public function initialized($id);

}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\ParameterBag;

use Symfony\Component\DependencyInjection\Exception\LogicException;

/**
 * Holds read-only parameters.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @api
 */
class FrozenParameterBag extends ParameterBag
{
    /**
     * Constructor.
     *
     * For performance reasons, the constructor assumes that
     * all keys are already lowercased.
     *
     * This is always the case when used internally.
     *
     * @param array $parameters An array of parameters
     *
     * @api
     */
    public function __construct(array $parameters = array())
    {
        $this->parameters = $parameters;
        $this->resolved = true;
    }

    /**
     * {@inheritDoc}
     *
     * @api
     */
    public function clear()
    {
        throw new LogicException('Impossible to call clear() on a frozen ParameterBag.');
    }

    /**
     * {@inheritDoc}
     *
     * @api
     */
    public function add(array $parameters)
    {
        throw new LogicException('Impossible to call add() on a frozen ParameterBag.');
    }

    /**
     * {@inheritDoc}
     *
     * @api
     */
    public function set($name, $value)
    {
        throw new LogicException('Impossible to call set() on a frozen ParameterBag.');
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\ParameterBag;

use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
use Symfony\Component\DependencyInjection\Exception\ParameterCircularReferenceException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;

/**
 * Holds parameters.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @api
 */
class ParameterBag implements ParameterBagInterface
{
    protected $parameters;
    protected $resolved;

    /**
     * Constructor.
     *
     * @param array $parameters An array of parameters
     *
     * @api
     */
    public function __construct(array $parameters = array())
    {
        $this->parameters = array();
        $this->add($parameters);
        $this->resolved = false;
    }

    /**
     * Clears all parameters.
     *
     * @api
     */
    public function clear()
    {
        $this->parameters = array();
    }

    /**
     * Adds parameters to the service container parameters.
     *
     * @param array $parameters An array of parameters
     *
     * @api
     */
    public function add(array $parameters)
    {
        foreach ($parameters as $key => $value) {
            $this->parameters[strtolower($key)] = $value;
        }
    }

    /**
     * Gets the service container parameters.
     *
     * @return array An array of parameters
     *
     * @api
     */
    public function all()
    {
        return $this->parameters;
    }

    /**
     * Gets a service container parameter.
     *
     * @param string $name The parameter name
     *
     * @return mixed  The parameter value
     *
     * @throws ParameterNotFoundException if the parameter is not defined
     *
     * @api
     */
    public function get($name)
    {
        $name = strtolower($name);

        if (!array_key_exists($name, $this->parameters)) {
            if (!$name) {
                throw new ParameterNotFoundException($name);
            }

            $alternatives = array();
            foreach (array_keys($this->parameters) as $key) {
                $lev = levenshtein($name, $key);
                if ($lev <= strlen($name) / 3 || false !== strpos($key, $name)) {
                    $alternatives[] = $key;
                }
            }

            throw new ParameterNotFoundException($name, null, null, null, $alternatives);
        }

        return $this->parameters[$name];
    }

    /**
     * Sets a service container parameter.
     *
     * @param string $name  The parameter name
     * @param mixed  $value The parameter value
     *
     * @api
     */
    public function set($name, $value)
    {
        $this->parameters[strtolower($name)] = $value;
    }

    /**
     * Returns true if a parameter name is defined.
     *
     * @param string $name The parameter name
     *
     * @return Boolean true if the parameter name is defined, false otherwise
     *
     * @api
     */
    public function has($name)
    {
        return array_key_exists(strtolower($name), $this->parameters);
    }

    /**
     * Removes a parameter.
     *
     * @param string $name The parameter name
     *
     * @api
     */
    public function remove($name)
    {
        unset($this->parameters[strtolower($name)]);
    }

    /**
     * Replaces parameter placeholders (%name%) by their values for all parameters.
     */
    public function resolve()
    {
        if ($this->resolved) {
            return;
        }

        $parameters = array();
        foreach ($this->parameters as $key => $value) {
            try {
                $value = $this->resolveValue($value);
                $parameters[$key] = $this->unescapeValue($value);
            } catch (ParameterNotFoundException $e) {
                $e->setSourceKey($key);

                throw $e;
            }
        }

        $this->parameters = $parameters;
        $this->resolved = true;
    }

    /**
     * Replaces parameter placeholders (%name%) by their values.
     *
     * @param mixed $value     A value
     * @param array $resolving An array of keys that are being resolved (used internally to detect circular references)
     *
     * @return mixed The resolved value
     *
     * @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
     * @throws ParameterCircularReferenceException if a circular reference if detected
     * @throws RuntimeException when a given parameter has a type problem.
     */
    public function resolveValue($value, array $resolving = array())
    {
        if (is_array($value)) {
            $args = array();
            foreach ($value as $k => $v) {
                $args[$this->resolveValue($k, $resolving)] = $this->resolveValue($v, $resolving);
            }

            return $args;
        }

        if (!is_string($value)) {
            return $value;
        }

        return $this->resolveString($value, $resolving);
    }

    /**
     * Resolves parameters inside a string
     *
     * @param string $value     The string to resolve
     * @param array  $resolving An array of keys that are being resolved (used internally to detect circular references)
     *
     * @return string The resolved string
     *
     * @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
     * @throws ParameterCircularReferenceException if a circular reference if detected
     * @throws RuntimeException when a given parameter has a type problem.
     */
    public function resolveString($value, array $resolving = array())
    {
        // we do this to deal with non string values (Boolean, integer, ...)
        // as the preg_replace_callback throw an exception when trying
        // a non-string in a parameter value
        if (preg_match('/^%([^%\s]+)%$/', $value, $match)) {
            $key = strtolower($match[1]);

            if (isset($resolving[$key])) {
                throw new ParameterCircularReferenceException(array_keys($resolving));
            }

            $resolving[$key] = true;

            return $this->resolved ? $this->get($key) : $this->resolveValue($this->get($key), $resolving);
        }

        $self = $this;

        return preg_replace_callback('/%%|%([^%\s]+)%/', function ($match) use ($self, $resolving, $value) {
            // skip %%
            if (!isset($match[1])) {
                return '%%';
            }

            $key = strtolower($match[1]);
            if (isset($resolving[$key])) {
                throw new ParameterCircularReferenceException(array_keys($resolving));
            }

            $resolved = $self->get($key);

            if (!is_string($resolved) && !is_numeric($resolved)) {
                throw new RuntimeException(sprintf('A string value must be composed of strings and/or numbers, but found parameter "%s" of type %s inside string value "%s".', $key, gettype($resolved), $value));
            }

            $resolved = (string) $resolved;
            $resolving[$key] = true;

            return $self->isResolved() ? $resolved : $self->resolveString($resolved, $resolving);
        }, $value);
    }

    public function isResolved()
    {
        return $this->resolved;
    }

    /**
     * {@inheritDoc}
     */
    public function escapeValue($value)
    {
        if (is_string($value)) {
            return str_replace('%', '%%', $value);
        }

        if (is_array($value)) {
            $result = array();
            foreach ($value as $k => $v) {
                $result[$k] = $this->escapeValue($v);
            }

            return $result;
        }

        return $value;
    }

    public function unescapeValue($value)
    {
        if (is_string($value)) {
            return str_replace('%%', '%', $value);
        }

        if (is_array($value)) {
            $result = array();
            foreach ($value as $k => $v) {
                $result[$k] = $this->unescapeValue($v);
            }

            return $result;
        }

        return $value;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\ParameterBag;

use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;

/**
 * ParameterBagInterface.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @api
 */
interface ParameterBagInterface
{
    /**
     * Clears all parameters.
     *
     * @api
     */
    public function clear();

    /**
     * Adds parameters to the service container parameters.
     *
     * @param array $parameters An array of parameters
     *
     * @api
     */
    public function add(array $parameters);

    /**
     * Gets the service container parameters.
     *
     * @return array An array of parameters
     *
     * @api
     */
    public function all();

    /**
     * Gets a service container parameter.
     *
     * @param string $name The parameter name
     *
     * @return mixed  The parameter value
     *
     * @throws ParameterNotFoundException if the parameter is not defined
     *
     * @api
     */
    public function get($name);

    /**
     * Sets a service container parameter.
     *
     * @param string $name  The parameter name
     * @param mixed  $value The parameter value
     *
     * @api
     */
    public function set($name, $value);

    /**
     * Returns true if a parameter name is defined.
     *
     * @param string $name The parameter name
     *
     * @return Boolean true if the parameter name is defined, false otherwise
     *
     * @api
     */
    public function has($name);

    /**
     * Replaces parameter placeholders (%name%) by their values for all parameters.
     */
    public function resolve();

    /**
     * Replaces parameter placeholders (%name%) by their values.
     *
     * @param mixed $value A value
     *
     * @throws ParameterNotFoundException if a placeholder references a parameter that does not exist
     */
    public function resolveValue($value);

    /**
     * Escape parameter placeholders %
     *
     * @param mixed $value
     *
     * @return mixed
     */
    public function escapeValue($value);

    /**
     * Unescape parameter placeholders %
     *
     * @param mixed $value
     *
     * @return mixed
     */
    public function unescapeValue($value);
}
CHANGELOG
=========

2.2.0
-----

 * added Extension::isConfigEnabled() to ease working with enableable configurations
 * added an Extension base class with sensible defaults to be used in conjunction
   with the Config component.
 * added PrependExtensionInterface (to be able to allow extensions to prepend
   application configuration settings for any Bundle)

2.1.0
-----

 * added IntrospectableContainerInterface (to be able to check if a service
   has been initialized or not)
 * added ConfigurationExtensionInterface
 * added Definition::clearTag()
 * component exceptions that inherit base SPL classes are now used exclusively
   (this includes dumped containers)
 * [BC BREAK] fixed unescaping of class arguments, method
   ParameterBag::unescapeValue() was made public
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection;

use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;

/**
 * ContainerInterface is the interface implemented by service container classes.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 *
 * @api
 */
interface ContainerInterface
{
    const EXCEPTION_ON_INVALID_REFERENCE = 1;
    const NULL_ON_INVALID_REFERENCE      = 2;
    const IGNORE_ON_INVALID_REFERENCE    = 3;
    const SCOPE_CONTAINER                = 'container';
    const SCOPE_PROTOTYPE                = 'prototype';

    /**
     * Sets a service.
     *
     * @param string $id      The service identifier
     * @param object $service The service instance
     * @param string $scope   The scope of the service
     *
     * @api
     */
    public function set($id, $service, $scope = self::SCOPE_CONTAINER);

    /**
     * Gets a service.
     *
     * @param string $id              The service identifier
     * @param int    $invalidBehavior The behavior when the service does not exist
     *
     * @return object The associated service
     *
     * @throws InvalidArgumentException if the service is not defined
     * @throws ServiceCircularReferenceException When a circular reference is detected
     * @throws ServiceNotFoundException When the service is not defined
     *
     * @see Reference
     *
     * @api
     */
    public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE);

    /**
     * Returns true if the given service is defined.
     *
     * @param string $id The service identifier
     *
     * @return Boolean true if the service is defined, false otherwise
     *
     * @api
     */
    public function has($id);

    /**
     * Gets a parameter.
     *
     * @param string $name The parameter name
     *
     * @return mixed  The parameter value
     *
     * @throws InvalidArgumentException if the parameter is not defined
     *
     * @api
     */
    public function getParameter($name);

    /**
     * Checks if a parameter exists.
     *
     * @param string $name The parameter name
     *
     * @return Boolean The presence of parameter in container
     *
     * @api
     */
    public function hasParameter($name);

    /**
     * Sets a parameter.
     *
     * @param string $name  The parameter name
     * @param mixed  $value The parameter value
     *
     * @api
     */
    public function setParameter($name, $value);

    /**
     * Enters the given scope
     *
     * @param string $name
     *
     * @api
     */
    public function enterScope($name);

    /**
     * Leaves the current scope, and re-enters the parent scope
     *
     * @param string $name
     *
     * @api
     */
    public function leaveScope($name);

    /**
     * Adds a scope to the container
     *
     * @param ScopeInterface $scope
     *
     * @api
     */
    public function addScope(ScopeInterface $scope);

    /**
     * Whether this container has the given scope
     *
     * @param string $name
     *
     * @return Boolean
     *
     * @api
     */
    public function hasScope($name);

    /**
     * Determines whether the given scope is currently active.
     *
     * It does however not check if the scope actually exists.
     *
     * @param string $name
     *
     * @return Boolean
     *
     * @api
     */
    public function isScopeActive($name);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Extension;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;

/**
 * ConfigurationExtensionInterface is the interface implemented by container extension classes.
 *
 * @author Kevin Bond <kevinbond@gmail.com>
 */
interface ConfigurationExtensionInterface
{
    /**
     * Returns extension configuration
     *
     * @param array            $config    $config    An array of configuration values
     * @param ContainerBuilder $container A ContainerBuilder instance
     *
     * @return ConfigurationInterface|null The configuration or null
     */
    public function getConfiguration(array $config, ContainerBuilder $container);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Extension;

use Symfony\Component\DependencyInjection\ContainerBuilder;

interface PrependExtensionInterface
{
    /**
     * Allow an extension to prepend the extension configurations.
     *
     * @param ContainerBuilder $container
     */
    public function prepend(ContainerBuilder $container);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Extension;

use Symfony\Component\DependencyInjection\ContainerBuilder;

/**
 * ExtensionInterface is the interface implemented by container extension classes.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @api
 */
interface ExtensionInterface
{
    /**
     * Loads a specific configuration.
     *
     * @param array            $config    An array of configuration values
     * @param ContainerBuilder $container A ContainerBuilder instance
     *
     * @throws InvalidArgumentException When provided tag is not defined in this extension
     *
     * @api
     */
    public function load(array $config, ContainerBuilder $container);

    /**
     * Returns the namespace to be used for this extension (XML namespace).
     *
     * @return string The XML namespace
     *
     * @api
     */
    public function getNamespace();

    /**
     * Returns the base path for the XSD files.
     *
     * @return string The XSD base path
     *
     * @api
     */
    public function getXsdValidationBasePath();

    /**
     * Returns the recommended alias to use in XML.
     *
     * This alias is also the mandatory prefix to use when using YAML.
     *
     * @return string The alias
     *
     * @api
     */
    public function getAlias();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection\Extension;

use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Exception\BadMethodCallException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\Definition\Processor;
use Symfony\Component\Config\Definition\ConfigurationInterface;

/**
 * Provides useful features shared by many extensions.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
abstract class Extension implements ExtensionInterface, ConfigurationExtensionInterface
{
    /**
     * Returns the base path for the XSD files.
     *
     * @return string The XSD base path
     */
    public function getXsdValidationBasePath()
    {
        return false;
    }

    /**
     * Returns the namespace to be used for this extension (XML namespace).
     *
     * @return string The XML namespace
     */
    public function getNamespace()
    {
        return 'http://example.org/schema/dic/'.$this->getAlias();
    }

    /**
     * Returns the recommended alias to use in XML.
     *
     * This alias is also the mandatory prefix to use when using YAML.
     *
     * This convention is to remove the "Extension" postfix from the class
     * name and then lowercase and underscore the result. So:
     *
     *     AcmeHelloExtension
     *
     * becomes
     *
     *     acme_hello
     *
     * This can be overridden in a sub-class to specify the alias manually.
     *
     * @return string The alias
     *
     * @throws BadMethodCallException When the extension name does not follow conventions
     */
    public function getAlias()
    {
        $className = get_class($this);
        if (substr($className, -9) != 'Extension') {
            throw new BadMethodCallException('This extension does not follow the naming convention; you must overwrite the getAlias() method.');
        }
        $classBaseName = substr(strrchr($className, '\\'), 1, -9);

        return Container::underscore($classBaseName);
    }

    /**
     * {@inheritDoc}
     */
    public function getConfiguration(array $config, ContainerBuilder $container)
    {
        $reflected = new \ReflectionClass($this);
        $namespace = $reflected->getNamespaceName();

        $class = $namespace.'\\Configuration';
        if (class_exists($class)) {
            $r = new \ReflectionClass($class);
            $container->addResource(new FileResource($r->getFileName()));

            if (!method_exists($class, '__construct')) {
                $configuration = new $class();

                return $configuration;
            }
        }

        return null;
    }

    final protected function processConfiguration(ConfigurationInterface $configuration, array $configs)
    {
        $processor = new Processor();

        return $processor->processConfiguration($configuration, $configs);
    }

    /**
     * @param ContainerBuilder $container
     * @param array            $config
     *
     * @return Boolean Whether the configuration is enabled
     *
     * @throws InvalidArgumentException When the config is not enableable
     */
    protected function isConfigEnabled(ContainerBuilder $container, array $config)
    {
        if (!array_key_exists('enabled', $config)) {
            throw new InvalidArgumentException("The config array has no 'enabled' key.");
        }

        return (Boolean) $container->getParameterBag()->resolveValue($config['enabled']);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection;

/**
 * ContainerAwareInterface should be implemented by classes that depends on a Container.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @api
 */
interface ContainerAwareInterface
{
    /**
     * Sets the Container.
     *
     * @param ContainerInterface|null $container A ContainerInterface instance or null
     *
     * @api
     */
    public function setContainer(ContainerInterface $container = null);
}
DependencyInjection Component
=============================

DependencyInjection manages your services via a robust and flexible Dependency
Injection Container.

Here is a simple example that shows how to register services and parameters:

    use Symfony\Component\DependencyInjection\ContainerBuilder;
    use Symfony\Component\DependencyInjection\Reference;

    $sc = new ContainerBuilder();
    $sc
        ->register('foo', '%foo.class%')
        ->addArgument(new Reference('bar'))
    ;
    $sc->setParameter('foo.class', 'Foo');

    $sc->get('foo');

Method Calls (Setter Injection):

    $sc = new ContainerBuilder();

    $sc
        ->register('bar', '%bar.class%')
        ->addMethodCall('setFoo', array(new Reference('foo')))
    ;
    $sc->setParameter('bar.class', 'Bar');

    $sc->get('bar');

Factory Class:

If your service is retrieved by calling a static method:

    $sc = new ContainerBuilder();

    $sc
        ->register('bar', '%bar.class%')
        ->setFactoryClass('%bar.class%')
        ->setFactoryMethod('getInstance')
        ->addArgument('Aarrg!!!')
    ;
    $sc->setParameter('bar.class', 'Bar');

    $sc->get('bar');

File Include:

For some services, especially those that are difficult or impossible to
autoload, you may need the container to include a file before
instantiating your class.

    $sc = new ContainerBuilder();

    $sc
        ->register('bar', '%bar.class%')
        ->setFile('/path/to/file')
        ->addArgument('Aarrg!!!')
    ;
    $sc->setParameter('bar.class', 'Bar');

    $sc->get('bar');

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/DependencyInjection/
    $ composer.phar install --dev
    $ phpunit
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\DependencyInjection;

/**
 * Reference represents a service reference.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 *
 * @api
 */
class Reference
{
    private $id;
    private $invalidBehavior;
    private $strict;

    /**
     * Constructor.
     *
     * @param string  $id              The service identifier
     * @param int     $invalidBehavior The behavior when the service does not exist
     * @param Boolean $strict          Sets how this reference is validated
     *
     * @see Container
     */
    public function __construct($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, $strict = true)
    {
        $this->id = strtolower($id);
        $this->invalidBehavior = $invalidBehavior;
        $this->strict = $strict;
    }

    /**
     * __toString.
     *
     * @return string The service identifier
     */
    public function __toString()
    {
        return (string) $this->id;
    }

    /**
     * Returns the behavior to be used when the service does not exist.
     *
     * @return int
     */
    public function getInvalidBehavior()
    {
        return $this->invalidBehavior;
    }

    /**
     * Returns true when this Reference is strict
     *
     * @return Boolean
     */
    public function isStrict()
    {
        return $this->strict;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Util;

/**
 * XMLUtils is a bunch of utility methods to XML operations.
 *
 * This class contains static methods only and is not meant to be instantiated.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 * @author Martin HasoÅˆ <martin.hason@gmail.com>
 */
class XmlUtils
{
    /**
     * This class should not be instantiated
     */
    private function __construct()
    {
    }

    /**
     * Loads an XML file.
     *
     * @param string $file                      An XML file path
     * @param string|callable $schemaOrCallable An XSD schema file path or callable
     *
     * @return \DOMDocument
     *
     * @throws \InvalidArgumentException When loading of XML file returns error
     */
    public static function loadFile($file, $schemaOrCallable = null)
    {
        $internalErrors = libxml_use_internal_errors(true);
        $disableEntities = libxml_disable_entity_loader(true);
        libxml_clear_errors();

        $dom = new \DOMDocument();
        $dom->validateOnParse = true;
        if (!$dom->loadXML(file_get_contents($file), LIBXML_NONET | (defined('LIBXML_COMPACT') ? LIBXML_COMPACT : 0))) {
            libxml_disable_entity_loader($disableEntities);

            throw new \InvalidArgumentException(implode("\n", static::getXmlErrors($internalErrors)));
        }

        $dom->normalizeDocument();

        libxml_use_internal_errors($internalErrors);
        libxml_disable_entity_loader($disableEntities);

        foreach ($dom->childNodes as $child) {
            if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) {
                throw new \InvalidArgumentException('Document types are not allowed.');
            }
        }

        if (null !== $schemaOrCallable) {
            $internalErrors = libxml_use_internal_errors(true);
            libxml_clear_errors();

            $e = null;
            if (is_callable($schemaOrCallable)) {
                try {
                    $valid = call_user_func($schemaOrCallable, $dom, $internalErrors);
                } catch (\Exception $e) {
                    $valid = false;
                }
            } elseif (!is_array($schemaOrCallable) && is_file((string) $schemaOrCallable)) {
                $valid = @$dom->schemaValidate($schemaOrCallable);
            } else {
                libxml_use_internal_errors($internalErrors);

                throw new \InvalidArgumentException('The schemaOrCallable argument has to be a valid path to XSD file or callable.');
            }

            if (!$valid) {
                $messages = static::getXmlErrors($internalErrors);
                if (empty($messages)) {
                    $messages = array(sprintf('The XML file "%s" is not valid.', $file));
                }
                throw new \InvalidArgumentException(implode("\n", $messages), 0, $e);
            }

            libxml_use_internal_errors($internalErrors);
        }

        return $dom;
    }

    /**
     * Converts a \DomElement object to a PHP array.
     *
     * The following rules applies during the conversion:
     *
     *  * Each tag is converted to a key value or an array
     *    if there is more than one "value"
     *
     *  * The content of a tag is set under a "value" key (<foo>bar</foo>)
     *    if the tag also has some nested tags
     *
     *  * The attributes are converted to keys (<foo foo="bar"/>)
     *
     *  * The nested-tags are converted to keys (<foo><foo>bar</foo></foo>)
     *
     * @param \DomElement $element     A \DomElement instance
     * @param Boolean     $checkPrefix Check prefix in an element or an attribute name
     *
     * @return array A PHP array
     */
    public static function convertDomElementToArray(\DomElement $element, $checkPrefix = true)
    {
        $prefix = (string) $element->prefix;
        $empty = true;
        $config = array();
        foreach ($element->attributes as $name => $node) {
            if ($checkPrefix && !in_array((string) $node->prefix, array('', $prefix), true)) {
                continue;
            }
            $config[$name] = static::phpize($node->value);
            $empty = false;
        }

        $nodeValue = false;
        foreach ($element->childNodes as $node) {
            if ($node instanceof \DOMText) {
                if (trim($node->nodeValue)) {
                    $nodeValue = trim($node->nodeValue);
                    $empty = false;
                }
            } elseif ($checkPrefix && $prefix != (string) $node->prefix) {
                continue;
            } elseif (!$node instanceof \DOMComment) {
                $value = static::convertDomElementToArray($node, $checkPrefix);

                $key = $node->localName;
                if (isset($config[$key])) {
                    if (!is_array($config[$key]) || !is_int(key($config[$key]))) {
                        $config[$key] = array($config[$key]);
                    }
                    $config[$key][] = $value;
                } else {
                    $config[$key] = $value;
                }

                $empty = false;
            }
        }

        if (false !== $nodeValue) {
            $value = static::phpize($nodeValue);
            if (count($config)) {
                $config['value'] = $value;
            } else {
                $config = $value;
            }
        }

        return !$empty ? $config : null;
    }

    /**
     * Converts an xml value to a php type.
     *
     * @param mixed $value
     *
     * @return mixed
     */
    public static function phpize($value)
    {
        $value = (string) $value;
        $lowercaseValue = strtolower($value);

        switch (true) {
            case 'null' === $lowercaseValue:
                return null;
            case ctype_digit($value):
                $raw = $value;
                $cast = intval($value);

                return '0' == $value[0] ? octdec($value) : (((string) $raw == (string) $cast) ? $cast : $raw);
            case 'true' === $lowercaseValue:
                return true;
            case 'false' === $lowercaseValue:
                return false;
            case is_numeric($value):
                return '0x' == $value[0].$value[1] ? hexdec($value) : floatval($value);
            case preg_match('/^(-|\+)?[0-9]+(\.[0-9]+)?$/', $value):
                return floatval($value);
            default:
                return $value;
        }
    }

    protected static function getXmlErrors($internalErrors)
    {
        $errors = array();
        foreach (libxml_get_errors() as $error) {
            $errors[] = sprintf('[%s %s] %s (in %s - line %d, column %d)',
                LIBXML_ERR_WARNING == $error->level ? 'WARNING' : 'ERROR',
                $error->code,
                trim($error->message),
                $error->file ? $error->file : 'n/a',
                $error->line,
                $error->column
            );
        }

        libxml_clear_errors();
        libxml_use_internal_errors($internalErrors);

        return $errors;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Exception;

/**
 * Exception class for when a circular reference is detected when importing resources.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class FileLoaderImportCircularReferenceException extends FileLoaderLoadException
{
    public function __construct(array $resources, $code = null, $previous = null)
    {
        $message = sprintf('Circular reference detected in "%s" ("%s" > "%s").', $this->varToString($resources[0]), implode('" > "', $resources), $resources[0]);

        call_user_func('Exception::__construct', $message, $code, $previous);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Exception;

/**
 * Exception class for when a resource cannot be loaded or imported.
 *
 * @author Ryan Weaver <ryan@thatsquality.com>
 */
class FileLoaderLoadException extends \Exception
{
    /**
     * @param string     $resource       The resource that could not be imported
     * @param string     $sourceResource The original resource importing the new resource
     * @param integer    $code           The error code
     * @param \Exception $previous       A previous exception
     */
    public function __construct($resource, $sourceResource = null, $code = null, $previous = null)
    {
        if (null === $sourceResource) {
            $message = sprintf('Cannot load resource "%s".', $this->varToString($resource));
        } else {
            $message = sprintf('Cannot import resource "%s" from "%s".', $this->varToString($resource), $this->varToString($sourceResource));
        }

        // Is the resource located inside a bundle?
        if ('@' === $resource[0]) {
            $parts = explode(DIRECTORY_SEPARATOR, $resource);
            $bundle = substr($parts[0], 1);
            $message .= ' '.sprintf('Make sure the "%s" bundle is correctly registered and loaded in the application kernel class.', $bundle);
        } elseif ($previous) {
            // include the previous exception, to help the user see what might be the underlying cause
            $message .= ' '.sprintf('(%s)', $previous->getMessage());
        }

        parent::__construct($message, $code, $previous);
    }

    protected function varToString($var)
    {
        if (is_object($var)) {
            return sprintf('Object(%s)', get_class($var));
        }

        if (is_array($var)) {
            $a = array();
            foreach ($var as $k => $v) {
                $a[] = sprintf('%s => %s', $k, $this->varToString($v));
            }

            return sprintf("Array(%s)", implode(', ', $a));
        }

        if (is_resource($var)) {
            return sprintf('Resource(%s)', get_resource_type($var));
        }

        if (null === $var) {
            return 'null';
        }

        if (false === $var) {
            return 'false';
        }

        if (true === $var) {
            return 'true';
        }

        return (string) $var;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition;

/**
 * Configuration interface
 *
 * @author Victor Berchet <victor@suumit.com>
 */
interface ConfigurationInterface
{
    /**
     * Generates the configuration tree builder.
     *
     * @return \Symfony\Component\Config\Definition\Builder\TreeBuilder The tree builder
     */
    public function getConfigTreeBuilder();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition;

use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;

/**
 * This node represents a numeric value in the config tree
 *
 * @author David Jeanmonod <david.jeanmonod@gmail.com>
 */
class NumericNode extends ScalarNode
{
    protected $min;
    protected $max;

    public function __construct($name, NodeInterface $parent = null, $min = null, $max = null)
    {
        parent::__construct($name, $parent);
        $this->min = $min;
        $this->max = $max;
    }

    /**
     * {@inheritDoc}
     */
    protected function finalizeValue($value)
    {
        $value = parent::finalizeValue($value);

        $errorMsg = null;
        if (isset($this->min) && $value < $this->min) {
            $errorMsg = sprintf('The value %s is too small for path "%s". Should be greater than: %s', $value, $this->getPath(), $this->min);
        }
        if (isset($this->max) && $value > $this->max) {
            $errorMsg = sprintf('The value %s is too big for path "%s". Should be less than: %s', $value, $this->getPath(), $this->max);
        }
        if (isset($errorMsg)) {
            $ex = new InvalidConfigurationException($errorMsg);
            $ex->setPath($this->getPath());
            throw $ex;
        }

        return $value;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition;

use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;

/**
 * This node represents a value of variable type in the config tree.
 *
 * This node is intended for values of arbitrary type.
 * Any PHP type is accepted as a value.
 *
 * @author Jeremy Mikola <jmikola@gmail.com>
 */
class VariableNode extends BaseNode implements PrototypeNodeInterface
{
    protected $defaultValueSet = false;
    protected $defaultValue;
    protected $allowEmptyValue = true;

    /**
     * {@inheritDoc}
     */
    public function setDefaultValue($value)
    {
        $this->defaultValueSet = true;
        $this->defaultValue = $value;
    }

    /**
     * {@inheritDoc}
     */
    public function hasDefaultValue()
    {
        return $this->defaultValueSet;
    }

    /**
     * {@inheritDoc}
     */
    public function getDefaultValue()
    {
        return $this->defaultValue instanceof \Closure ? call_user_func($this->defaultValue) : $this->defaultValue;
    }

    /**
     * Sets if this node is allowed to have an empty value.
     *
     * @param Boolean $boolean True if this entity will accept empty values.
     */
    public function setAllowEmptyValue($boolean)
    {
        $this->allowEmptyValue = (Boolean) $boolean;
    }

    /**
     * {@inheritDoc}
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * {@inheritDoc}
     */
    protected function validateType($value)
    {
    }

    /**
     * {@inheritDoc}
     */
    protected function finalizeValue($value)
    {
        if (!$this->allowEmptyValue && empty($value)) {
            $ex = new InvalidConfigurationException(sprintf(
                'The path "%s" cannot contain an empty value, but got %s.',
                $this->getPath(),
                json_encode($value)
            ));
            $ex->setPath($this->getPath());

            throw $ex;
        }

        return $value;
    }

    /**
     * {@inheritDoc}
     */
    protected function normalizeValue($value)
    {
        return $value;
    }

    /**
     * {@inheritDoc}
     */
    protected function mergeValues($leftSide, $rightSide)
    {
        return $rightSide;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Exception;

/**
 * This exception is usually not encountered by the end-user, but only used
 * internally to signal the parent scope to unset a key.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class UnsetKeyException extends Exception
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Exception;

/**
 * A very general exception which can be thrown whenever non of the more specific
 * exceptions is suitable.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class InvalidConfigurationException extends Exception
{
    private $path;

    public function setPath($path)
    {
        $this->path = $path;
    }

    public function getPath()
    {
        return $this->path;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Exception;

/**
 * Thrown when an error is detected in a node Definition.
 *
 * @author Victor Berchet <victor.berchet@suumit.com>
 */
class InvalidDefinitionException extends Exception
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Exception;

/**
 * This exception is thrown whenever the key of an array is not unique. This can
 * only be the case if the configuration is coming from an XML file.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class DuplicateKeyException extends InvalidConfigurationException
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Exception;

/**
 * Base exception for all configuration exceptions
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class Exception extends \RuntimeException
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Exception;

/**
 * This exception is thrown if an invalid type is encountered.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class InvalidTypeException extends InvalidConfigurationException
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Exception;

/**
 * This exception is thrown when a configuration path is overwritten from a
 * subsequent configuration file, but the entry node specifically forbids this.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ForbiddenOverwriteException extends InvalidConfigurationException
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Builder;

use Symfony\Component\Config\Definition\VariableNode;

/**
 * This class provides a fluent interface for defining a node.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class VariableNodeDefinition extends NodeDefinition
{
    /**
     * Instantiate a Node
     *
     * @return VariableNode The node
     */
    protected function instantiateNode()
    {
        return new VariableNode($this->name, $this->parent);
    }

    /**
     * {@inheritDoc}
     */
    protected function createNode()
    {
        $node = $this->instantiateNode();

        if (null !== $this->normalization) {
            $node->setNormalizationClosures($this->normalization->before);
        }

        if (null !== $this->merge) {
            $node->setAllowOverwrite($this->merge->allowOverwrite);
        }

        if (true === $this->default) {
            $node->setDefaultValue($this->defaultValue);
        }

        if (false === $this->allowEmptyValue) {
            $node->setAllowEmptyValue($this->allowEmptyValue);
        }

        $node->addEquivalentValue(null, $this->nullEquivalent);
        $node->addEquivalentValue(true, $this->trueEquivalent);
        $node->addEquivalentValue(false, $this->falseEquivalent);
        $node->setRequired($this->required);

        if (null !== $this->validation) {
            $node->setFinalValidationClosures($this->validation->rules);
        }

        return $node;
    }

}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Builder;

/**
 * An interface that must be implemented by all node parents
 *
 * @author Victor Berchet <victor@suumit.com>
 */
interface NodeParentInterface
{
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Builder;

/**
 * This class builds validation conditions.
 *
 * @author Christophe Coevoet <stof@notk.org>
 */
class ValidationBuilder
{
    protected $node;
    public $rules;

    /**
     * Constructor
     *
     * @param NodeDefinition $node The related node
     */
    public function __construct(NodeDefinition $node)
    {
        $this->node = $node;

        $this->rules = array();
    }

    /**
     * Registers a closure to run as normalization or an expression builder to build it if null is provided.
     *
     * @param \Closure $closure
     *
     * @return ExprBuilder|ValidationBuilder
     */
    public function rule(\Closure $closure = null)
    {
        if (null !== $closure) {
            $this->rules[] = $closure;

            return $this;
        }

        return $this->rules[] = new ExprBuilder($this->node);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Builder;

use Symfony\Component\Config\Definition\NodeInterface;
use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException;

/**
 * This class provides a fluent interface for defining a node.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
abstract class NodeDefinition implements NodeParentInterface
{
    protected $name;
    protected $normalization;
    protected $validation;
    protected $defaultValue;
    protected $default;
    protected $required;
    protected $merge;
    protected $allowEmptyValue;
    protected $nullEquivalent;
    protected $trueEquivalent;
    protected $falseEquivalent;
    /**
     * @var NodeParentInterface|NodeInterface
     */
    protected $parent;
    protected $attributes = array();

    /**
     * Constructor
     *
     * @param string              $name   The name of the node
     * @param NodeParentInterface $parent The parent
     */
    public function __construct($name, NodeParentInterface $parent = null)
    {
        $this->parent = $parent;
        $this->name = $name;
        $this->default = false;
        $this->required = false;
        $this->trueEquivalent = true;
        $this->falseEquivalent = false;
    }

    /**
     * Sets the parent node.
     *
     * @param NodeParentInterface $parent The parent
     *
     * @return NodeDefinition
     */
    public function setParent(NodeParentInterface $parent)
    {
        $this->parent = $parent;

        return $this;
    }

    /**
     * Sets info message.
     *
     * @param string $info The info text
     *
     * @return NodeDefinition
     */
    public function info($info)
    {
        return $this->attribute('info', $info);
    }

    /**
     * Sets example configuration.
     *
     * @param string|array $example
     *
     * @return NodeDefinition
     */
    public function example($example)
    {
        return $this->attribute('example', $example);
    }

    /**
     * Sets an attribute on the node.
     *
     * @param string $key
     * @param mixed $value
     *
     * @return NodeDefinition
     */
    public function attribute($key, $value)
    {
        $this->attributes[$key] = $value;

        return $this;
    }

    /**
     * Returns the parent node.
     *
     * @return NodeParentInterface The builder of the parent node
     */
    public function end()
    {
        return $this->parent;
    }

    /**
     * Creates the node.
     *
     * @param Boolean $forceRootNode Whether to force this node as the root node
     *
     * @return NodeInterface
     */
    public function getNode($forceRootNode = false)
    {
        if ($forceRootNode) {
            $this->parent = null;
        }

        if (null !== $this->normalization) {
            $this->normalization->before = ExprBuilder::buildExpressions($this->normalization->before);
        }

        if (null !== $this->validation) {
            $this->validation->rules = ExprBuilder::buildExpressions($this->validation->rules);
        }

        $node = $this->createNode();
        $node->setAttributes($this->attributes);

        return $node;
    }

    /**
     * Sets the default value.
     *
     * @param mixed $value The default value
     *
     * @return NodeDefinition
     */
    public function defaultValue($value)
    {
        $this->default = true;
        $this->defaultValue = $value;

        return $this;
    }

    /**
     * Sets the node as required.
     *
     * @return NodeDefinition
     */
    public function isRequired()
    {
        $this->required = true;

        return $this;
    }

    /**
     * Sets the equivalent value used when the node contains null.
     *
     * @param mixed $value
     *
     * @return NodeDefinition
     */
    public function treatNullLike($value)
    {
        $this->nullEquivalent = $value;

        return $this;
    }

    /**
     * Sets the equivalent value used when the node contains true.
     *
     * @param mixed $value
     *
     * @return NodeDefinition
     */
    public function treatTrueLike($value)
    {
        $this->trueEquivalent = $value;

        return $this;
    }

    /**
     * Sets the equivalent value used when the node contains false.
     *
     * @param mixed $value
     *
     * @return NodeDefinition
     */
    public function treatFalseLike($value)
    {
        $this->falseEquivalent = $value;

        return $this;
    }

    /**
     * Sets null as the default value.
     *
     * @return NodeDefinition
     */
    public function defaultNull()
    {
        return $this->defaultValue(null);
    }

    /**
     * Sets true as the default value.
     *
     * @return NodeDefinition
     */
    public function defaultTrue()
    {
        return $this->defaultValue(true);
    }

    /**
     * Sets false as the default value.
     *
     * @return NodeDefinition
     */
    public function defaultFalse()
    {
        return $this->defaultValue(false);
    }

    /**
     * Sets an expression to run before the normalization.
     *
     * @return ExprBuilder
     */
    public function beforeNormalization()
    {
        return $this->normalization()->before();
    }

    /**
     * Denies the node value being empty.
     *
     * @return NodeDefinition
     */
    public function cannotBeEmpty()
    {
        $this->allowEmptyValue = false;

        return $this;
    }

    /**
     * Sets an expression to run for the validation.
     *
     * The expression receives the value of the node and must return it. It can
     * modify it.
     * An exception should be thrown when the node is not valid.
     *
     * @return ExprBuilder
     */
    public function validate()
    {
        return $this->validation()->rule();
    }

    /**
     * Sets whether the node can be overwritten.
     *
     * @param Boolean $deny Whether the overwriting is forbidden or not
     *
     * @return NodeDefinition
     */
    public function cannotBeOverwritten($deny = true)
    {
        $this->merge()->denyOverwrite($deny);

        return $this;
    }

    /**
     * Gets the builder for validation rules.
     *
     * @return ValidationBuilder
     */
    protected function validation()
    {
        if (null === $this->validation) {
            $this->validation = new ValidationBuilder($this);
        }

        return $this->validation;
    }

    /**
     * Gets the builder for merging rules.
     *
     * @return MergeBuilder
     */
    protected function merge()
    {
        if (null === $this->merge) {
            $this->merge = new MergeBuilder($this);
        }

        return $this->merge;
    }

    /**
     * Gets the builder for normalization rules.
     *
     * @return NormalizationBuilder
     */
    protected function normalization()
    {
        if (null === $this->normalization) {
            $this->normalization = new NormalizationBuilder($this);
        }

        return $this->normalization;
    }

    /**
     * Instantiate and configure the node according to this definition
     *
     * @return NodeInterface $node The node instance
     *
     * @throws InvalidDefinitionException When the definition is invalid
     */
    abstract protected function createNode();

}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Builder;

/**
 * This class provides a fluent interface for building a node.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class NodeBuilder implements NodeParentInterface
{
    protected $parent;
    protected $nodeMapping;

    /**
     * Constructor
     *
     */
    public function __construct()
    {
        $this->nodeMapping = array(
            'variable'    => __NAMESPACE__.'\\VariableNodeDefinition',
            'scalar'      => __NAMESPACE__.'\\ScalarNodeDefinition',
            'boolean'     => __NAMESPACE__.'\\BooleanNodeDefinition',
            'integer'     => __NAMESPACE__.'\\IntegerNodeDefinition',
            'float'       => __NAMESPACE__.'\\FloatNodeDefinition',
            'array'       => __NAMESPACE__.'\\ArrayNodeDefinition',
            'enum'        => __NAMESPACE__.'\\EnumNodeDefinition',
        );
    }

    /**
     * Set the parent node.
     *
     * @param ParentNodeDefinitionInterface $parent The parent node
     *
     * @return NodeBuilder This node builder
     */
    public function setParent(ParentNodeDefinitionInterface $parent = null)
    {
        $this->parent = $parent;

        return $this;
    }

    /**
     * Creates a child array node.
     *
     * @param string $name The name of the node
     *
     * @return ArrayNodeDefinition The child node
     */
    public function arrayNode($name)
    {
        return $this->node($name, 'array');
    }

    /**
     * Creates a child scalar node.
     *
     * @param string $name the name of the node
     *
     * @return ScalarNodeDefinition The child node
     */
    public function scalarNode($name)
    {
        return $this->node($name, 'scalar');
    }

    /**
     * Creates a child Boolean node.
     *
     * @param string $name The name of the node
     *
     * @return BooleanNodeDefinition The child node
     */
    public function booleanNode($name)
    {
        return $this->node($name, 'boolean');
    }

    /**
     * Creates a child integer node.
     *
     * @param string $name the name of the node
     *
     * @return IntegerNodeDefinition The child node
     */
    public function integerNode($name)
    {
        return $this->node($name, 'integer');
    }

    /**
     * Creates a child float node.
     *
     * @param string $name the name of the node
     *
     * @return FloatNodeDefinition The child node
     */
    public function floatNode($name)
    {
        return $this->node($name, 'float');
    }

    /**
     * Creates a child EnumNode.
     *
     * @param string $name
     *
     * @return EnumNodeDefinition
     */
    public function enumNode($name)
    {
        return $this->node($name, 'enum');
    }

    /**
     * Creates a child variable node.
     *
     * @param string $name The name of the node
     *
     * @return VariableNodeDefinition The builder of the child node
     */
    public function variableNode($name)
    {
        return $this->node($name, 'variable');
    }

    /**
     * Returns the parent node.
     *
     * @return ParentNodeDefinitionInterface The parent node
     */
    public function end()
    {
        return $this->parent;
    }

    /**
     * Creates a child node.
     *
     * @param string $name The name of the node
     * @param string $type The type of the node
     *
     * @return NodeDefinition The child node
     *
     * @throws \RuntimeException When the node type is not registered
     * @throws \RuntimeException When the node class is not found
     */
    public function node($name, $type)
    {
        $class = $this->getNodeClass($type);

        $node = new $class($name);

        $this->append($node);

        return $node;
    }

    /**
     * Appends a node definition.
     *
     * Usage:
     *
     *     $node = new ArrayNodeDefinition('name')
     *         ->children()
     *             ->scalarNode('foo')->end()
     *             ->scalarNode('baz')->end()
     *             ->append($this->getBarNodeDefinition())
     *         ->end()
     *     ;
     *
     * @param NodeDefinition $node
     *
     * @return NodeBuilder This node builder
     */
    public function append(NodeDefinition $node)
    {
        if ($node instanceof ParentNodeDefinitionInterface) {
            $builder = clone $this;
            $builder->setParent(null);
            $node->setBuilder($builder);
        }

        if (null !== $this->parent) {
            $this->parent->append($node);
            // Make this builder the node parent to allow for a fluid interface
            $node->setParent($this);
        }

        return $this;
    }

    /**
     * Adds or overrides a node Type.
     *
     * @param string $type  The name of the type
     * @param string $class The fully qualified name the node definition class
     *
     * @return NodeBuilder This node builder
     */
    public function setNodeClass($type, $class)
    {
        $this->nodeMapping[strtolower($type)] = $class;

        return $this;
    }

    /**
     * Returns the class name of the node definition.
     *
     * @param string $type The node type
     *
     * @return string The node definition class name
     *
     * @throws \RuntimeException When the node type is not registered
     * @throws \RuntimeException When the node class is not found
     */
    protected function getNodeClass($type)
    {
        $type = strtolower($type);

        if (!isset($this->nodeMapping[$type])) {
            throw new \RuntimeException(sprintf('The node type "%s" is not registered.', $type));
        }

        $class = $this->nodeMapping[$type];

        if (!class_exists($class)) {
            throw new \RuntimeException(sprintf('The node class "%s" does not exist.', $class));
        }

        return $class;
    }

}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Builder;

use Symfony\Component\Config\Definition\ArrayNode;
use Symfony\Component\Config\Definition\PrototypedArrayNode;
use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException;

/**
 * This class provides a fluent interface for defining an array node.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ArrayNodeDefinition extends NodeDefinition implements ParentNodeDefinitionInterface
{
    protected $performDeepMerging;
    protected $ignoreExtraKeys;
    protected $children;
    protected $prototype;
    protected $atLeastOne;
    protected $allowNewKeys;
    protected $key;
    protected $removeKeyItem;
    protected $addDefaults;
    protected $addDefaultChildren;
    protected $nodeBuilder;
    protected $normalizeKeys;

    /**
     * {@inheritDoc}
     */
    public function __construct($name, NodeParentInterface $parent = null)
    {
        parent::__construct($name, $parent);

        $this->children = array();
        $this->addDefaults = false;
        $this->addDefaultChildren = false;
        $this->allowNewKeys = true;
        $this->atLeastOne = false;
        $this->allowEmptyValue = true;
        $this->performDeepMerging = true;
        $this->nullEquivalent = array();
        $this->trueEquivalent = array();
        $this->normalizeKeys = true;
    }

    /**
     * Sets a custom children builder.
     *
     * @param NodeBuilder $builder A custom NodeBuilder
     */
    public function setBuilder(NodeBuilder $builder)
    {
        $this->nodeBuilder = $builder;
    }

    /**
     * Returns a builder to add children nodes.
     *
     * @return NodeBuilder
     */
    public function children()
    {
        return $this->getNodeBuilder();
    }

    /**
     * Sets a prototype for child nodes.
     *
     * @param string $type the type of node
     *
     * @return NodeDefinition
     */
    public function prototype($type)
    {
        return $this->prototype = $this->getNodeBuilder()->node(null, $type)->setParent($this);
    }

    /**
     * Adds the default value if the node is not set in the configuration.
     *
     * This method is applicable to concrete nodes only (not to prototype nodes).
     * If this function has been called and the node is not set during the finalization
     * phase, it's default value will be derived from its children default values.
     *
     * @return ArrayNodeDefinition
     */
    public function addDefaultsIfNotSet()
    {
        $this->addDefaults = true;

        return $this;
    }

    /**
     * Adds children with a default value when none are defined.
     *
     * @param integer|string|array|null $children The number of children|The child name|The children names to be added
     *
     * This method is applicable to prototype nodes only.
     *
     * @return ArrayNodeDefinition
     */
    public function addDefaultChildrenIfNoneSet($children = null)
    {
        $this->addDefaultChildren = $children;

        return $this;
    }

    /**
     * Requires the node to have at least one element.
     *
     * This method is applicable to prototype nodes only.
     *
     * @return ArrayNodeDefinition
     */
    public function requiresAtLeastOneElement()
    {
        $this->atLeastOne = true;

        return $this;
    }

    /**
     * Disallows adding news keys in a subsequent configuration.
     *
     * If used all keys have to be defined in the same configuration file.
     *
     * @return ArrayNodeDefinition
     */
    public function disallowNewKeysInSubsequentConfigs()
    {
        $this->allowNewKeys = false;

        return $this;
    }

    /**
     * Sets a normalization rule for XML configurations.
     *
     * @param string $singular The key to remap
     * @param string $plural   The plural of the key for irregular plurals
     *
     * @return ArrayNodeDefinition
     */
    public function fixXmlConfig($singular, $plural = null)
    {
        $this->normalization()->remap($singular, $plural);

        return $this;
    }

    /**
     * Sets the attribute which value is to be used as key.
     *
     * This is useful when you have an indexed array that should be an
     * associative array. You can select an item from within the array
     * to be the key of the particular item. For example, if "id" is the
     * "key", then:
     *
     *     array(
     *         array('id' => 'my_name', 'foo' => 'bar'),
     *     );
     *
     *   becomes
     *
     *     array(
     *         'my_name' => array('foo' => 'bar'),
     *     );
     *
     * If you'd like "'id' => 'my_name'" to still be present in the resulting
     * array, then you can set the second argument of this method to false.
     *
     * This method is applicable to prototype nodes only.
     *
     * @param string  $name          The name of the key
     * @param Boolean $removeKeyItem Whether or not the key item should be removed.
     *
     * @return ArrayNodeDefinition
     */
    public function useAttributeAsKey($name, $removeKeyItem = true)
    {
        $this->key = $name;
        $this->removeKeyItem = $removeKeyItem;

        return $this;
    }

    /**
     * Sets whether the node can be unset.
     *
     * @param Boolean $allow
     *
     * @return ArrayNodeDefinition
     */
    public function canBeUnset($allow = true)
    {
        $this->merge()->allowUnset($allow);

        return $this;
    }

    /**
     * Adds an "enabled" boolean to enable the current section.
     *
     * By default, the section is disabled. If any configuration is specified then
     * the node will be automatically enabled:
     *
     * enableableArrayNode: {enabled: true, ...}   # The config is enabled & default values get overridden
     * enableableArrayNode: ~                      # The config is enabled & use the default values
     * enableableArrayNode: true                   # The config is enabled & use the default values
     * enableableArrayNode: {other: value, ...}    # The config is enabled & default values get overridden
     * enableableArrayNode: {enabled: false, ...}  # The config is disabled
     * enableableArrayNode: false                  # The config is disabled
     *
     * @return ArrayNodeDefinition
     */
    public function canBeEnabled()
    {
        $this
            ->addDefaultsIfNotSet()
            ->treatFalseLike(array('enabled' => false))
            ->treatTrueLike(array('enabled' => true))
            ->treatNullLike(array('enabled' => true))
            ->beforeNormalization()
                ->ifArray()
                ->then(function($v) {
                    $v['enabled'] = isset($v['enabled']) ? $v['enabled'] : true;

                    return $v;
                })
            ->end()
            ->children()
                ->booleanNode('enabled')
                    ->defaultFalse()
        ;

        return $this;
    }

    /**
     * Adds an "enabled" boolean to enable the current section.
     *
     * By default, the section is enabled.
     *
     * @return ArrayNodeDefinition
     */
    public function canBeDisabled()
    {
        $this
            ->addDefaultsIfNotSet()
            ->treatFalseLike(array('enabled' => false))
            ->treatTrueLike(array('enabled' => true))
            ->treatNullLike(array('enabled' => true))
            ->children()
                ->booleanNode('enabled')
                    ->defaultTrue()
        ;

        return $this;
    }

    /**
     * Disables the deep merging of the node.
     *
     * @return ArrayNodeDefinition
     */
    public function performNoDeepMerging()
    {
        $this->performDeepMerging = false;

        return $this;
    }

    /**
     * Allows extra config keys to be specified under an array without
     * throwing an exception.
     *
     * Those config values are simply ignored. This should be used only
     * in special cases where you want to send an entire configuration
     * array through a special tree that processes only part of the array.
     *
     * @return ArrayNodeDefinition
     */
    public function ignoreExtraKeys()
    {
        $this->ignoreExtraKeys = true;

        return $this;
    }

    /**
     * Sets key normalization.
     *
     * @param Boolean $bool Whether to enable key normalization
     *
     * @return ArrayNodeDefinition
     */
    public function normalizeKeys($bool)
    {
        $this->normalizeKeys = (Boolean) $bool;

        return $this;
    }

    /**
     * Appends a node definition.
     *
     *     $node = new ArrayNodeDefinition()
     *         ->children()
     *             ->scalarNode('foo')->end()
     *             ->scalarNode('baz')->end()
     *         ->end()
     *         ->append($this->getBarNodeDefinition())
     *     ;
     *
     * @param NodeDefinition $node A NodeDefinition instance
     *
     * @return ArrayNodeDefinition This node
     */
    public function append(NodeDefinition $node)
    {
        $this->children[$node->name] = $node->setParent($this);

        return $this;
    }

    /**
     * Returns a node builder to be used to add children and prototype
     *
     * @return NodeBuilder The node builder
     */
    protected function getNodeBuilder()
    {
        if (null === $this->nodeBuilder) {
            $this->nodeBuilder = new NodeBuilder();
        }

        return $this->nodeBuilder->setParent($this);
    }

    /**
     * {@inheritDoc}
     */
    protected function createNode()
    {
        if (null === $this->prototype) {
            $node = new ArrayNode($this->name, $this->parent);

            $this->validateConcreteNode($node);

            $node->setAddIfNotSet($this->addDefaults);

            foreach ($this->children as $child) {
                $child->parent = $node;
                $node->addChild($child->getNode());
            }
        } else {
            $node = new PrototypedArrayNode($this->name, $this->parent);

            $this->validatePrototypeNode($node);

            if (null !== $this->key) {
                $node->setKeyAttribute($this->key, $this->removeKeyItem);
            }

            if (true === $this->atLeastOne) {
                $node->setMinNumberOfElements(1);
            }

            if ($this->default) {
                $node->setDefaultValue($this->defaultValue);
            }

            if (false !== $this->addDefaultChildren) {
                $node->setAddChildrenIfNoneSet($this->addDefaultChildren);
                if ($this->prototype instanceof static && null === $this->prototype->prototype) {
                    $this->prototype->addDefaultsIfNotSet();
                }
            }

            $this->prototype->parent = $node;
            $node->setPrototype($this->prototype->getNode());
        }

        $node->setAllowNewKeys($this->allowNewKeys);
        $node->addEquivalentValue(null, $this->nullEquivalent);
        $node->addEquivalentValue(true, $this->trueEquivalent);
        $node->addEquivalentValue(false, $this->falseEquivalent);
        $node->setPerformDeepMerging($this->performDeepMerging);
        $node->setRequired($this->required);
        $node->setIgnoreExtraKeys($this->ignoreExtraKeys);
        $node->setNormalizeKeys($this->normalizeKeys);

        if (null !== $this->normalization) {
            $node->setNormalizationClosures($this->normalization->before);
            $node->setXmlRemappings($this->normalization->remappings);
        }

        if (null !== $this->merge) {
            $node->setAllowOverwrite($this->merge->allowOverwrite);
            $node->setAllowFalse($this->merge->allowFalse);
        }

        if (null !== $this->validation) {
            $node->setFinalValidationClosures($this->validation->rules);
        }

        return $node;
    }

    /**
     * Validate the configuration of a concrete node.
     *
     * @param ArrayNode $node The related node
     *
     * @throws InvalidDefinitionException
     */
    protected function validateConcreteNode(ArrayNode $node)
    {
        $path = $node->getPath();

        if (null !== $this->key) {
            throw new InvalidDefinitionException(
                sprintf('->useAttributeAsKey() is not applicable to concrete nodes at path "%s"', $path)
            );
        }

        if (true === $this->atLeastOne) {
            throw new InvalidDefinitionException(
                sprintf('->requiresAtLeastOneElement() is not applicable to concrete nodes at path "%s"', $path)
            );
        }

        if ($this->default) {
            throw new InvalidDefinitionException(
                sprintf('->defaultValue() is not applicable to concrete nodes at path "%s"', $path)
            );
        }

        if (false !== $this->addDefaultChildren) {
            throw new InvalidDefinitionException(
                sprintf('->addDefaultChildrenIfNoneSet() is not applicable to concrete nodes at path "%s"', $path)
            );
        }
    }

    /**
     * Validate the configuration of a prototype node.
     *
     * @param PrototypedArrayNode $node The related node
     *
     * @throws InvalidDefinitionException
     */
    protected function validatePrototypeNode(PrototypedArrayNode $node)
    {
        $path = $node->getPath();

        if ($this->addDefaults) {
            throw new InvalidDefinitionException(
                sprintf('->addDefaultsIfNotSet() is not applicable to prototype nodes at path "%s"', $path)
            );
        }

        if (false !== $this->addDefaultChildren) {
            if ($this->default) {
                throw new InvalidDefinitionException(
                    sprintf('A default value and default children might not be used together at path "%s"', $path)
                );
            }

            if (null !== $this->key && (null === $this->addDefaultChildren || is_integer($this->addDefaultChildren) && $this->addDefaultChildren > 0)) {
                throw new InvalidDefinitionException(
                    sprintf('->addDefaultChildrenIfNoneSet() should set default children names as ->useAttributeAsKey() is used at path "%s"', $path)
                );
            }

            if (null === $this->key && (is_string($this->addDefaultChildren) || is_array($this->addDefaultChildren))) {
                throw new InvalidDefinitionException(
                    sprintf('->addDefaultChildrenIfNoneSet() might not set default children names as ->useAttributeAsKey() is not used at path "%s"', $path)
                );
            }
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Builder;
use Symfony\Component\Config\Definition\Exception\UnsetKeyException;

/**
 * This class builds an if expression.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 * @author Christophe Coevoet <stof@notk.org>
 */
class ExprBuilder
{
    protected $node;
    public $ifPart;
    public $thenPart;

    /**
     * Constructor
     *
     * @param NodeDefinition $node The related node
     */
    public function __construct(NodeDefinition $node)
    {
        $this->node = $node;
    }

    /**
     * Marks the expression as being always used.
     *
     * @param \Closure $then
     *
     * @return ExprBuilder
     */
    public function always(\Closure $then = null)
    {
        $this->ifPart = function($v) { return true; };

        if (null !== $then) {
            $this->thenPart = $then;
        }

        return $this;
    }

    /**
     * Sets a closure to use as tests.
     *
     * The default one tests if the value is true.
     *
     * @param \Closure $closure
     *
     * @return ExprBuilder
     */
    public function ifTrue(\Closure $closure = null)
    {
        if (null === $closure) {
            $closure = function($v) { return true === $v; };
        }

        $this->ifPart = $closure;

        return $this;
    }

    /**
     * Tests if the value is a string.
     *
     * @return ExprBuilder
     */
    public function ifString()
    {
        $this->ifPart = function($v) { return is_string($v); };

        return $this;
    }

    /**
     * Tests if the value is null.
     *
     * @return ExprBuilder
     */
    public function ifNull()
    {
        $this->ifPart = function($v) { return null === $v; };

        return $this;
    }

    /**
     * Tests if the value is an array.
     *
     * @return ExprBuilder
     */
    public function ifArray()
    {
        $this->ifPart = function($v) { return is_array($v); };

        return $this;
    }

    /**
     * Tests if the value is in an array.
     *
     * @param array $array
     *
     * @return ExprBuilder
     */
    public function ifInArray(array $array)
    {
        $this->ifPart = function($v) use ($array) { return in_array($v, $array, true); };

        return $this;
    }

    /**
     * Tests if the value is not in an array.
     *
     * @param array $array
     *
     * @return ExprBuilder
     */
    public function ifNotInArray(array $array)
    {
        $this->ifPart = function($v) use ($array) { return !in_array($v, $array, true); };

        return $this;
    }

    /**
     * Sets the closure to run if the test pass.
     *
     * @param \Closure $closure
     *
     * @return ExprBuilder
     */
    public function then(\Closure $closure)
    {
        $this->thenPart = $closure;

        return $this;
    }

    /**
     * Sets a closure returning an empty array.
     *
     * @return ExprBuilder
     */
    public function thenEmptyArray()
    {
        $this->thenPart = function($v) { return array(); };

        return $this;
    }

    /**
     * Sets a closure marking the value as invalid at validation time.
     *
     * if you want to add the value of the node in your message just use a %s placeholder.
     *
     * @param string $message
     *
     * @return ExprBuilder
     *
     * @throws \InvalidArgumentException
     */
    public function thenInvalid($message)
    {
        $this->thenPart = function ($v) use ($message) {throw new \InvalidArgumentException(sprintf($message, json_encode($v))); };

        return $this;
    }

    /**
     * Sets a closure unsetting this key of the array at validation time.
     *
     * @return ExprBuilder
     *
     * @throws UnsetKeyException
     */
    public function thenUnset()
    {
        $this->thenPart = function ($v) { throw new UnsetKeyException('Unsetting key'); };

        return $this;
    }

    /**
     * Returns the related node
     *
     * @return NodeDefinition
     *
     * @throws \RuntimeException
     */
    public function end()
    {
        if (null === $this->ifPart) {
            throw new \RuntimeException('You must specify an if part.');
        }
        if (null === $this->thenPart) {
            throw new \RuntimeException('You must specify a then part.');
        }

        return $this->node;
    }

    /**
     * Builds the expressions.
     *
     * @param ExprBuilder[] $expressions An array of ExprBuilder instances to build
     *
     * @return array
     */
    public static function buildExpressions(array $expressions)
    {
        foreach ($expressions as $k => $expr) {
            if ($expr instanceof ExprBuilder) {
                $expressions[$k] = function($v) use ($expr) {
                    return call_user_func($expr->ifPart, $v) ? call_user_func($expr->thenPart, $v) : $v;
                };
            }
        }

        return $expressions;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Builder;

/**
 * Abstract class that contain common code of integer and float node definition.
 *
 * @author David Jeanmonod <david.jeanmonod@gmail.com>
 */
abstract class NumericNodeDefinition extends ScalarNodeDefinition
{
    protected $min;
    protected $max;

    /**
     * Ensures that the value is smaller than the given reference.
     *
     * @param mixed $max
     *
     * @return NumericNodeDefinition
     *
     * @throws \InvalidArgumentException when the constraint is inconsistent
     */
    public function max($max)
    {
        if (isset($this->min) && $this->min > $max) {
            throw new \InvalidArgumentException(sprintf('You cannot define a max(%s) as you already have a min(%s)', $max, $this->min));
        }
        $this->max = $max;

        return $this;
    }

    /**
     * Ensures that the value is bigger than the given reference.
     *
     * @param mixed $min
     *
     * @return NumericNodeDefinition
     *
     * @throws \InvalidArgumentException when the constraint is inconsistent
     */
    public function min($min)
    {
        if (isset($this->max) && $this->max < $min) {
            throw new \InvalidArgumentException(sprintf('You cannot define a min(%s) as you already have a max(%s)', $min, $this->max));
        }
        $this->min = $min;

        return $this;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Builder;

/**
 * This class builds merge conditions.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class MergeBuilder
{
    protected $node;
    public $allowFalse;
    public $allowOverwrite;

    /**
     * Constructor
     *
     * @param NodeDefinition $node The related node
     */
    public function __construct(NodeDefinition $node)
    {
        $this->node = $node;
        $this->allowFalse = false;
        $this->allowOverwrite = true;
    }

    /**
     * Sets whether the node can be unset.
     *
     * @param Boolean $allow
     *
     * @return MergeBuilder
     */
    public function allowUnset($allow = true)
    {
        $this->allowFalse = $allow;

        return $this;
    }

    /**
     * Sets whether the node can be overwritten.
     *
     * @param Boolean $deny Whether the overwriting is forbidden or not
     *
     * @return MergeBuilder
     */
    public function denyOverwrite($deny = true)
    {
        $this->allowOverwrite = !$deny;

        return $this;
    }

    /**
     * Returns the related node.
     *
     * @return NodeDefinition
     */
    public function end()
    {
        return $this->node;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Builder;

use Symfony\Component\Config\Definition\IntegerNode;

/**
 * This class provides a fluent interface for defining an integer node.
 *
 * @author Jeanmonod David <david.jeanmonod@gmail.com>
 */
class IntegerNodeDefinition extends NumericNodeDefinition
{
    /**
     * Instantiates a Node.
     *
     * @return IntegerNode The node
     */
    protected function instantiateNode()
    {
        return new IntegerNode($this->name, $this->parent, $this->min, $this->max);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Builder;

use Symfony\Component\Config\Definition\BooleanNode;

/**
 * This class provides a fluent interface for defining a node.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class BooleanNodeDefinition extends ScalarNodeDefinition
{
    /**
     * {@inheritDoc}
     */
    public function __construct($name, NodeParentInterface $parent = null)
    {
        parent::__construct($name, $parent);

        $this->nullEquivalent = true;
    }

    /**
     * Instantiate a Node
     *
     * @return BooleanNode The node
     */
    protected function instantiateNode()
    {
        return new BooleanNode($this->name, $this->parent);
    }

}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Builder;

use Symfony\Component\Config\Definition\NodeInterface;

/**
 * This is the entry class for building a config tree.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class TreeBuilder implements NodeParentInterface
{
    protected $tree;
    protected $root;
    protected $builder;

    /**
     * Creates the root node.
     *
     * @param string      $name    The name of the root node
     * @param string      $type    The type of the root node
     * @param NodeBuilder $builder A custom node builder instance
     *
     * @return ArrayNodeDefinition|NodeDefinition The root node (as an ArrayNodeDefinition when the type is 'array')
     *
     * @throws \RuntimeException When the node type is not supported
     */
    public function root($name, $type = 'array', NodeBuilder $builder = null)
    {
        $builder = $builder ?: new NodeBuilder();

        return $this->root = $builder->node($name, $type)->setParent($this);
    }

    /**
     * Builds the tree.
     *
     * @return NodeInterface
     *
     * @throws \RuntimeException
     */
    public function buildTree()
    {
        if (null === $this->root) {
            throw new \RuntimeException('The configuration tree has no root node.');
        }
        if (null !== $this->tree) {
            return $this->tree;
        }

        return $this->tree = $this->root->getNode(true);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Builder;

use Symfony\Component\Config\Definition\FloatNode;

/**
 * This class provides a fluent interface for defining a float node.
 *
 * @author Jeanmonod David <david.jeanmonod@gmail.com>
 */
class FloatNodeDefinition extends NumericNodeDefinition
{
    /**
     * Instantiates a Node.
     *
     * @return FloatNode The node
     */
    protected function instantiateNode()
    {
        return new FloatNode($this->name, $this->parent, $this->min, $this->max);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Builder;

use Symfony\Component\Config\Definition\ScalarNode;

/**
 * This class provides a fluent interface for defining a node.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ScalarNodeDefinition extends VariableNodeDefinition
{
    /**
     * Instantiate a Node
     *
     * @return ScalarNode The node
     */
    protected function instantiateNode()
    {
        return new ScalarNode($this->name, $this->parent);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Builder;

use Symfony\Component\Config\Definition\EnumNode;
use Symfony\Component\Config\Definition\Builder\ScalarNodeDefinition;

/**
 * Enum Node Definition.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class EnumNodeDefinition extends ScalarNodeDefinition
{
    private $values;

    public function values(array $values)
    {
        $values = array_unique($values);

        if (count($values) <= 1) {
            throw new \InvalidArgumentException('->values() must be called with at least two distinct values.');
        }

        $this->values = $values;

        return $this;
    }

    /**
     * Instantiate a Node
     *
     * @return EnumNode The node
     *
     * @throws \RuntimeException
     */
    protected function instantiateNode()
    {
        if (null === $this->values) {
            throw new \RuntimeException('You must call ->values() on enum nodes.');
        }

        return new EnumNode($this->name, $this->parent, $this->values);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Builder;

/**
 * An interface that must be implemented by nodes which can have children
 *
 * @author Victor Berchet <victor@suumit.com>
 */
interface ParentNodeDefinitionInterface
{
    public function children();

    public function append(NodeDefinition $node);

    public function setBuilder(NodeBuilder $builder);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition\Builder;

/**
 * This class builds normalization conditions.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class NormalizationBuilder
{
    protected $node;
    public $before;
    public $remappings;

    /**
     * Constructor
     *
     * @param NodeDefinition $node The related node
     */
    public function __construct(NodeDefinition $node)
    {
        $this->node = $node;
        $this->keys = false;
        $this->remappings = array();
        $this->before = array();
    }

    /**
     * Registers a key to remap to its plural form.
     *
     * @param string $key    The key to remap
     * @param string $plural The plural of the key in case of irregular plural
     *
     * @return NormalizationBuilder
     */
    public function remap($key, $plural = null)
    {
        $this->remappings[] = array($key, null === $plural ? $key.'s' : $plural);

        return $this;
    }

    /**
     * Registers a closure to run before the normalization or an expression builder to build it if null is provided.
     *
     * @param \Closure $closure
     *
     * @return ExprBuilder|NormalizationBuilder
     */
    public function before(\Closure $closure = null)
    {
        if (null !== $closure) {
            $this->before[] = $closure;

            return $this;
        }

        return $this->before[] = new ExprBuilder($this->node);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition;

use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\Definition\Exception\DuplicateKeyException;
use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
use Symfony\Component\Config\Definition\Exception\Exception;

/**
 * Represents a prototyped Array node in the config tree.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class PrototypedArrayNode extends ArrayNode
{
    protected $prototype;
    protected $keyAttribute;
    protected $removeKeyAttribute;
    protected $minNumberOfElements;
    protected $defaultValue;
    protected $defaultChildren;

    /**
     * Constructor.
     *
     * @param string        $name   The Node's name
     * @param NodeInterface $parent The node parent
     */
    public function __construct($name, NodeInterface $parent = null)
    {
        parent::__construct($name, $parent);

        $this->minNumberOfElements = 0;
        $this->defaultValue = array();
    }

    /**
     * Sets the minimum number of elements that a prototype based node must
     * contain. By default this is zero, meaning no elements.
     *
     * @param integer $number
     */
    public function setMinNumberOfElements($number)
    {
        $this->minNumberOfElements = $number;
    }

    /**
     * Sets the attribute which value is to be used as key.
     *
     * This is useful when you have an indexed array that should be an
     * associative array. You can select an item from within the array
     * to be the key of the particular item. For example, if "id" is the
     * "key", then:
     *
     *     array(
     *         array('id' => 'my_name', 'foo' => 'bar'),
     *     );
     *
     *  becomes
     *
     *      array(
     *          'my_name' => array('foo' => 'bar'),
     *      );
     *
     * If you'd like "'id' => 'my_name'" to still be present in the resulting
     * array, then you can set the second argument of this method to false.
     *
     * @param string  $attribute The name of the attribute which value is to be used as a key
     * @param Boolean $remove    Whether or not to remove the key
     */
    public function setKeyAttribute($attribute, $remove = true)
    {
        $this->keyAttribute = $attribute;
        $this->removeKeyAttribute = $remove;
    }

    /**
     * Retrieves the name of the attribute which value should be used as key.
     *
     * @return string The name of the attribute
     */
    public function getKeyAttribute()
    {
        return $this->keyAttribute;
    }

    /**
     * Sets the default value of this node.
     *
     * @param string $value
     *
     * @throws \InvalidArgumentException if the default value is not an array
     */
    public function setDefaultValue($value)
    {
        if (!is_array($value)) {
            throw new \InvalidArgumentException($this->getPath().': the default value of an array node has to be an array.');
        }

        $this->defaultValue = $value;
    }

    /**
     * Checks if the node has a default value.
     *
     * @return Boolean
     */
    public function hasDefaultValue()
    {
        return true;
    }

    /**
     * Adds default children when none are set.
     *
     * @param integer|string|array|null $children The number of children|The child name|The children names to be added
     */
    public function setAddChildrenIfNoneSet($children = array('defaults'))
    {
        if (null === $children) {
            $this->defaultChildren = array('defaults');
        } else {
            $this->defaultChildren = is_integer($children) && $children > 0 ? range(1, $children) : (array) $children;
        }
    }

    /**
     * Retrieves the default value.
     *
     * The default value could be either explicited or derived from the prototype
     * default value.
     *
     * @return array The default value
     */
    public function getDefaultValue()
    {
        if (null !== $this->defaultChildren) {
            $default = $this->prototype->hasDefaultValue() ? $this->prototype->getDefaultValue() : array();
            $defaults = array();
            foreach (array_values($this->defaultChildren) as $i => $name) {
                $defaults[null === $this->keyAttribute ? $i : $name] = $default;
            }

            return $defaults;
        }

        return $this->defaultValue;
    }

    /**
     * Sets the node prototype.
     *
     * @param PrototypeNodeInterface $node
     */
    public function setPrototype(PrototypeNodeInterface $node)
    {
        $this->prototype = $node;
    }

    /**
     * Retrieves the prototype
     *
     * @return PrototypeNodeInterface The prototype
     */
    public function getPrototype()
    {
        return $this->prototype;
    }

    /**
     * Disable adding concrete children for prototyped nodes.
     *
     * @param NodeInterface $node The child node to add
     *
     * @throws Exception
     */
    public function addChild(NodeInterface $node)
    {
        throw new Exception('A prototyped array node can not have concrete children.');
    }

    /**
     * Finalizes the value of this node.
     *
     * @param mixed $value
     *
     * @return mixed The finalized value
     *
     * @throws UnsetKeyException
     * @throws InvalidConfigurationException if the node doesn't have enough children
     */
    protected function finalizeValue($value)
    {
        if (false === $value) {
            $msg = sprintf('Unsetting key for path "%s", value: %s', $this->getPath(), json_encode($value));
            throw new UnsetKeyException($msg);
        }

        foreach ($value as $k => $v) {
            $this->prototype->setName($k);
            try {
                $value[$k] = $this->prototype->finalize($v);
            } catch (UnsetKeyException $unset) {
                unset($value[$k]);
            }
        }

        if (count($value) < $this->minNumberOfElements) {
            $msg = sprintf('The path "%s" should have at least %d element(s) defined.', $this->getPath(), $this->minNumberOfElements);
            $ex = new InvalidConfigurationException($msg);
            $ex->setPath($this->getPath());

            throw $ex;
        }

        return $value;
    }

    /**
     * Normalizes the value.
     *
     * @param mixed $value The value to normalize
     *
     * @return mixed The normalized value
     *
     * @throws InvalidConfigurationException
     * @throws DuplicateKeyException
     */
    protected function normalizeValue($value)
    {
        if (false === $value) {
            return $value;
        }

        $value = $this->remapXml($value);

        $isAssoc = array_keys($value) !== range(0, count($value) -1);
        $normalized = array();
        foreach ($value as $k => $v) {
            if (null !== $this->keyAttribute && is_array($v)) {
                if (!isset($v[$this->keyAttribute]) && is_int($k) && !$isAssoc) {
                    $msg = sprintf('The attribute "%s" must be set for path "%s".', $this->keyAttribute, $this->getPath());
                    $ex = new InvalidConfigurationException($msg);
                    $ex->setPath($this->getPath());

                    throw $ex;
                } elseif (isset($v[$this->keyAttribute])) {
                    $k = $v[$this->keyAttribute];

                    // remove the key attribute when required
                    if ($this->removeKeyAttribute) {
                        unset($v[$this->keyAttribute]);
                    }

                    // if only "value" is left
                    if (1 == count($v) && isset($v['value'])) {
                        $v = $v['value'];
                    }
                }

                if (array_key_exists($k, $normalized)) {
                    $msg = sprintf('Duplicate key "%s" for path "%s".', $k, $this->getPath());
                    $ex = new DuplicateKeyException($msg);
                    $ex->setPath($this->getPath());

                    throw $ex;
                }
            }

            $this->prototype->setName($k);
            if (null !== $this->keyAttribute || $isAssoc) {
                $normalized[$k] = $this->prototype->normalize($v);
            } else {
                $normalized[] = $this->prototype->normalize($v);
            }
        }

        return $normalized;
    }

    /**
     * Merges values together.
     *
     * @param mixed $leftSide  The left side to merge.
     * @param mixed $rightSide The right side to merge.
     *
     * @return mixed The merged values
     *
     * @throws InvalidConfigurationException
     * @throws \RuntimeException
     */
    protected function mergeValues($leftSide, $rightSide)
    {
        if (false === $rightSide) {
            // if this is still false after the last config has been merged the
            // finalization pass will take care of removing this key entirely
            return false;
        }

        if (false === $leftSide || !$this->performDeepMerging) {
            return $rightSide;
        }

        foreach ($rightSide as $k => $v) {
            // prototype, and key is irrelevant, so simply append the element
            if (null === $this->keyAttribute) {
                $leftSide[] = $v;
                continue;
            }

            // no conflict
            if (!array_key_exists($k, $leftSide)) {
                if (!$this->allowNewKeys) {
                    $ex = new InvalidConfigurationException(sprintf(
                        'You are not allowed to define new elements for path "%s". ' .
                        'Please define all elements for this path in one config file.',
                        $this->getPath()
                    ));
                    $ex->setPath($this->getPath());

                    throw $ex;
                }

                $leftSide[$k] = $v;
                continue;
            }

            $this->prototype->setName($k);
            $leftSide[$k] = $this->prototype->merge($leftSide[$k], $v);
        }

        return $leftSide;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition;

use Symfony\Component\Config\Definition\Exception\InvalidTypeException;

/**
 * This node represents a float value in the config tree.
 *
 * @author Jeanmonod David <david.jeanmonod@gmail.com>
 */
class FloatNode extends NumericNode
{
    /**
     * {@inheritDoc}
     */
    protected function validateType($value)
    {
        // Integers are also accepted, we just cast them
        if (is_int($value)) {
            $value = (float) $value;
        }

        if (!is_float($value)) {
            $ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected float, but got %s.', $this->getPath(), gettype($value)));
            $ex->setPath($this->getPath());

            throw $ex;
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition;

use Symfony\Component\Config\Definition\Exception\Exception;
use Symfony\Component\Config\Definition\Exception\ForbiddenOverwriteException;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;

/**
 * The base node class
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
abstract class BaseNode implements NodeInterface
{
    protected $name;
    protected $parent;
    protected $normalizationClosures;
    protected $finalValidationClosures;
    protected $allowOverwrite;
    protected $required;
    protected $equivalentValues;
    protected $attributes = array();

    /**
     * Constructor.
     *
     * @param string        $name   The name of the node
     * @param NodeInterface $parent The parent of this node
     *
     * @throws \InvalidArgumentException if the name contains a period.
     */
    public function __construct($name, NodeInterface $parent = null)
    {
        if (false !== strpos($name, '.')) {
            throw new \InvalidArgumentException('The name must not contain ".".');
        }

        $this->name = $name;
        $this->parent = $parent;
        $this->normalizationClosures = array();
        $this->finalValidationClosures = array();
        $this->allowOverwrite = true;
        $this->required = false;
        $this->equivalentValues = array();
    }

    public function setAttribute($key, $value)
    {
        $this->attributes[$key] = $value;
    }

    public function getAttribute($key, $default = null)
    {
        return isset($this->attributes[$key]) ? $this->attributes[$key] : $default;
    }

    public function hasAttribute($key)
    {
        return isset($this->attributes[$key]);
    }

    public function getAttributes()
    {
        return $this->attributes;
    }

    public function setAttributes(array $attributes)
    {
        $this->attributes = $attributes;
    }

    public function removeAttribute($key)
    {
        unset($this->attributes[$key]);
    }

    /**
     * Sets an info message.
     *
     * @param string $info
     */
    public function setInfo($info)
    {
        $this->setAttribute('info', $info);
    }

    /**
     * Returns info message.
     *
     * @return string The info text
     */
    public function getInfo()
    {
        return $this->getAttribute('info');
    }

    /**
     * Sets the example configuration for this node.
     *
     * @param string|array $example
     */
    public function setExample($example)
    {
        $this->setAttribute('example', $example);
    }

    /**
     * Retrieves the example configuration for this node.
     *
     * @return string|array The example
     */
    public function getExample()
    {
        return $this->getAttribute('example');
    }

    /**
     * Adds an equivalent value.
     *
     * @param mixed $originalValue
     * @param mixed $equivalentValue
     */
    public function addEquivalentValue($originalValue, $equivalentValue)
    {
        $this->equivalentValues[] = array($originalValue, $equivalentValue);
    }

    /**
     * Set this node as required.
     *
     * @param Boolean $boolean Required node
     */
    public function setRequired($boolean)
    {
        $this->required = (Boolean) $boolean;
    }

    /**
     * Sets if this node can be overridden.
     *
     * @param Boolean $allow
     */
    public function setAllowOverwrite($allow)
    {
        $this->allowOverwrite = (Boolean) $allow;
    }

    /**
     * Sets the closures used for normalization.
     *
     * @param \Closure[] $closures An array of Closures used for normalization
     */
    public function setNormalizationClosures(array $closures)
    {
        $this->normalizationClosures = $closures;
    }

    /**
     * Sets the closures used for final validation.
     *
     * @param \Closure[] $closures An array of Closures used for final validation
     */
    public function setFinalValidationClosures(array $closures)
    {
        $this->finalValidationClosures = $closures;
    }

    /**
     * Checks if this node is required.
     *
     * @return Boolean
     */
    public function isRequired()
    {
        return $this->required;
    }

    /**
     * Returns the name of this node
     *
     * @return string The Node's name.
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Retrieves the path of this node.
     *
     * @return string The Node's path
     */
    public function getPath()
    {
        $path = $this->name;

        if (null !== $this->parent) {
            $path = $this->parent->getPath().'.'.$path;
        }

        return $path;
    }

    /**
     * Merges two values together.
     *
     * @param mixed $leftSide
     * @param mixed $rightSide
     *
     * @return mixed The merged value
     *
     * @throws ForbiddenOverwriteException
     */
    final public function merge($leftSide, $rightSide)
    {
        if (!$this->allowOverwrite) {
            throw new ForbiddenOverwriteException(sprintf(
                'Configuration path "%s" cannot be overwritten. You have to '
               .'define all options for this path, and any of its sub-paths in '
               .'one configuration section.',
                $this->getPath()
            ));
        }

        $this->validateType($leftSide);
        $this->validateType($rightSide);

        return $this->mergeValues($leftSide, $rightSide);
    }

    /**
     * Normalizes a value, applying all normalization closures.
     *
     * @param mixed $value Value to normalize.
     *
     * @return mixed The normalized value.
     */
    final public function normalize($value)
    {
        $value = $this->preNormalize($value);

        // run custom normalization closures
        foreach ($this->normalizationClosures as $closure) {
            $value = $closure($value);
        }

        // replace value with their equivalent
        foreach ($this->equivalentValues as $data) {
            if ($data[0] === $value) {
                $value = $data[1];
            }
        }

        // validate type
        $this->validateType($value);

        // normalize value
        return $this->normalizeValue($value);
    }

    /**
     * Normalizes the value before any other normalization is applied.
     *
     * @param $value
     *
     * @return $value The normalized array value
     */
    protected function preNormalize($value)
    {
        return $value;
    }

    /**
     * Finalizes a value, applying all finalization closures.
     *
     * @param mixed $value The value to finalize
     *
     * @return mixed The finalized value
     *
     * @throws InvalidConfigurationException
     */
    final public function finalize($value)
    {
        $this->validateType($value);

        $value = $this->finalizeValue($value);

        // Perform validation on the final value if a closure has been set.
        // The closure is also allowed to return another value.
        foreach ($this->finalValidationClosures as $closure) {
            try {
                $value = $closure($value);
            } catch (Exception $correctEx) {
                throw $correctEx;
            } catch (\Exception $invalid) {
                throw new InvalidConfigurationException(sprintf(
                    'Invalid configuration for path "%s": %s',
                    $this->getPath(),
                    $invalid->getMessage()
                ), $invalid->getCode(), $invalid);
            }
        }

        return $value;
    }

    /**
     * Validates the type of a Node.
     *
     * @param mixed $value The value to validate
     *
     * @throws InvalidTypeException when the value is invalid
     */
    abstract protected function validateType($value);

    /**
     * Normalizes the value.
     *
     * @param mixed $value The value to normalize.
     *
     * @return mixed The normalized value
     */
    abstract protected function normalizeValue($value);

    /**
     * Merges two values together.
     *
     * @param mixed $leftSide
     * @param mixed $rightSide
     *
     * @return mixed The merged value
     */
    abstract protected function mergeValues($leftSide, $rightSide);

    /**
     * Finalizes a value.
     *
     * @param mixed $value The value to finalize
     *
     * @return mixed The finalized value
     */
    abstract protected function finalizeValue($value);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition;

use Symfony\Component\Config\Definition\VariableNode;
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;

/**
 * This node represents a scalar value in the config tree.
 *
 * The following values are considered scalars:
 *   * booleans
 *   * strings
 *   * null
 *   * integers
 *   * floats
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ScalarNode extends VariableNode
{
    /**
     * {@inheritDoc}
     */
    protected function validateType($value)
    {
        if (!is_scalar($value) && null !== $value) {
            $ex = new InvalidTypeException(sprintf(
                'Invalid type for path "%s". Expected scalar, but got %s.',
                $this->getPath(),
                gettype($value)
            ));
            $ex->setPath($this->getPath());

            throw $ex;
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition;

/**
 * This class is the entry point for config normalization/merging/finalization.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class Processor
{
    /**
     * Processes an array of configurations.
     *
     * @param NodeInterface $configTree The node tree describing the configuration
     * @param array         $configs    An array of configuration items to process
     *
     * @return array The processed configuration
     */
    public function process(NodeInterface $configTree, array $configs)
    {
        $currentConfig = array();
        foreach ($configs as $config) {
            $config = $configTree->normalize($config);
            $currentConfig = $configTree->merge($currentConfig, $config);
        }

        return $configTree->finalize($currentConfig);
    }

    /**
     * Processes an array of configurations.
     *
     * @param ConfigurationInterface $configuration The configuration class
     * @param array                  $configs       An array of configuration items to process
     *
     * @return array The processed configuration
     */
    public function processConfiguration(ConfigurationInterface $configuration, array $configs)
    {
        return $this->process($configuration->getConfigTreeBuilder()->buildTree(), $configs);
    }

    /**
     * Normalizes a configuration entry.
     *
     * This method returns a normalize configuration array for a given key
     * to remove the differences due to the original format (YAML and XML mainly).
     *
     * Here is an example.
     *
     * The configuration in XML:
     *
     * <twig:extension>twig.extension.foo</twig:extension>
     * <twig:extension>twig.extension.bar</twig:extension>
     *
     * And the same configuration in YAML:
     *
     * extensions: ['twig.extension.foo', 'twig.extension.bar']
     *
     * @param array  $config A config array
     * @param string $key    The key to normalize
     * @param string $plural The plural form of the key if it is irregular
     *
     * @return array
     */
    public static function normalizeConfig($config, $key, $plural = null)
    {
        if (null === $plural) {
            $plural = $key.'s';
        }

        if (isset($config[$plural])) {
            return $config[$plural];
        }

        if (isset($config[$key])) {
            if (is_string($config[$key]) || !is_int(key($config[$key]))) {
                // only one
                return  array($config[$key]);
            }

            return  $config[$key];
        }

        return array();
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition;

/**
 * Common Interface among all nodes.
 *
 * In most cases, it is better to inherit from BaseNode instead of implementing
 * this interface yourself.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
interface NodeInterface
{
    /**
     * Returns the name of the node.
     *
     * @return string The name of the node
     */
    public function getName();

    /**
     * Returns the path of the node.
     *
     * @return string The node path
     */
    public function getPath();

    /**
     * Returns true when the node is required.
     *
     * @return Boolean If the node is required
     */
    public function isRequired();

    /**
     * Returns true when the node has a default value.
     *
     * @return Boolean If the node has a default value
     */
    public function hasDefaultValue();

    /**
     * Returns the default value of the node.
     *
     * @return mixed The default value
     * @throws \RuntimeException if the node has no default value
     */
    public function getDefaultValue();

    /**
     * Normalizes the supplied value.
     *
     * @param mixed $value The value to normalize
     *
     * @return mixed The normalized value
     */
    public function normalize($value);

    /**
     * Merges two values together.
     *
     * @param mixed $leftSide
     * @param mixed $rightSide
     *
     * @return mixed The merged values
     */
    public function merge($leftSide, $rightSide);

    /**
     * Finalizes a value.
     *
     * @param mixed $value The value to finalize
     *
     * @return mixed The finalized value
     */
    public function finalize($value);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition;

use Symfony\Component\Config\Definition\Exception\InvalidTypeException;

/**
 * This node represents an integer value in the config tree.
 *
 * @author Jeanmonod David <david.jeanmonod@gmail.com>
 */
class IntegerNode extends NumericNode
{
    /**
     * {@inheritDoc}
     */
    protected function validateType($value)
    {
        if (!is_int($value)) {
            $ex = new InvalidTypeException(sprintf('Invalid type for path "%s". Expected int, but got %s.', $this->getPath(), gettype($value)));
            $ex->setPath($this->getPath());

            throw $ex;
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition;

/**
 * Dumps a reference configuration for the given configuration/node instance.
 *
 * Currently, only YML format is supported.
 *
 * @author Kevin Bond <kevinbond@gmail.com>
 */
class ReferenceDumper
{
    private $reference;

    public function dump(ConfigurationInterface $configuration)
    {
        return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree());
    }

    public function dumpNode(NodeInterface $node)
    {
        $this->reference = '';
        $this->writeNode($node);
        $ref = $this->reference;
        $this->reference = null;

        return $ref;
    }

    /**
     * @param NodeInterface $node
     * @param integer       $depth
     */
    private function writeNode(NodeInterface $node, $depth = 0)
    {
        $comments = array();
        $default = '';
        $defaultArray = null;
        $children = null;
        $example = $node->getExample();

        // defaults
        if ($node instanceof ArrayNode) {
            $children = $node->getChildren();

            if ($node instanceof PrototypedArrayNode) {
                $prototype = $node->getPrototype();

                if ($prototype instanceof ArrayNode) {
                    $children = $prototype->getChildren();
                }

                // check for attribute as key
                if ($key = $node->getKeyAttribute()) {
                    $keyNode = new ArrayNode($key, $node);
                    $keyNode->setInfo('Prototype');

                    // add children
                    foreach ($children as $childNode) {
                        $keyNode->addChild($childNode);
                    }
                    $children = array($key => $keyNode);
                }
            }

            if (!$children) {
                if ($node->hasDefaultValue() && count($defaultArray = $node->getDefaultValue())) {
                    $default = '';
                } elseif (!is_array($example)) {
                    $default = '[]';
                }
            }
        } else {
            $default = '~';

            if ($node->hasDefaultValue()) {
                $default = $node->getDefaultValue();

                if (true === $default) {
                    $default = 'true';
                } elseif (false === $default) {
                    $default = 'false';
                } elseif (null === $default) {
                    $default = '~';
                } elseif (is_array($default)) {
                    if ($node->hasDefaultValue() && count($defaultArray = $node->getDefaultValue())) {
                        $default = '';
                    } elseif (!is_array($example)) {
                        $default = '[]';
                    }
                }
            }
        }

        // required?
        if ($node->isRequired()) {
            $comments[] = 'Required';
        }

        // example
        if ($example && !is_array($example)) {
            $comments[] = 'Example: '.$example;
        }

        $default = (string) $default != '' ? ' '.$default : '';
        $comments = count($comments) ? '# '.implode(', ', $comments) : '';

        $text = rtrim(sprintf('%-20s %s %s', $node->getName().':', $default, $comments), ' ');

        if ($info = $node->getInfo()) {
            $this->writeLine('');
            // indenting multi-line info
            $info = str_replace("\n", sprintf("\n%".$depth * 4 . "s# ", ' '), $info);
            $this->writeLine('# '.$info, $depth * 4);
        }

        $this->writeLine($text, $depth * 4);

        // output defaults
        if ($defaultArray) {
            $this->writeLine('');

            $message = count($defaultArray) > 1 ? 'Defaults' : 'Default';

            $this->writeLine('# '.$message.':', $depth * 4 + 4);

            $this->writeArray($defaultArray, $depth + 1);
        }

        if (is_array($example)) {
            $this->writeLine('');

            $message = count($example) > 1 ? 'Examples' : 'Example';

            $this->writeLine('# '.$message.':', $depth * 4 + 4);

            $this->writeArray($example, $depth + 1);
        }

        if ($children) {
            foreach ($children as $childNode) {
                $this->writeNode($childNode, $depth + 1);
            }
        }
    }

    /**
     * Outputs a single config reference line
     *
     * @param string $text
     * @param int    $indent
     */
    private function writeLine($text, $indent = 0)
    {
        $indent = strlen($text) + $indent;
        $format = '%'.$indent.'s';

        $this->reference .= sprintf($format, $text)."\n";
    }

    private function writeArray(array $array, $depth)
    {
        $isIndexed = array_values($array) === $array;

        foreach ($array as $key => $value) {
            if (is_array($value)) {
                $val = '';
            } else {
                $val = $value;
            }

            if ($isIndexed) {
                $this->writeLine('- '.$val, $depth * 4);
            } else {
                $this->writeLine(sprintf('%-20s %s', $key.':', $val), $depth * 4);
            }

            if (is_array($value)) {
                $this->writeArray($value, $depth + 1);
            }
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition;

use Symfony\Component\Config\Definition\Exception\InvalidTypeException;

/**
 * This node represents a Boolean value in the config tree.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class BooleanNode extends ScalarNode
{
    /**
     * {@inheritDoc}
     */
    protected function validateType($value)
    {
        if (!is_bool($value)) {
            $ex = new InvalidTypeException(sprintf(
                'Invalid type for path "%s". Expected boolean, but got %s.',
                $this->getPath(),
                gettype($value)
            ));
            $ex->setPath($this->getPath());

            throw $ex;
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition;

/**
 * This interface must be implemented by nodes which can be used as prototypes.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
interface PrototypeNodeInterface extends NodeInterface
{
    /**
     * Sets the name of the node.
     *
     * @param string $name The name of the node
     */
    public function setName($name);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition;

use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
use Symfony\Component\Config\Definition\Exception\UnsetKeyException;

/**
 * Represents an Array node in the config tree.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class ArrayNode extends BaseNode implements PrototypeNodeInterface
{
    protected $xmlRemappings;
    protected $children;
    protected $allowFalse;
    protected $allowNewKeys;
    protected $addIfNotSet;
    protected $performDeepMerging;
    protected $ignoreExtraKeys;
    protected $normalizeKeys;

    /**
     * Constructor.
     *
     * @param string        $name   The Node's name
     * @param NodeInterface $parent The node parent
     */
    public function __construct($name, NodeInterface $parent = null)
    {
        parent::__construct($name, $parent);

        $this->children = array();
        $this->xmlRemappings = array();
        $this->removeKeyAttribute = true;
        $this->allowFalse = false;
        $this->addIfNotSet = false;
        $this->allowNewKeys = true;
        $this->performDeepMerging = true;
        $this->normalizeKeys = true;
    }

    public function setNormalizeKeys($normalizeKeys)
    {
        $this->normalizeKeys = (Boolean) $normalizeKeys;
    }

    /**
     * Normalizes keys between the different configuration formats.
     *
     * Namely, you mostly have foo_bar in YAML while you have foo-bar in XML.
     * After running this method, all keys are normalized to foo_bar.
     *
     * If you have a mixed key like foo-bar_moo, it will not be altered.
     * The key will also not be altered if the target key already exists.
     *
     * @param mixed $value
     *
     * @return array The value with normalized keys
     */
    protected function preNormalize($value)
    {
        if (!$this->normalizeKeys || !is_array($value)) {
            return $value;
        }

        foreach ($value as $k => $v) {
            if (false !== strpos($k, '-') && false === strpos($k, '_') && !array_key_exists($normalizedKey = str_replace('-', '_', $k), $value)) {
                $value[$normalizedKey] = $v;
                unset($value[$k]);
            }
        }

        return $value;
    }

    /**
     * Retrieves the children of this node.
     *
     * @return array The children
     */
    public function getChildren()
    {
        return $this->children;
    }

    /**
     * Sets the xml remappings that should be performed.
     *
     * @param array $remappings an array of the form array(array(string, string))
     */
    public function setXmlRemappings(array $remappings)
    {
        $this->xmlRemappings = $remappings;
    }

    /**
     * Sets whether to add default values for this array if it has not been
     * defined in any of the configuration files.
     *
     * @param Boolean $boolean
     */
    public function setAddIfNotSet($boolean)
    {
        $this->addIfNotSet = (Boolean) $boolean;
    }

    /**
     * Sets whether false is allowed as value indicating that the array should be unset.
     *
     * @param Boolean $allow
     */
    public function setAllowFalse($allow)
    {
        $this->allowFalse = (Boolean) $allow;
    }

    /**
     * Sets whether new keys can be defined in subsequent configurations.
     *
     * @param Boolean $allow
     */
    public function setAllowNewKeys($allow)
    {
        $this->allowNewKeys = (Boolean) $allow;
    }

    /**
     * Sets if deep merging should occur.
     *
     * @param Boolean $boolean
     */
    public function setPerformDeepMerging($boolean)
    {
        $this->performDeepMerging = (Boolean) $boolean;
    }

    /**
     * Whether extra keys should just be ignore without an exception.
     *
     * @param Boolean $boolean To allow extra keys
     */
    public function setIgnoreExtraKeys($boolean)
    {
        $this->ignoreExtraKeys = (Boolean) $boolean;
    }

    /**
     * Sets the node Name.
     *
     * @param string $name The node's name
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * Checks if the node has a default value.
     *
     * @return Boolean
     */
    public function hasDefaultValue()
    {
        return $this->addIfNotSet;
    }

    /**
     * Retrieves the default value.
     *
     * @return array The default value
     *
     * @throws \RuntimeException if the node has no default value
     */
    public function getDefaultValue()
    {
        if (!$this->hasDefaultValue()) {
            throw new \RuntimeException(sprintf('The node at path "%s" has no default value.', $this->getPath()));
        }

        $defaults = array();
        foreach ($this->children as $name => $child) {
            if ($child->hasDefaultValue()) {
                $defaults[$name] = $child->getDefaultValue();
            }
        }

        return $defaults;
    }

    /**
     * Adds a child node.
     *
     * @param NodeInterface $node The child node to add
     *
     * @throws \InvalidArgumentException when the child node has no name
     * @throws \InvalidArgumentException when the child node's name is not unique
     */
    public function addChild(NodeInterface $node)
    {
        $name = $node->getName();
        if (empty($name)) {
            throw new \InvalidArgumentException('Child nodes must be named.');
        }
        if (isset($this->children[$name])) {
            throw new \InvalidArgumentException(sprintf('A child node named "%s" already exists.', $name));
        }

        $this->children[$name] = $node;
    }

    /**
     * Finalizes the value of this node.
     *
     * @param mixed $value
     *
     * @return mixed The finalised value
     *
     * @throws UnsetKeyException
     * @throws InvalidConfigurationException if the node doesn't have enough children
     */
    protected function finalizeValue($value)
    {
        if (false === $value) {
            $msg = sprintf('Unsetting key for path "%s", value: %s', $this->getPath(), json_encode($value));
            throw new UnsetKeyException($msg);
        }

        foreach ($this->children as $name => $child) {
            if (!array_key_exists($name, $value)) {
                if ($child->isRequired()) {
                    $msg = sprintf('The child node "%s" at path "%s" must be configured.', $name, $this->getPath());
                    $ex = new InvalidConfigurationException($msg);
                    $ex->setPath($this->getPath());

                    throw $ex;
                }

                if ($child->hasDefaultValue()) {
                    $value[$name] = $child->getDefaultValue();
                }

                continue;
            }

            try {
                $value[$name] = $child->finalize($value[$name]);
            } catch (UnsetKeyException $unset) {
                unset($value[$name]);
            }
        }

        return $value;
    }

    /**
     * Validates the type of the value.
     *
     * @param mixed $value
     *
     * @throws InvalidTypeException
     */
    protected function validateType($value)
    {
        if (!is_array($value) && (!$this->allowFalse || false !== $value)) {
            $ex = new InvalidTypeException(sprintf(
                'Invalid type for path "%s". Expected array, but got %s',
                $this->getPath(),
                gettype($value)
            ));
            $ex->setPath($this->getPath());

            throw $ex;
        }
    }

    /**
     * Normalizes the value.
     *
     * @param mixed $value The value to normalize
     *
     * @return mixed The normalized value
     *
     * @throws InvalidConfigurationException
     */
    protected function normalizeValue($value)
    {
        if (false === $value) {
            return $value;
        }

        $value = $this->remapXml($value);

        $normalized = array();
        foreach ($this->children as $name => $child) {
            if (array_key_exists($name, $value)) {
                $normalized[$name] = $child->normalize($value[$name]);
                unset($value[$name]);
            }
        }

        // if extra fields are present, throw exception
        if (count($value) && !$this->ignoreExtraKeys) {
            $msg = sprintf('Unrecognized options "%s" under "%s"', implode(', ', array_keys($value)), $this->getPath());
            $ex = new InvalidConfigurationException($msg);
            $ex->setPath($this->getPath());

            throw $ex;
        }

        return $normalized;
    }

    /**
     * Remaps multiple singular values to a single plural value.
     *
     * @param array $value The source values
     *
     * @return array The remapped values
     */
    protected function remapXml($value)
    {
        foreach ($this->xmlRemappings as $transformation) {
            list($singular, $plural) = $transformation;

            if (!isset($value[$singular])) {
                continue;
            }

            $value[$plural] = Processor::normalizeConfig($value, $singular, $plural);
            unset($value[$singular]);
        }

        return $value;
    }

    /**
     * Merges values together.
     *
     * @param mixed $leftSide  The left side to merge.
     * @param mixed $rightSide The right side to merge.
     *
     * @return mixed The merged values
     *
     * @throws InvalidConfigurationException
     * @throws \RuntimeException
     */
    protected function mergeValues($leftSide, $rightSide)
    {
        if (false === $rightSide) {
            // if this is still false after the last config has been merged the
            // finalization pass will take care of removing this key entirely
            return false;
        }

        if (false === $leftSide || !$this->performDeepMerging) {
            return $rightSide;
        }

        foreach ($rightSide as $k => $v) {
            // no conflict
            if (!array_key_exists($k, $leftSide)) {
                if (!$this->allowNewKeys) {
                    $ex = new InvalidConfigurationException(sprintf(
                        'You are not allowed to define new elements for path "%s". '
                       .'Please define all elements for this path in one config file. '
                       .'If you are trying to overwrite an element, make sure you redefine it '
                       .'with the same name.',
                        $this->getPath()
                    ));
                    $ex->setPath($this->getPath());

                    throw $ex;
                }

                $leftSide[$k] = $v;
                continue;
            }

            if (!isset($this->children[$k])) {
                throw new \RuntimeException('merge() expects a normalized config array.');
            }

            $leftSide[$k] = $this->children[$k]->merge($leftSide[$k], $v);
        }

        return $leftSide;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Definition;

use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\Definition\ScalarNode;

/**
 * Node which only allows a finite set of values.
 *
 * @author Johannes M. Schmitt <schmittjoh@gmail.com>
 */
class EnumNode extends ScalarNode
{
    private $values;

    public function __construct($name, NodeInterface $parent = null, array $values = array())
    {
        $values = array_unique($values);
        if (count($values) <= 1) {
            throw new \InvalidArgumentException('$values must contain at least two distinct elements.');
        }

        parent::__construct($name, $parent);
        $this->values = $values;
    }

    public function getValues()
    {
        return $this->values;
    }

    protected function finalizeValue($value)
    {
        $value = parent::finalizeValue($value);

        if (!in_array($value, $this->values, true)) {
            $ex = new InvalidConfigurationException(sprintf(
                'The value %s is not allowed for path "%s". Permissible values: %s',
                json_encode($value),
                $this->getPath(),
                implode(', ', array_map('json_encode', $this->values))));
            $ex->setPath($this->getPath());

            throw $ex;
        }

        return $value;
    }
}
<?xml version="1.0" encoding="UTF-8"?>

<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false"
         syntaxCheck="false"
         bootstrap="vendor/autoload.php"
>
    <testsuites>
        <testsuite name="Symfony Config Component Test Suite">
            <directory>./Tests/</directory>
        </testsuite>
    </testsuites>

    <filter>
        <whitelist>
            <directory>./</directory>
            <exclude>
                <directory>./Resources</directory>
                <directory>./Tests</directory>
                <directory>./vendor</directory>
            </exclude>
        </whitelist>
    </filter>
</phpunit>
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config;

/**
 * @author Fabien Potencier <fabien@symfony.com>
 */
interface FileLocatorInterface
{
    /**
     * Returns a full path for a given file name.
     *
     * @param mixed   $name        The file name to locate
     * @param string  $currentPath The current path
     * @param Boolean $first       Whether to return the first occurrence or an array of filenames
     *
     * @return string|array The full path to the file|An array of file paths
     *
     * @throws \InvalidArgumentException When file is not found
     */
    public function locate($name, $currentPath = null, $first = true);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Resource;

/**
 * ResourceInterface is the interface that must be implemented by all Resource classes.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
interface ResourceInterface
{
    /**
     * Returns a string representation of the Resource.
     *
     * @return string A string representation of the Resource
     */
    public function __toString();

    /**
     * Returns true if the resource has not been updated since the given timestamp.
     *
     * @param integer $timestamp The last time the resource was loaded
     *
     * @return Boolean true if the resource has not been updated, false otherwise
     */
    public function isFresh($timestamp);

    /**
     * Returns the resource tied to this Resource.
     *
     * @return mixed The resource
     */
    public function getResource();
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Resource;

/**
 * DirectoryResource represents a resources stored in a subdirectory tree.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class DirectoryResource implements ResourceInterface, \Serializable
{
    private $resource;
    private $pattern;

    /**
     * Constructor.
     *
     * @param string $resource The file path to the resource
     * @param string $pattern  A pattern to restrict monitored files
     */
    public function __construct($resource, $pattern = null)
    {
        $this->resource = $resource;
        $this->pattern = $pattern;
    }

    /**
     * Returns a string representation of the Resource.
     *
     * @return string A string representation of the Resource
     */
    public function __toString()
    {
        return (string) $this->resource;
    }

    /**
     * Returns the resource tied to this Resource.
     *
     * @return mixed The resource
     */
    public function getResource()
    {
        return $this->resource;
    }

    public function getPattern()
    {
        return $this->pattern;
    }

    /**
     * Returns true if the resource has not been updated since the given timestamp.
     *
     * @param integer $timestamp The last time the resource was loaded
     *
     * @return Boolean true if the resource has not been updated, false otherwise
     */
    public function isFresh($timestamp)
    {
        if (!is_dir($this->resource)) {
            return false;
        }

        $newestMTime = filemtime($this->resource);
        foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->resource), \RecursiveIteratorIterator::SELF_FIRST) as $file) {
            // if regex filtering is enabled only check matching files
            if ($this->pattern && $file->isFile() && !preg_match($this->pattern, $file->getBasename())) {
                continue;
            }

            // always monitor directories for changes, except the .. entries
            // (otherwise deleted files wouldn't get detected)
            if ($file->isDir() && '/..' === substr($file, -3)) {
                continue;
            }

            $newestMTime = max($file->getMTime(), $newestMTime);
        }

        return $newestMTime < $timestamp;
    }

    public function serialize()
    {
        return serialize(array($this->resource, $this->pattern));
    }

    public function unserialize($serialized)
    {
        list($this->resource, $this->pattern) = unserialize($serialized);
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Resource;

/**
 * FileResource represents a resource stored on the filesystem.
 *
 * The resource can be a file or a directory.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class FileResource implements ResourceInterface, \Serializable
{
    private $resource;

    /**
     * Constructor.
     *
     * @param string $resource The file path to the resource
     */
    public function __construct($resource)
    {
        $this->resource = realpath($resource);
    }

    /**
     * Returns a string representation of the Resource.
     *
     * @return string A string representation of the Resource
     */
    public function __toString()
    {
        return (string) $this->resource;
    }

    /**
     * Returns the resource tied to this Resource.
     *
     * @return mixed The resource
     */
    public function getResource()
    {
        return $this->resource;
    }

    /**
     * Returns true if the resource has not been updated since the given timestamp.
     *
     * @param integer $timestamp The last time the resource was loaded
     *
     * @return Boolean true if the resource has not been updated, false otherwise
     */
    public function isFresh($timestamp)
    {
        if (!file_exists($this->resource)) {
            return false;
        }

        return filemtime($this->resource) < $timestamp;
    }

    public function serialize()
    {
        return serialize($this->resource);
    }

    public function unserialize($serialized)
    {
        $this->resource = unserialize($serialized);
    }
}
{
    "name": "symfony/config",
    "type": "library",
    "description": "Symfony Config Component",
    "keywords": [],
    "homepage": "http://symfony.com",
    "license": "MIT",
    "authors": [
        {
            "name": "Fabien Potencier",
            "email": "fabien@symfony.com"
        },
        {
            "name": "Symfony Community",
            "homepage": "http://symfony.com/contributors"
        }
    ],
    "require": {
        "php": ">=5.3.3",
        "symfony/filesystem": "~2.3"
    },
    "autoload": {
        "psr-0": { "Symfony\\Component\\Config\\": "" }
    },
    "target-dir": "Symfony/Component/Config",
    "minimum-stability": "dev",
    "extra": {
        "branch-alias": {
            "dev-master": "2.3-dev"
        }
    }
}
Copyright (c) 2004-2013 Fabien Potencier

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Loader;

use Symfony\Component\Config\Exception\FileLoaderLoadException;

/**
 * DelegatingLoader delegates loading to other loaders using a loader resolver.
 *
 * This loader acts as an array of LoaderInterface objects - each having
 * a chance to load a given resource (handled by the resolver)
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class DelegatingLoader extends Loader
{
    /**
     * Constructor.
     *
     * @param LoaderResolverInterface $resolver A LoaderResolverInterface instance
     */
    public function __construct(LoaderResolverInterface $resolver)
    {
        $this->resolver = $resolver;
    }

    /**
     * Loads a resource.
     *
     * @param mixed  $resource A resource
     * @param string $type     The resource type
     *
     * @return mixed
     *
     * @throws FileLoaderLoadException if no loader is found.
     */
    public function load($resource, $type = null)
    {
        if (false === $loader = $this->resolver->resolve($resource, $type)) {
            throw new FileLoaderLoadException($resource);
        }

        return $loader->load($resource, $type);
    }

    /**
     * {@inheritdoc}
     */
    public function supports($resource, $type = null)
    {
        return false === $this->resolver->resolve($resource, $type) ? false : true;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Loader;

/**
 * LoaderResolver selects a loader for a given resource.
 *
 * A resource can be anything (e.g. a full path to a config file or a Closure).
 * Each loader determines whether it can load a resource and how.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class LoaderResolver implements LoaderResolverInterface
{
    /**
     * @var LoaderInterface[] An array of LoaderInterface objects
     */
    private $loaders;

    /**
     * Constructor.
     *
     * @param LoaderInterface[] $loaders An array of loaders
     */
    public function __construct(array $loaders = array())
    {
        $this->loaders = array();
        foreach ($loaders as $loader) {
            $this->addLoader($loader);
        }
    }

    /**
     * Returns a loader able to load the resource.
     *
     * @param mixed  $resource A resource
     * @param string $type     The resource type
     *
     * @return LoaderInterface|false A LoaderInterface instance
     */
    public function resolve($resource, $type = null)
    {
        foreach ($this->loaders as $loader) {
            if ($loader->supports($resource, $type)) {
                return $loader;
            }
        }

        return false;
    }

    /**
     * Adds a loader.
     *
     * @param LoaderInterface $loader A LoaderInterface instance
     */
    public function addLoader(LoaderInterface $loader)
    {
        $this->loaders[] = $loader;
        $loader->setResolver($this);
    }

    /**
     * Returns the registered loaders.
     *
     * @return LoaderInterface[] An array of LoaderInterface instances
     */
    public function getLoaders()
    {
        return $this->loaders;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Loader;

/**
 * LoaderInterface is the interface implemented by all loader classes.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
interface LoaderInterface
{
    /**
     * Loads a resource.
     *
     * @param mixed  $resource The resource
     * @param string $type     The resource type
     */
    public function load($resource, $type = null);

    /**
     * Returns true if this class supports the given resource.
     *
     * @param mixed  $resource A resource
     * @param string $type     The resource type
     *
     * @return Boolean true if this class supports the given resource, false otherwise
     */
    public function supports($resource, $type = null);

    /**
     * Gets the loader resolver.
     *
     * @return LoaderResolverInterface A LoaderResolverInterface instance
     */
    public function getResolver();

    /**
     * Sets the loader resolver.
     *
     * @param LoaderResolverInterface $resolver A LoaderResolverInterface instance
     */
    public function setResolver(LoaderResolverInterface $resolver);

}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Loader;

/**
 * LoaderResolverInterface selects a loader for a given resource.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
interface LoaderResolverInterface
{
    /**
     * Returns a loader able to load the resource.
     *
     * @param mixed  $resource A resource
     * @param string $type     The resource type
     *
     * @return LoaderInterface A LoaderInterface instance
     */
    public function resolve($resource, $type = null);
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Loader;

use Symfony\Component\Config\Exception\FileLoaderLoadException;

/**
 * Loader is the abstract class used by all built-in loaders.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
abstract class Loader implements LoaderInterface
{
    protected $resolver;

    /**
     * Gets the loader resolver.
     *
     * @return LoaderResolverInterface A LoaderResolverInterface instance
     */
    public function getResolver()
    {
        return $this->resolver;
    }

    /**
     * Sets the loader resolver.
     *
     * @param LoaderResolverInterface $resolver A LoaderResolverInterface instance
     */
    public function setResolver(LoaderResolverInterface $resolver)
    {
        $this->resolver = $resolver;
    }

    /**
     * Imports a resource.
     *
     * @param mixed  $resource A Resource
     * @param string $type     The resource type
     *
     * @return mixed
     */
    public function import($resource, $type = null)
    {
        return $this->resolve($resource, $type)->load($resource, $type);
    }

    /**
     * Finds a loader able to load an imported resource.
     *
     * @param mixed  $resource A Resource
     * @param string $type     The resource type
     *
     * @return LoaderInterface A LoaderInterface instance
     *
     * @throws FileLoaderLoadException if no loader is found
     */
    public function resolve($resource, $type = null)
    {
        if ($this->supports($resource, $type)) {
            return $this;
        }

        $loader = null === $this->resolver ? false : $this->resolver->resolve($resource, $type);

        if (false === $loader) {
            throw new FileLoaderLoadException($resource);
        }

        return $loader;
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config\Loader;

use Symfony\Component\Config\FileLocatorInterface;
use Symfony\Component\Config\Exception\FileLoaderLoadException;
use Symfony\Component\Config\Exception\FileLoaderImportCircularReferenceException;

/**
 * FileLoader is the abstract class used by all built-in loaders that are file based.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
abstract class FileLoader extends Loader
{
    protected static $loading = array();

    protected $locator;

    private $currentDir;

    /**
     * Constructor.
     *
     * @param FileLocatorInterface $locator A FileLocatorInterface instance
     */
    public function __construct(FileLocatorInterface $locator)
    {
        $this->locator = $locator;
    }

    public function setCurrentDir($dir)
    {
        $this->currentDir = $dir;
    }

    public function getLocator()
    {
        return $this->locator;
    }

    /**
     * Imports a resource.
     *
     * @param mixed   $resource       A Resource
     * @param string  $type           The resource type
     * @param Boolean $ignoreErrors   Whether to ignore import errors or not
     * @param string  $sourceResource The original resource importing the new resource
     *
     * @return mixed
     *
     * @throws FileLoaderLoadException
     * @throws FileLoaderImportCircularReferenceException
     */
    public function import($resource, $type = null, $ignoreErrors = false, $sourceResource = null)
    {
        try {
            $loader = $this->resolve($resource, $type);

            if ($loader instanceof FileLoader && null !== $this->currentDir) {
                $resource = $this->locator->locate($resource, $this->currentDir, false);
            }

            $resources = is_array($resource) ? $resource : array($resource);
            for ($i = 0; $i < $resourcesCount = count($resources); $i++ ) {
                if (isset(self::$loading[$resources[$i]])) {
                    if ($i == $resourcesCount-1) {
                        throw new FileLoaderImportCircularReferenceException(array_keys(self::$loading));
                    }
                } else {
                    $resource = $resources[$i];
                    break;
                }
            }
            self::$loading[$resource] = true;

            $ret = $loader->load($resource, $type);

            unset(self::$loading[$resource]);

            return $ret;
        } catch (FileLoaderImportCircularReferenceException $e) {
            throw $e;
        } catch (\Exception $e) {
            if (!$ignoreErrors) {
                // prevent embedded imports from nesting multiple exceptions
                if ($e instanceof FileLoaderLoadException) {
                    throw $e;
                }

                throw new FileLoaderLoadException($resource, $sourceResource, null, $e);
            }
        }
    }
}
<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config;

use Symfony\Component\Config\Resource\ResourceInterface;
use Symfony\Component\Filesystem\Filesystem;

/**
 * ConfigCache manages PHP cache files.
 *
 * When debug is enabled, it knows when to flush the cache
 * thanks to an array of ResourceInterface instances.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class ConfigCache
{
    private $debug;
    private $file;

    /**
     * Constructor.
     *
     * @param string  $file  The absolute cache path
     * @param Boolean $debug Whether debugging is enabled or not
     */
    public function __construct($file, $debug)
    {
        $this->file = $file;
        $this->debug = (Boolean) $debug;
    }

    /**
     * Gets the cache file path.
     *
     * @return string The cache file path
     */
    public function __toString()
    {
        return $this->file;
    }

    /**
     * Checks if the cache is still fresh.
     *
     * This method always returns true when debug is off and the
     * cache file exists.
     *
     * @return Boolean true if the cache is fresh, false otherwise
     */
    public function isFresh()
    {
        if (!is_file($this->file)) {
            return false;
        }

        if (!$this->debug) {
            return true;
        }

        $metadata = $this->getMetaFile();
        if (!is_file($metadata)) {
            return false;
        }

        $time = filemtime($this->file);
        $meta = unserialize(file_get_contents($metadata));
        foreach ($meta as $resource) {
            if (!$resource->isFresh($time)) {
                return false;
            }
        }

        return true;
    }

    /**
     * Writes cache.
     *
     * @param string              $content  The content to write in the cache
     * @param ResourceInterface[] $metadata An array of ResourceInterface instances
     *
     * @throws \RuntimeException When cache file can't be wrote
     */
    public function write($content, array $metadata = null)
    {
        $mode = 0666 & ~umask();
        $filesystem = new Filesystem();
        $filesystem->dumpFile($this->file, $content, $mode);

        if (null !== $metadata && true === $this->debug) {
            $filesystem->dumpFile($this->getMetaFile(), serialize($metadata), $mode);
        }
    }

    /**
     * Gets the meta file path.
     *
     * @return string The meta file path
     */
    private function getMetaFile()
    {
        return $this->file.'.meta';
    }

}
CHANGELOG
=========

2.2.0
-----

 * added ArrayNodeDefinition::canBeEnabled() and ArrayNodeDefinition::canBeDisabled()
   to ease configuration when some sections are respectively disabled / enabled
   by default.
 * added a `normalizeKeys()` method for array nodes (to avoid key normalization)
 * added numerical type handling for config definitions
 * added convenience methods for optional configuration sections to ArrayNodeDefinition
 * added a utils class for XML manipulations

2.1.0
-----

 * added a way to add documentation on configuration
 * implemented `Serializable` on resources
 * LoaderResolverInterface is now used instead of LoaderResolver for type
   hinting
Config Component
================

Config provides the infrastructure for loading configurations from different
data sources and optionally monitoring these data sources for changes. There
are additional tools for validating, normalizing and handling of defaults that
can optionally be used to convert from different formats to arrays.

Resources
---------

You can run the unit tests with the following command:

    $ cd path/to/Symfony/Component/Config/
    $ composer.phar install --dev
    $ phpunit

<?php

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Symfony\Component\Config;

/**
 * FileLocator uses an array of pre-defined paths to find files.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class FileLocator implements FileLocatorInterface
{
    protected $paths;

    /**
     * Constructor.
     *
     * @param string|array $paths A path or an array of paths where to look for resources
     */
    public function __construct($paths = array())
    {
        $this->paths = (array) $paths;
    }

    /**
     * Returns a full path for a given file name.
     *
     * @param mixed   $name        The file name to locate
     * @param string  $currentPath The current path
     * @param Boolean $first       Whether to return the first occurrence or an array of filenames
     *
     * @return string|array The full path to the file|An array of file paths
     *
     * @throws \InvalidArgumentException When file is not found
     */
    public function locate($name, $currentPath = null, $first = true)
    {
        if ($this->isAbsolutePath($name)) {
            if (!file_exists($name)) {
                throw new \InvalidArgumentException(sprintf('The file "%s" does not exist.', $name));
            }

            return $name;
        }

        $filepaths = array();
        if (null !== $currentPath && file_exists($file = $currentPath.DIRECTORY_SEPARATOR.$name)) {
            if (true === $first) {
                return $file;
            }
            $filepaths[] = $file;
        }

        foreach ($this->paths as $path) {
            if (file_exists($file = $path.DIRECTORY_SEPARATOR.$name)) {
                if (true === $first) {
                    return $file;
                }
                $filepaths[] = $file;
            }
        }

        if (!$filepaths) {
            throw new \InvalidArgumentException(sprintf('The file "%s" does not exist (in: %s%s).', $name, null !== $currentPath ? $currentPath.', ' : '', implode(', ', $this->paths)));
        }

        return array_values(array_unique($filepaths));
    }

    /**
     * Returns whether the file path is an absolute path.
     *
     * @param string $file A file path
     *
     * @return Boolean
     */
    private function isAbsolutePath($file)
    {
        if ($file[0] == '/' || $file[0] == '\\'
            || (strlen($file) > 3 && ctype_alpha($file[0])
                && $file[1] == ':'
                && ($file[2] == '\\' || $file[2] == '/')
            )
            || null !== parse_url($file, PHP_URL_SCHEME)
        ) {
            return true;
        }

        return false;
    }
}
# -*- mode: ruby -*-
# vi: set ft=ruby :

# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"

$build_script = <<SCRIPT
apt-get update

echo Installing HHVM...
wget -O - http://dl.hhvm.com/conf/hhvm.gpg.key | sudo apt-key add -
echo deb http://dl.hhvm.com/ubuntu trusty main | sudo tee /etc/apt/sources.list.d/hhvm.list
sudo apt-get update
sudo apt-get install -y hhvm

echo Installing PHP...
sudo apt-get install -y php5 php5-cli php5-curl php5-fpm php5-intl

echo Installing Other deps. ...
sudo apt-get install -y git

SCRIPT

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "ubuntu/trusty64"

  # The url from where the 'config.vm.box' box will be fetched if it
  # doesn't already exist on the user's system.
  # config.vm.box_url = "http://domain.com/path/to/above.box"

  # Create a forwarded port mapping which allows access to a specific port
  # within the machine from a port on the host machine. In the example below,
  # accessing "localhost:8080" will access port 80 on the guest machine.
  # config.vm.network "forwarded_port", guest: 80, host: 8080

  # Create a private network, which allows host-only access to the machine
  # using a specific IP.
  # config.vm.network "private_network", ip: "192.168.33.10"

  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
  config.vm.network "public_network"

  # If true, then any SSH connections made will enable agent forwarding.
  # Default value: false
  # config.ssh.forward_agent = true

  # Share an additional folder to the guest VM. The first argument is
  # the path on the host to the actual folder. The second argument is
  # the path on the guest to mount the folder. And the optional third
  # argument is a set of non-required options.
  config.vm.synced_folder "./", "/home/vagrant/pdepend/"

  config.vm.provider :virtualbox do |vb|
    vb.name = "pDepend VM"
    vb.customize ["modifyvm", :id, "--memory", "5642"]
    vb.customize ["modifyvm", :id, "--cpus", "4"]
    vb.customize ["modifyvm", :id, "--hwvirtex", "on"]
    vb.customize ["modifyvm", :id, "--nestedpaging", "on"]
  end

  config.vm.provision :shell, inline: $build_script
end
#!/usr/bin/env php
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  */

// Map this phar archive
Phar::mapPhar('${archive.alias}');

// Configure include path to use this phar
set_include_path('phar://${archive.alias}/' . PATH_SEPARATOR . get_include_path());

// Run command line interface if this is the called file
if (isset($argv[0]) && realpath($argv[0]) === __FILE__) {

    // Set memory limit to max allowed
    ini_set('memory_limit', -1);

    // Load command line utility
    include_once 'phar://${archive.alias}/vendor/autoload.php';

    exit(\PDepend\TextUI\Command::main($argv));
}
__HALT_COMPILER();
#!/usr/bin/env php
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  */

use PDepend\TextUI\Command;

// PEAR/svn workaround
if (strpos('@php_bin@', '@php_bin') === 0) {
    set_include_path('.' . PATH_SEPARATOR . dirname(__FILE__) . '/../main/php');
}

// check for pdepend installed as composer package
if (file_exists(__DIR__ . '/../../../../autoload.php')) {
    require_once __DIR__ . '/../../../../autoload.php';
} else {
    require_once __DIR__ . '/../../vendor/autoload.php';
}

// Allow as much memory as possible by default
if (extension_loaded('suhosin') && is_numeric(ini_get('suhosin.memory_limit'))) {
    $limit = ini_get('memory_limit');
    if (preg_match('(^(\d+)([BKMGT]))', $limit, $match)) {
        $shift = array('B' => 0, 'K' => 10, 'M' => 20, 'G' => 30, 'T' => 40);
        $limit = ($match[1] * (1 << $shift[$match[2]]));
    }
    if (ini_get('suhosin.memory_limit') > $limit && $limit > -1) {
        ini_set('memory_limit', ini_get('suhosin.memory_limit'));
    }
} else {
    ini_set('memory_limit', -1);
}

exit(Command::main());
@echo off
REM This file is part of PDepend.
REM
REM Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
REM All rights reserved.
REM
REM Redistribution and use in source and binary forms, with or without
REM modification, are permitted provided that the following conditions
REM are met:
REM
REM   * Redistributions of source code must retain the above copyright
REM     notice, this list of conditions and the following disclaimer.
REM 
REM   * Redistributions in binary form must reproduce the above copyright
REM     notice, this list of conditions and the following disclaimer in
REM     the documentation and/or other materials provided with the
REM     distribution.
REM
REM   * Neither the name of Manuel Pichler nor the names of his
REM     contributors may be used to endorse or promote products derived
REM     from this software without specific prior written permission.
REM
REM THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
REM "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
REM LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
REM FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
REM COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
REM INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
REM BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
REM LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
REM CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
REM LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
REM ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
REM POSSIBILITY OF SUCH DAMAGE.
REM
REM $Id$
REM


if "%PHPBIN%" == "" set PHPBIN=@php_bin@
if not exist "%PHPBIN%" if "%PHP_PEAR_PHP_BIN%" neq "" goto USE_PEAR_PATH
GOTO RUN
:USE_PEAR_PATH
set PHPBIN=%PHP_PEAR_PHP_BIN%
:RUN
"%PHPBIN%" "@bin_dir@\pdepend" %*
#!/usr/bin/env php
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  */

use PDepend\TextUI\Command;

// PEAR/svn workaround
if (strpos('@php_bin@', '@php_bin') === 0) {
    set_include_path('.' . PATH_SEPARATOR . dirname(__FILE__) . '/../main/php');
}

require_once __DIR__ . '/../../vendor/autoload.php';

// Allow as much memory as possible by default
if (extension_loaded('suhosin') && is_numeric(ini_get('suhosin.memory_limit'))) {
    $limit = ini_get('memory_limit');
    if (preg_match('(^(\d+)([BKMGT]))', $limit, $match)) {
        $shift = array('B' => 0, 'K' => 10, 'M' => 20, 'G' => 30, 'T' => 40);
        $limit = ($match[1] * (1 << $shift[$match[2]]));
    }
    if (ini_get('suhosin.memory_limit') > $limit && $limit > -1) {
        ini_set('memory_limit', ini_get('suhosin.memory_limit'));
    }
} else {
    ini_set('memory_limit', -1);
}

exit(Command::main());
<?xml version="1.0"?>
<xsd:schema targetNamespace="http://pdepend.org/schema/configuration"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            xmlns="http://pdepend.org/schema/configuration">

    <xsd:element name="configuration">
        <xsd:complexType>
            <xsd:choice minOccurs="0" maxOccurs="unbounded" >
                <xsd:element ref="imageConvert" minOccurs="0" maxOccurs="1" />
                <xsd:element ref="cache" minOccurs="0" maxOccurs="1" />
            </xsd:choice>
        </xsd:complexType>
    </xsd:element>

    <xsd:element name="cache">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element ref="driver" />
                <xsd:element ref="location" minOccurs="0" maxOccurs="1" />
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>

    <xsd:element name="driver">
        <xsd:simpleType>
            <xsd:restriction base="xsd:string">
                <xsd:enumeration value="file" />
                <xsd:enumeration value="memory" />
            </xsd:restriction>
        </xsd:simpleType>
    </xsd:element>

    <xsd:element name="location" type="xsd:anyURI" />

    <xsd:element name="imageConvert">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element ref="fontFamily" minOccurs="0" maxOccurs="1" />
                <xsd:element ref="fontSize" minOccurs="0" maxOccurs="1" />
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>

    <xsd:element name="fontFamily" type="xsd:string" />
    <xsd:element name="fontSize" type="xsd:int" />
</xsd:schema>
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:pdepend="http://pdepend.org/schema/dic/pdepend"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

    <services>
        <service id="pdepend.textui.runner" class="PDepend\TextUI\Runner">
            <argument type="service" id="pdepend.report_generator_factory" />
            <argument type="service" id="pdepend.engine" />
        </service>

        <service id="pdepend.util.cache_factory" class="PDepend\Util\Cache\CacheFactory">
            <argument type="service" id="pdepend.configuration" />
        </service>

        <service id="pdepend.engine" class="PDepend\Engine">
            <argument type="service" id="pdepend.configuration" />
            <argument type="service" id="pdepend.util.cache_factory" />
            <argument type="service" id="pdepend.analyzer_factory" />
        </service>

        <service id="pdepend.analyzer_factory" class="PDepend\Metrics\AnalyzerFactory">
            <argument type="service" id="service_container" />
        </service>

        <service id="pdepend.configuration" class="PDepend\Util\Configuration">
        </service>

        <service id="pdepend.textui.result_printer" class="PDepend\TextUI\ResultPrinter" />

        <service id="pdepend.report.summary.xml" class="PDepend\Report\Summary\Xml">
            <tag name="pdepend.logger" option="--summary-xml" message="Generates a xml log with all metrics." />
        </service>

        <service id="pdepend.report.dependencies.xml" class="PDepend\Report\Dependencies\Xml">
            <tag name="pdepend.logger" option="--dependency-xml" message="Generates a xml log with all dependencies." />
        </service>

        <service id="pdepend.report.jdepend.xml" class="PDepend\Report\Jdepend\Xml">
            <tag name="pdepend.logger" option="--jdepend-xml" message="Generates the package dependency log." />
        </service>

        <service id="pdepend.report.jdepend.chart" class="PDepend\Report\Jdepend\Chart">
            <tag name="pdepend.logger" option="--jdepend-chart" message="Generates a diagram of the analyzed packages." />
        </service>

        <service id="pdepend.report.overview.pyramid" class="PDepend\Report\Overview\Pyramid">
            <tag name="pdepend.logger" option="--overview-pyramid" message="Generates a chart with an Overview Pyramid for the analyzed project." />
        </service>

        <service id="pdepend.report_generator_factory" class="PDepend\Report\ReportGeneratorFactory">
            <argument type="service" id="service_container" />
        </service>

        <service id="pdepend.analyzer.class_level" class="PDepend\Metrics\Analyzer\ClassLevelAnalyzer">
            <tag name="pdepend.analyzer" />

            <call method="addAnalyzer">
                <argument type="service" id="pdepend.analyzer.cyclomatic_complexity" />
            </call>
        </service>

        <service id="pdepend.analyzer.code_rank" class="PDepend\Metrics\Analyzer\CodeRankAnalyzer">
            <tag name="pdepend.analyzer" option="--coderank-mode" message="Used CodeRank strategies. Comma separated list of 'inheritance'(default), 'property' and 'method'." value="*[,...]" />
        </service>

        <service id="pdepend.analyzer.cohesion" class="PDepend\Metrics\Analyzer\CohesionAnalyzer">
            <tag name="pdepend.analyzer" />
        </service>

        <service id="pdepend.analyzer.coupling" class="PDepend\Metrics\Analyzer\CouplingAnalyzer">
            <tag name="pdepend.analyzer" />
        </service>

        <service id="pdepend.analyzer.crap_index" class="PDepend\Metrics\Analyzer\CrapIndexAnalyzer">
            <tag name="pdepend.analyzer" option="--coverage-report" message="Clover style CodeCoverage report, as produced by PHPUnit's --coverage-clover option." />
            <call method="addAnalyzer">
                <argument type="service" id="pdepend.analyzer.cyclomatic_complexity" />
            </call>
        </service>

        <service id="pdepend.analyzer.cyclomatic_complexity" class="PDepend\Metrics\Analyzer\CyclomaticComplexityAnalyzer">
            <tag name="pdepend.analyzer" />
        </service>

        <service id="pdepend.analyzer.dependency" class="PDepend\Metrics\Analyzer\DependencyAnalyzer">
            <tag name="pdepend.analyzer" />
        </service>

        <service id="pdepend.analyzer.class_dependency" class="PDepend\Metrics\Analyzer\ClassDependencyAnalyzer">
            <tag name="pdepend.analyzer" />
        </service>

        <service id="pdepend.analyzer.hierarchy" class="PDepend\Metrics\Analyzer\HierarchyAnalyzer">
            <tag name="pdepend.analyzer" />
        </service>

        <service id="pdepend.analyzer.inheritance" class="PDepend\Metrics\Analyzer\InheritanceAnalyzer">
            <tag name="pdepend.analyzer" />
        </service>

        <service id="pdepend.analyzer.npath_complexity" class="PDepend\Metrics\Analyzer\NPathComplexityAnalyzer">
            <tag name="pdepend.analyzer" />
        </service>

        <service id="pdepend.analyzer.node_count" class="PDepend\Metrics\Analyzer\NodeCountAnalyzer">
            <tag name="pdepend.analyzer" />
        </service>

        <service id="pdepend.analyzer.node_loc" class="PDepend\Metrics\Analyzer\NodeLocAnalyzer">
            <tag name="pdepend.analyzer" />
        </service>

        <service id="pdepend.analyzer.halstead" class="PDepend\Metrics\Analyzer\HalsteadAnalyzer">
            <tag name="pdepend.analyzer" />
        </service>

        <service id="pdepend.analyzer.maintainability" class="PDepend\Metrics\Analyzer\MaintainabilityIndexAnalyzer">
            <tag name="pdepend.analyzer" />
        </service>
    </services>
</container>
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Input;

/**
 * Filters a given file path against a blacklist with disallow path fragments.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ExcludePathFilter implements Filter
{
    /**
     * Regular expression that should not match against the relative file paths.
     *
     * @var   string
     * @since 0.10.0
     */
    protected $relative = '';

    /**
     * Regular expression that should not match against the absolute file paths.
     *
     * @var   string
     * @since 0.10.0
     */
    protected $absolute = '';

    /**
     * Constructs a new exclude path filter instance and accepts an array of
     * exclude pattern as argument.
     *
     * @param array $patterns List of exclude file path patterns.
     */
    public function __construct(array $patterns)
    {
        $quoted = array_map('preg_quote', $patterns);

        $this->relative = '(' . str_replace('\*', '.*', join('|', $quoted)) . ')i';
        $this->absolute = '(^(' . str_replace('\*', '.*', join('|', $quoted)) .'))i';
    }

    /**
     * Returns <b>true</b> if this filter accepts the given path.
     *
     * @param string $relative The relative path to the specified root.
     * @param string $absolute The absolute path to a source file.
     *
     * @return boolean
     */
    public function accept($relative, $absolute)
    {
        return ($this->notRelative($relative) && $this->notAbsolute($absolute));
    }

    /**
     * This method checks if the given <b>$path</b> does not match against the
     * exclude patterns as an absolute path.
     *
     * @param string $path The absolute path to a source file.
     *
     * @return boolean
     * @since  0.10.0
     */
    protected function notAbsolute($path)
    {
        return (preg_match($this->absolute, $path) === 0);
    }

    /**
     * This method checks if the given <b>$path</b> does not match against the
     * exclude patterns as an relative path.
     *
     * @param string $path The relative path to a source file.
     *
     * @return boolean
     * @since  0.10.0
     */
    protected function notRelative($path)
    {
        return (preg_match($this->relative, $path) === 0);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Input;

/**
 * Simple utility filter iterator for php source files.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Iterator extends \FilterIterator
{
    /**
     * The associated filter object.
     *
     * @var \PDepend\Input\Filter
     */
    protected $filter = null;

    /**
     * Optional root path for the files.
     *
     * @var   string
     * @since 0.10.0
     */
    protected $rootPath = null;

    /**
     * Constructs a new file filter iterator.
     *
     * @param \Iterator             $iterator The inner iterator.
     * @param \PDepend\Input\Filter $filter   The filter object.
     * @param string                $rootPath Optional root path for the files.
     */
    public function __construct(\Iterator $iterator, Filter $filter, $rootPath = null)
    {
        parent::__construct($iterator);

        $this->filter   = $filter;
        $this->rootPath = $rootPath;
    }

    /**
     * Returns <b>true</b> if the file name ends with '.php'.
     *
     * @return boolean
     */
    public function accept()
    {
        return $this->filter->accept($this->getLocalPath(), $this->getFullPath());
    }

    /**
     * Returns the full qualified realpath for the currently active file.
     *
     * @return string
     * @since  0.10.0
     */
    protected function getFullPath()
    {
        return $this->getInnerIterator()->current()->getRealpath();
    }

    /**
     * Returns the local path of the current file, if the root path property was
     * set. If not, this method returns the absolute file path.
     *
     * @return string
     * @since  0.10.0
     */
    protected function getLocalPath()
    {
        if ($this->rootPath && 0 === strpos($this->getFullPath(), $this->rootPath)) {
            return substr($this->getFullPath(), strlen($this->rootPath));
        }
        return $this->getFullPath();
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Input;

/**
 * Simple composite pattern implementation that allows to bundle multiple
 * filter implementations.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class CompositeFilter implements Filter
{
    /**
     * List of aggregated {@link \PDepend\Input\Filter} objects.
     *
     * @var \PDepend\Input\Filter[]
     */
    protected $filters = array();

    /**
     * Adds a file filter to this composite.
     *
     * @param  \PDepend\Input\Filter $filter The new filter object.
     * @return void
     */
    public function append(Filter $filter)
    {
        $this->filters[] = $filter;
    }

    /**
     * Delegates the given <b>$localPath</b> object to all aggregated filters.
     * Returns <b>true</b> if this filter accepts the given path.
     *
     * @param  string $relative The relative path to the specified root.
     * @param  string $absolute The absolute path to a source file.
     * @return boolean
     */
    public function accept($relative, $absolute)
    {
        foreach ($this->filters as $filter) {
            if (false === $filter->accept($relative, $absolute)) {
                return false;
            }
        }
        return true;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Input;

/**
 * Whitelist filter that accepts files by their file extension.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ExtensionFilter implements Filter
{
    /**
     * Whitelist of accepted file extensions.
     *
     * @var array(string)
     */
    protected $extensions = array();

    /**
     * Constructs a new file extension filter instance with the given list of
     *  allowed file <b>$extensions</b>.
     *
     * @param array $extensions List of allowed extension.
     */
    public function __construct(array $extensions)
    {
        $this->extensions = $extensions;
    }

    /**
     * Returns <b>true</b> if this filter accepts the given paths.
     *
     * @param  string $relative The relative path to the specified root.
     * @param  string $absolute The absolute path to a source file.
     * @return boolean
     */
    public function accept($relative, $absolute)
    {
        if (strpos($absolute, 'php://') === 0) {
            return true;
        }

        $extension = pathinfo($relative, PATHINFO_EXTENSION);

        return in_array($extension, $this->extensions);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Input;

/**
 * Base interface for file filters.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface Filter
{
    /**
     * Returns <b>true</b> if this filter accepts the given paths.
     *
     * @param  string $relative The relative path to the specified root.
     * @param  string $absolute The absolute path to a source file.
     * @return boolean
     */
    public function accept($relative, $absolute);
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Util;

/**
 * This is a utility class for some file operations.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
final class FileUtil
{
    /**
     * Returns the home directory of the current user if it exists. Otherwise
     * this method will return the system temp directory.
     *
     * @return string
     * @since  0.10.0
     */
    public static function getUserHomeDirOrSysTempDir()
    {
        $home = self::getUserHomeDir();
        if (file_exists($home) && is_writable($home)) {
            return $home;
        }
        return self::getSysTempDir();
    }

    /**
     * Returns the system temp directory.
     *
     * @return string
     */
    public static function getSysTempDir()
    {
        return sys_get_temp_dir();
    }

    /**
     * Returns the home directory of the current user.
     *
     * @return string
     * @since  0.10.0
     */
    public static function getUserHomeDir()
    {
        if ((PHP_OS === 'Darwin') || (PHP_OS === 'CYGWIN') || (false === stripos(PHP_OS, 'win'))) {
            return getenv('HOME');
        }
        return getenv('HOMEDRIVE') . getenv('HOMEPATH');
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Util;

/**
 * Registry class for the PDepend configuration class.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ConfigurationInstance
{
    /**
     * The unique configuration instance.
     *
     * @var \PDepend\Util\Configuration
     */
    private static $configuration = null;

    /**
     * Returns a configured config instance or <b>null</b>.
     *
     * @return \PDepend\Util\Configuration
     */
    public static function get()
    {
        return self::$configuration;
    }

    /**
     * Sets the configuration instance.
     *
     * @param  \PDepend\Util\Configuration $configuration The config instance.
     * @return void
     */
    public static function set(Configuration $configuration = null)
    {
        self::$configuration = $configuration;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Util;

/**
 * This is a simply utility class that will perform mathematical operations with
 * bcmath when the extension exists, otherwise it will use default math operations.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
final class MathUtil
{
    /**
     * This method will multiply the two given operands with the bcmath extension
     * when available, otherwise it will use the default mathematical operations.
     *
     * @param string $left  The left arithmetic operand.
     * @param string $right The right arithmetic operand.
     *
     * @return string
     */
    public static function mul($left, $right)
    {
        if (function_exists('bcmul')) {
            return bcmul($left, $right);
        }
        return (string) ((int) $left * (int) $right);
    }

    /**
     * This method will add the two given operands with the bcmath extension
     * when available, otherwise it will use the default mathematical operations.
     *
     * @param string $left  The left arithmetic operand.
     * @param string $right The right arithmetic operand.
     *
     * @return string
     */
    public static function add($left, $right)
    {
        if (function_exists('bcadd')) {
            return bcadd($left, $right);
        }
        return (string) ((int) $left + (int) $right);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Util;

/**
 * Simple container class that holds settings for PDepend and all its sub
 * systems.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Configuration
{
    /**
     * Simple object tree holding the concrete configuration values.
     *
     * @var   \stdClass
     * @since 0.10.0
     */
    protected $settings = null;

    /**
     * Constructs a new configuration instance with the given settings tree.
     *
     * @param \stdClass $settings The concrete configuration values.
     * @since 0.10.0
     */
    public function __construct(\stdClass $settings)
    {
        $this->settings = $settings;
    }

    /**
     * Magic get method that is called by PHP's runtime engine whenever an
     * undeclared object property is accessed through a read operation. This
     * implementation of the magic get method checks if a configuration value
     * for the given <b>$name</b> exists and returns the configuration value if
     * a matching entry exists. Otherwise this method will throw an exception.
     *
     * @param  string $name Name of the requested configuration value.
     * @return mixed
     * @throws \OutOfRangeException If no matching configuration value exists.
     * @since  0.10.0
     */
    public function __get($name)
    {
        if (isset($this->settings->{$name})) {
            return $this->settings->{$name};
        }
        throw new \OutOfRangeException(
            sprintf("A configuration option '%s' not exists.", $name)
        );
    }

    /**
     * Magic setter method that will be called by PHP's runtime engine when a
     * write operation is performed on an undeclared object property. This
     * implementation of the magic set method always throws an exception, because
     * configuration settings are immutable.
     *
     * @param  string $name  Name of the write property.
     * @param  mixed  $value The new property value.
     * @return void
     * @throws \OutOfRangeException Whenever this method is called.
     * @since  0.10.0
     */
    public function __set($name, $value)
    {
        throw new \OutOfRangeException(
            sprintf("A configuration option '%s' not exists.", $name)
        );
    }

    /**
     * Magic isset method that will be called by PHP's runtime engine when the
     * <em>isset()</em> operator is called on an undefined object property. This
     * implementation of the magic isset method tests if a configuration value
     * for the given <b>$name</b> exists.
     *
     * @param  string $name Name of the requested property.
     * @return boolean
     * @since  0.10.0
     */
    public function __isset($name)
    {
        return isset($this->settings->{$name});
    }
}
<?php
/**
 * This file is part of PHP_Depend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Util;

/**
 * Utility class used to test for required php version workarounds.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Workarounds
{
    /**
     * Tests if the used PHP version has the known unserialize issue with object
     * references.
     *
     * @return boolean
     * @see    https://bugs.php.net/bug.php?id=62373
     */
    public function hasSerializeReferenceIssue()
    {
        return (version_compare(phpversion(), "5.4.0") > 0 && version_compare("5.4.5", phpversion()) > 0);
    }

    /**
     * Tests if the current environment has no known issues and does not
     * require any workaround.
     *
     * @return boolean
     */
    public function isNotRequired()
    {
        return !$this->hasSerializeReferenceIssue();
    }

    /**
     * Returns an array with error messages related to the required workarounds.
     *
     * @return array
     */
    public function getRequiredWorkarounds()
    {
        $issues = array();
        if ($this->hasSerializeReferenceIssue()) {
            $issues[] = 'File cache deactivated due to known serialize() issues in PHP ' . phpversion();
        }

        return $issues;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Util;

/**
 * This is a simply utility class that will perform mathematical operations with
 * bcmath when the extension exists, otherwise it will use default math operations.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.2.x
 */
final class Utf8Util
{
    public static function ensureEncoding($raw)
    {
        if (function_exists('mb_detect_encoding')) {
            $encoding = mb_detect_encoding($raw);
        } else {
            $encoding = 'UTF8';
        }

        $text = '';
        if (function_exists('iconv')) {
            $text = @iconv($encoding, 'UTF8//IGNORE', $raw);
        }

        if ('' == $text) {
            $text = utf8_encode($raw);
        }

        return $text;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Util;

/**
 * Simple utility class that is used to create different image formats. This
 * class can use the ImageMagick cli tool <b>convert</b> and the pecl extension
 * <b>pecl/imagick</b>.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ImageConvert
{
    /**
     * Tries to converts the <b>$input</b> image into the <b>$output</b> format.
     *
     * @param  string $input  The input file.
     * @param  string $output The output file.
     * @return void
     */
    public static function convert($input, $output)
    {
        $inputType  = strtolower(pathinfo($input, PATHINFO_EXTENSION));
        $outputType = strtolower(pathinfo($output, PATHINFO_EXTENSION));

        // Check for output file without extension and reuse input type
        if ($outputType === '') {
            $outputType = $inputType;
            $output    .= ".{$outputType}";
        }

        if ($inputType === 'svg') {
            self::prepareSvg($input);
        }

        if ($inputType === $outputType) {
            file_put_contents($output, file_get_contents($input));
        } elseif (extension_loaded('imagick') === true) {
            $imagick = new \Imagick($input);
            $imagick->setImageFormat($outputType);
            $imagick->writeImage($output);

            // The following code is not testable when imagick is installed
            // @codeCoverageIgnoreStart
        } elseif (self::hasImagickConvert() === true) {
            $input  = escapeshellarg($input);
            $output = escapeshellarg($output);

            system("convert {$input} {$output}");
        } else {
            $fallback = substr($output, 0, -strlen($outputType)) . $inputType;

            echo "WARNING: Cannot generate image of type '{$outputType}'. This",
                 " feature needs either the\n         pecl/imagick extension or",
                 " the ImageMagick cli tool 'convert'.\n\n",
                 "Writing alternative image:\n{$fallback}\n\n";

            file_put_contents($fallback, file_get_contents($input));
        }
        // @codeCoverageIgnoreEnd
    }

    /**
     * Tests that the ImageMagick CLI tool <b>convert</b> exists.
     *
     * @return boolean
     */
    protected static function hasImagickConvert()
    {
        // @codeCoverageIgnoreStart
        $desc = array(
            0  =>  array('pipe', 'r'),
            1  =>  array('pipe', 'w'),
            2  =>  array('pipe', 'a'),
        );

        $proc = proc_open('convert', $desc, $pipes);
        if (is_resource($proc)) {
            fwrite($pipes[0], '-version');
            fclose($pipes[0]);

            return (0 === proc_close($proc));
        }
        return false;
        // @codeCoverageIgnoreEnd
    }

    /**
     * Utility method for svg input files.
     *
     * If the input file has the mime type svg and a configuration file with
     * imageConvert options exists, this method will prepare the input image
     * file.
     *
     * @param  string $input The input svg file.
     * @return void
     */
    protected static function prepareSvg($input)
    {
        // Check for a configuration instance
        if (($config = ConfigurationInstance::get()) === null) {
            return;
        }

        $svg = file_get_contents($input);

        // Check for font family
        if (isset($config->imageConvert->fontFamily)) {
            // Get font family
            $fontFamily = (string) $config->imageConvert->fontFamily;
            // Replace CSS separators
            $fontReplace = 'font-family:' . strtr($fontFamily, ';:', '  ');
            $fontPattern = '/font-family:\s*Arial/';

            $svg = preg_replace($fontPattern, $fontReplace, $svg);
        }

        // Check for font size
        if (isset($config->imageConvert->fontSize)) {
            // Get font size
            $fontSize = abs((float) $config->imageConvert->fontSize);

            // Fetch all font-size expressions
            preg_match_all('/font-size:\s*(\d+)/', $svg, $fontSizes);
            $fontSizes = array_unique($fontSizes[1]);

            $resize = ($fontSize - max($fontSizes));
            foreach ($fontSizes as $fontSize) {
                // Calculate resize value
                $fontReplace = 'font-size:' . ($fontSize + $resize);
                $fontPattern = "/font-size:\s*{$fontSize}/";

                $svg = preg_replace($fontPattern, $fontReplace, $svg);
            }
        }

        file_put_contents($input, $svg);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Util;

use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Source\AST\AbstractASTType;
use PDepend\Source\AST\ASTCompilationUnit;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTMethod;

/**
 * This class provides methods to generate unique, but reproducable identifiers
 * for nodes generated during the parsing process.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class IdBuilder
{
    /**
     * Generates an identifier for the given file instance.
     *
     * @param  \PDepend\Source\AST\ASTCompilationUnit $compilationUnit
     * @return string
     */
    public function forFile(ASTCompilationUnit $compilationUnit)
    {
        return $this->hash($compilationUnit->getFileName());
    }

    /**
     * Generates an identifier for the given function instance.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return string
     */
    public function forFunction(ASTFunction $function)
    {
        return $this->forOffsetItem($function, 'function');
    }

    /**
     * Generates an identifier for the given class, interface or trait instance.
     *
     * @param  \PDepend\Source\AST\AbstractASTType $type
     * @return string
     */
    public function forClassOrInterface(AbstractASTType $type)
    {

        return $this->forOffsetItem(
            $type,
            ltrim(strrchr(strtolower(get_class($type)), '_'), '_')
        );
    }

    /**
     * Generates an identifier for the given source item.
     *
     * @param  \PDepend\Source\AST\AbstractASTArtifact $artifact
     * @param  string                                  $prefix   The item type identifier.
     * @return string
     */
    protected function forOffsetItem(AbstractASTArtifact $artifact, $prefix)
    {
        $fileHash = $artifact->getCompilationUnit()->getId();
        $itemHash = $this->hash($prefix . ':' . strtolower($artifact->getName()));

        $offset = $this->getOffsetInFile($fileHash, $itemHash);

        return sprintf('%s-%s-%s', $fileHash, $itemHash, $offset);
    }

    /**
     * Generates an identifier for the given method instance.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return string
     */
    public function forMethod(ASTMethod $method)
    {
        return sprintf(
            '%s-%s',
            $method->getParent()->getId(),
            $this->hash(strtolower($method->getName()))
        );
    }

    /**
     * Creates a base 36 hash for the given string.
     *
     * @param  string $string The raw input identifier/string.
     * @return string
     */
    protected function hash($string)
    {
        return substr(base_convert(md5($string), 16, 36), 0, 11);
    }

    /**
     * Returns the node offset/occurence of the given <b>$string</b> within a
     * file.
     *
     * @param  string $file   The file identifier.
     * @param  string $string The node identifier.
     * @return string
     */
    protected function getOffsetInFile($file, $string)
    {
        if (isset($this->offsetInFile[$file][$string])) {
            $this->offsetInFile[$file][$string]++;
        } else {
            $this->offsetInFile[$file][$string] = 0;
        }
        return sprintf(
            '%02s',
            base_convert($this->offsetInFile[$file][$string], 10, 36)
        );
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */

namespace PDepend\Util\Cache;

/**
 * Base interface for a concrete cache driver.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */
interface CacheDriver
{
    /**
     * The current cache version.
     */
    const VERSION = '@version:0cccd352eaa5723147a994a742e6670a:@';

    /**
     * Sets the type for the next <em>store()</em> or <em>restore()</em> method
     * call. A type is something like a namespace or group for cache entries.
     *
     * Note that the cache type will be reset after each storage method call, so
     * you must invoke right before every call to <em>restore()</em> or
     * <em>store()</em>.
     *
     * @param  string $type
     * @return \PDepend\Util\Cache\CacheDriver
     */
    public function type($type);

    /**
     * This method will store the given <em>$data</em> under <em>$key</em>. This
     * method can be called with a third parameter that will be used as a
     * verification token, when the a cache entry gets restored. If the stored
     * hash and the supplied hash are not identical, that cache entry will be
     * removed and not returned.
     *
     * @param  string $key  The cache key for the given data.
     * @param  mixed  $data Any data that should be cached.
     * @param  string $hash Optional hash that will be used for verification.
     * @return void
     */
    public function store($key, $data, $hash = null);

    /**
     * This method tries to restore an existing cache entry for the given
     * <em>$key</em>. If a matching entry exists, this method verifies that the
     * given <em>$hash</em> and the the value stored with cache entry are equal.
     * Then it returns the cached entry. Otherwise this method will return
     * <b>NULL</b>.
     *
     * @param  string $key  The cache key for the given data.
     * @param  string $hash Optional hash that will be used for verification.
     * @return mixed
     */
    public function restore($key, $hash = null);

    /**
     * This method will remove an existing cache entry for the given identifier.
     * It will delete all cache entries where the cache key start with the given
     * <b>$pattern</b>. If no matching entry exists, this method simply does
     * nothing.
     *
     * @param  string $pattern The cache key pattern.
     * @return void
     */
    public function remove($pattern);
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */

namespace PDepend\Util\Cache;

use PDepend\Util\Cache\Driver\FileCacheDriver;
use PDepend\Util\Cache\Driver\MemoryCacheDriver;
use PDepend\Util\Configuration;

/**
 * Factory that encapsulates the creation of a concrete cache instance.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */
class CacheFactory
{
    /**
     * The system configuration.
     *
     * @var \PDepend\Util\Configuration
     */
    protected $configuration = null;

    /**
     * Singleton property that holds existing cache instances.
     *
     * @var \PDepend\Util\Cache\CacheDriver[]
     */
    protected $caches = array();

    /**
     * Constructs a new cache factory instance for the given configuration.
     *
     * @param \PDepend\Util\Configuration $configuration The system configuration.
     */
    public function __construct(Configuration $configuration)
    {
        $this->configuration = $configuration;
    }

    /**
     * Creates a new instance or returns an existing cache for the given cache
     * identifier.
     *
     * @param string $cacheKey The name/identifier for the cache instance.
     *
     * @return \PDepend\Util\Cache\CacheDriver
     */
    public function create($cacheKey = null)
    {
        if (false === isset($this->caches[$cacheKey])) {
            $this->caches[$cacheKey] = $this->createCache($cacheKey);
        }
        return $this->caches[$cacheKey];
    }

    /**
     * Creates a cache instance based on the supplied configuration.
     *
     * @param  string $cacheKey The name/identifier for the cache instance.
     * @return \PDepend\Util\Cache\CacheDriver
     * @throws \InvalidArgumentException If the configured cache driver is unknown.
     */
    protected function createCache($cacheKey)
    {
        switch ($this->configuration->cache->driver) {
            case 'file':
                return $this->createFileCache(
                    $this->configuration->cache->location,
                    $cacheKey
                );
            case 'memory':
                return $this->createMemoryCache();
        }
        throw new \InvalidArgumentException(
            "Unknown cache driver '{$this->configuration->cache->driver}' given."
        );
    }

    /**
     * Creates a new file system based cache instance.
     *
     * @param  string $location Cache root directory.
     * @param  string $cacheKey The name/identifier for the cache instance.
     * @return \PDepend\Util\Cache\Driver\FileCacheDriver
     */
    protected function createFileCache($location, $cacheKey)
    {
        return new FileCacheDriver($location, $cacheKey);
    }

    /**
     * Creates an in memory cache instance.
     *
     * @return \PDepend\Util\Cache\Driver\MemoryCacheDriver
     */
    protected function createMemoryCache()
    {
        return new MemoryCacheDriver();
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */

namespace PDepend\Util\Cache\Driver\File;

use PDepend\Util\Cache\CacheDriver;

/**
 * Directory helper for the file system based cache implementation.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */
class FileCacheDirectory
{
    /**
     * The current cache version/hash number.
     */
    const VERSION = CacheDriver::VERSION;

    /**
     * The cache root directory.
     *
     * @var string
     */
    protected $cacheDir = null;

    /**
     * Constructs a new cache directory helper instance.
     *
     * @param string $cacheDir The cache root directory.
     */
    public function __construct($cacheDir)
    {
        $this->cacheDir = $this->ensureExists($cacheDir);

        if (false === $this->isValidVersion()) {
            $this->flush();
        }
    }

    /**
     * Creates a cache directory for the given cache entry key and returns the
     * full qualified path for that cache directory.
     *
     * @param  string $key The cache for an entry.
     * @return string
     */
    public function createCacheDirectory($key)
    {
        return $this->createOrReturnCacheDirectory($key);
    }

    /**
     * Returns the full qualified path for an existing cache directory or
     * creates a new cache directory for the given cache entry key and returns
     * the full qualified path for that cache directory.
     *
     * @param  string $key The cache for an entry.
     * @return string
     */
    protected function createOrReturnCacheDirectory($key)
    {
        $path = $this->getCacheDir() . '/' . substr($key, 0, 2);
        if (false === file_exists($path)) {
            @mkdir($path, 0775, true);
        }
        return $path;
    }

    /**
     * Ensures that the given <b>$cacheDir</b> really exists.
     *
     * @param  string $cacheDir The cache root directory.
     * @return string
     */
    protected function ensureExists($cacheDir)
    {
        if (false === file_exists($cacheDir)) {
            @mkdir($cacheDir, 0775, true);
        }
        return $cacheDir;
    }

    /**
     * Tests if the current software cache version is similar to the stored
     * file system cache version.
     *
     * @return boolean
     */
    protected function isValidVersion()
    {
        return (self::VERSION === $this->readVersion());
    }

    /**
     * Reads the stored cache version number from the cache root directory.
     *
     * @return string
     */
    protected function readVersion()
    {
        if (file_exists($this->getVersionFile())) {
            return trim(file_get_contents($this->getVersionFile()));
        }
        return null;
    }

    /**
     * Writes the current software cache version into a file in the cache root
     * directory.
     *
     * @return void
     */
    protected function writeVersion()
    {
        file_put_contents($this->getVersionFile(), self::VERSION, LOCK_EX);
    }

    /**
     * Returns the file name for the used version file.
     *
     * @return string
     */
    protected function getVersionFile()
    {
        return $this->getCacheDir() . '/_version';
    }

    /**
     * Returns the cache root directory.
     *
     * @return string
     */
    protected function getCacheDir()
    {
        return $this->cacheDir;
    }

    /**
     * Flushes all contents below the configured cache root directory and writes
     * a version file with the current software version.
     *
     * @return void
     */
    protected function flush()
    {
        $this->flushDirectory($this->getCacheDir());
        $this->writeVersion();
    }

    /**
     * Deletes all files and directories below the given <b>$cacheDir</b>.
     *
     * @param string $cacheDir A cache directory.
     *
     * @return void
     */
    protected function flushDirectory($cacheDir)
    {
        foreach (new \DirectoryIterator($cacheDir) as $child) {
            $this->flushEntry($child);
        }
    }

    /**
     * Flushes the cache record for the given file info instance, independent if
     * it is a file, directory or symlink.
     *
     * @param  \SplFileInfo $file
     * @return void
     */
    protected function flushEntry(\SplFileInfo $file)
    {
        $path = $file->getRealPath();
        if ($file->isDot()) {
            return;
        } elseif ($file->isFile()) {
            @unlink($path);
        } else {
            $this->flushDirectory($path);
            @rmdir($path);
        }
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Util\Cache\Driver\File;

use PDepend\Util\Log;

/**
 * Simple garbage collector for PDepend's file cache.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class FileCacheGarbageCollector
{
    /**
     * @var string
     */
    private $cacheDir;

    /**
     * @var integer
     */
    private $minTime;

    /**
     * @param string $cacheDir
     * @param integer $maxDays
     */
    public function __construct($cacheDir, $maxDays = 30)
    {
        $this->cacheDir = $cacheDir;
        $this->minTime = time() - ($maxDays * 86400);
    }

    /**
     * Removes all outdated cache files and returns the number of garbage
     * collected files.
     *
     * @return integer
     */
    public function garbageCollect()
    {
        if (false === file_exists($this->cacheDir)) {
            return 0;
        }

        $count = 0;

        try {
            $files = new \RecursiveIteratorIterator(
                new \RecursiveDirectoryIterator($this->cacheDir)
            );
            foreach ($files as $file) {
                if ($this->isCollectibleFile($file)) {
                    $this->garbageCollectFile($file);
                    $count += 1;
                }
            }

            return $count;
        } catch (\UnexpectedValueException $e) {
            /* This may happen if PHPMD and PDepend run in parallel */
            return $count;
        }
    }

    /**
     * Checks if the given file can be removed.
     *
     * @param \SplFileInfo $file
     * @return boolean
     */
    private function isCollectibleFile(\SplFileInfo $file)
    {
        if (false === $file->isFile()) {
            return false;
        }

        $time = $file->getATime();
        if ($time > $this->minTime) {
            return false;
        }

        $time = $file->getMTime();
        if ($time > $this->minTime) {
            return false;
        }

        return true;
    }

    /**
     * Removes the given cache file.
     *
     * @param \SplFileInfo $file
     * @return void
     */
    private function garbageCollectFile(\SplFileInfo $file)
    {
        Log::debug("Removing file '{$file->getPathname()}' from cache.");

        @unlink($file->getPathname());
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */

namespace PDepend\Util\Cache\Driver;

use PDepend\Util\Cache\CacheDriver;

/**
 * A memory based cache implementation.
 *
 * This class implements the {@link \PDepend\Util\Cache\CacheDriver} interface based
 * on an in memory data structure. This means that all cached entries will get
 * lost when the php process exits.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */
class MemoryCacheDriver implements CacheDriver
{
    /**
     * Default cache entry type.
     */
    const ENTRY_TYPE = 'cache';

    /**
     * The in memory cache.
     *
     * @var array(string=>array)
     */
    protected $cache = array();

    /**
     * Current cache entry type.
     *
     * @var string
     */
    protected $type = self::ENTRY_TYPE;

    /**
     * Unique identifier within the same cache instance.
     *
     * @var string
     */
    protected $staticId = null;

    /**
     * Global stack, mainly used during testing.
     *
     * @var array
     */
    protected static $staticCache = array();

    /**
     * Instantiates a new in memory cache instance.
     */
    public function __construct()
    {
        $this->staticId = sha1(uniqid(rand(0, PHP_INT_MAX)));
    }

    /**
     * Sets the type for the next <em>store()</em> or <em>restore()</em> method
     * call. A type is something like a namespace or group for cache entries.
     *
     * Note that the cache type will be reset after each storage method call, so
     * you must invoke right before every call to <em>restore()</em> or
     * <em>store()</em>.
     *
     * @param  string $type The name or object type for the next storage method call.
     * @return \PDepend\Util\Cache\CacheDriver
     */
    public function type($type)
    {
        $this->type = $type;
        return $this;
    }

    /**
     * This method will store the given <em>$data</em> under <em>$key</em>. This
     * method can be called with a third parameter that will be used as a
     * verification token, when the a cache entry gets restored. If the stored
     * hash and the supplied hash are not identical, that cache entry will be
     * removed and not returned.
     *
     * @param  string $key  The cache key for the given data.
     * @param  mixed  $data Any data that should be cached.
     * @param  string $hash Optional hash that will be used for verification.
     * @return void
     */
    public function store($key, $data, $hash = null)
    {
        $this->cache[$this->getCacheKey($key)] = array($hash, $data);
    }

    /**
     * This method tries to restore an existing cache entry for the given
     * <em>$key</em>. If a matching entry exists, this method verifies that the
     * given <em>$hash</em> and the the value stored with cache entry are equal.
     * Then it returns the cached entry. Otherwise this method will return
     * <b>NULL</b>.
     *
     * @param  string $key  The cache key for the given data.
     * @param  string $hash Optional hash that will be used for verification.
     * @return mixed
     */
    public function restore($key, $hash = null)
    {
        $cacheKey = $this->getCacheKey($key);
        if (isset($this->cache[$cacheKey]) && $this->cache[$cacheKey][0] === $hash) {
            return $this->cache[$cacheKey][1];
        }
        return null;
    }

    /**
     * This method will remove an existing cache entry for the given identifier.
     * It will delete all cache entries where the cache key start with the given
     * <b>$pattern</b>. If no matching entry exists, this method simply does
     * nothing.
     *
     * @param  string $pattern The cache key pattern.
     * @return void
     */
    public function remove($pattern)
    {
        foreach (array_keys($this->cache) as $key) {
            if (0 === strpos($key, $pattern)) {
                unset($this->cache[$key]);
            }
        }
    }

    /**
     * Creates a prepared cache entry identifier, based on the given <em>$key</em>
     * and the <em>$type</em> property. Note that this method resets the cache
     * type, so that it is only valid for a single call.
     *
     * @param  string $key The concrete object key.
     * @return string
     */
    protected function getCacheKey($key)
    {
        $type       = $this->type;
        $this->type = self::ENTRY_TYPE;

        return "{$key}.{$type}";
    }

    /**
     * PHP's magic serialize sleep method.
     *
     * @return array
     * @since  1.0.2
     */
    public function __sleep()
    {
        self::$staticCache[$this->staticId] = $this->cache;

        return array('staticId');
    }

    /**
     * PHP's magic serialize wakeup method.
     *
     * @return void
     * @since  1.0.2
     */
    public function __wakeup()
    {
        $this->cache = self::$staticCache[$this->staticId];
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */

namespace PDepend\Util\Cache\Driver;

use PDepend\Util\Cache\CacheDriver;
use PDepend\Util\Cache\Driver\File\FileCacheDirectory;
use PDepend\Util\Cache\Driver\File\FileCacheGarbageCollector;

/**
 * A file system based cache implementation.
 *
 * This class implements the {@link \PDepend\Util\Cache\CacheDriver} interface
 * based on the local file system. It creates a special directory structure and
 * stores all cache entries in files under this directory structure.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */
class FileCacheDriver implements CacheDriver
{
    /**
     * Default cache entry type.
     */
    const ENTRY_TYPE = 'cache';

    /**
     * The cache directory handler
     *
     * @var FileCacheDirectory
     */
    protected $directory;

    /**
     * The current cache entry type.
     *
     * @var string
     */
    protected $type = self::ENTRY_TYPE;

    /**
     * Major and minor version of the currently used PHP.
     *
     * @var string
     */
    protected $version;

    /**
     * Unique key for this cache instance.
     *
     * @var   string
     * @since 1.0.0
     */
    private $cacheKey;

    /**
     * @var \PDepend\Util\Cache\Driver\File\FileCacheGarbageCollector
     */
    private $garbageCollector;

    /**
     * This method constructs a new file cache instance for the given root
     * directory.
     *
     * @param string $root     The cache root directory.
     * @param string $cacheKey Unique key for this cache instance.
     */
    public function __construct($root, $cacheKey = null)
    {
        $this->directory = new FileCacheDirectory($root);
        $this->version   = preg_replace('(^(\d+\.\d+).*)', '\\1', phpversion());

        $this->cacheKey = $cacheKey;

        $this->garbageCollect($root);
    }

    /**
     * Sets the type for the next <em>store()</em> or <em>restore()</em> method
     * call. A type is something like a namespace or group for cache entries.
     *
     * Note that the cache type will be reset after each storage method call, so
     * you must invoke right before every call to <em>restore()</em> or
     * <em>store()</em>.
     *
     * @param  string $type The name or object type for the next storage method call.
     * @return \PDepend\Util\Cache\CacheDriver
     */
    public function type($type)
    {
        $this->type = $type;
        return $this;
    }

    /**
     * This method will store the given <em>$data</em> under <em>$key</em>. This
     * method can be called with a third parameter that will be used as a
     * verification token, when the a cache entry gets restored. If the stored
     * hash and the supplied hash are not identical, that cache entry will be
     * removed and not returned.
     *
     * @param  string $key  The cache key for the given data.
     * @param  mixed  $data Any data that should be cached.
     * @param  string $hash Optional hash that will be used for verification.
     * @return void
     */
    public function store($key, $data, $hash = null)
    {
        $file = $this->getCacheFile($key);
        $this->write($file, serialize(array('hash' => $hash, 'data' => $data)));
    }

    /**
     * This method writes the given <em>$data</em> into <em>$file</em>.
     *
     * @param  string $file The cache file name.
     * @param  string $data Serialized cache data.
     * @return void
     */
    protected function write($file, $data)
    {
        $handle = fopen($file, 'wb');
        flock($handle, LOCK_EX);
        fwrite($handle, $data);
        flock($handle, LOCK_UN);
        fclose($handle);
    }

    /**
     * This method tries to restore an existing cache entry for the given
     * <em>$key</em>. If a matching entry exists, this method verifies that the
     * given <em>$hash</em> and the the value stored with cache entry are equal.
     * Then it returns the cached entry. Otherwise this method will return
     * <b>NULL</b>.
     *
     * @param  string $key  The cache key for the given data.
     * @param  string $hash Optional hash that will be used for verification.
     * @return mixed
     */
    public function restore($key, $hash = null)
    {
        $file = $this->getCacheFile($key);
        if (file_exists($file)) {
            return $this->restoreFile($file, $hash);
        }
        return null;
    }

    /**
     * This method restores a cache entry, when the given <em>$hash</em> is equal
     * to stored hash value. If both hashes are equal this method returns the
     * cached entry. Otherwise this method returns <b>NULL</b>.
     *
     * @param  string $file The cache file name.
     * @param  string $hash The verification hash.
     * @return mixed
     */
    protected function restoreFile($file, $hash)
    {
        $data = unserialize($this->read($file));
        if ($data['hash'] === $hash) {
            return $data['data'];
        }
        return null;
    }

    /**
     * This method reads the raw data from the given <em>$file</em>.
     *
     * @param  string $file The cache file name.
     * @return string
     */
    protected function read($file)
    {
        $handle = fopen($file, 'rb');
        flock($handle, LOCK_EX);

        $data = fread($handle, filesize($file));

        flock($handle, LOCK_UN);
        fclose($handle);

        return $data;
    }

    /**
     * This method will remove an existing cache entry for the given identifier.
     * It will delete all cache entries where the cache key start with the given
     * <b>$pattern</b>. If no matching entry exists, this method simply does
     * nothing.
     *
     * @param  string $pattern The cache key pattern.
     * @return void
     */
    public function remove($pattern)
    {
        $file = $this->getCacheFileWithoutExtension($pattern);
        $glob = glob("{$file}*.*");
        // avoid error if we dont find files
        if ($glob !== false) {
            foreach (glob("{$file}*.*") as $f) {
                unlink($f);
            }
        }
    }

    /**
     * This method creates the full qualified file name for a cache entry. This
     * file name is a combination of the given <em>$key</em>, the cache root
     * directory and the current entry type.
     *
     * @param  string $key The cache key for the given data.
     * @return string
     */
    protected function getCacheFile($key)
    {
        $cacheFile = $this->getCacheFileWithoutExtension($key) .
                     '.' . $this->version .
                     '.' . $this->type;

        $this->type = self::ENTRY_TYPE;

        return $cacheFile;
    }

    /**
     * This method creates the full qualified file name for a cache entry. This
     * file name is a combination of the given <em>$key</em>, the cache root
     * directory and the current entry type, but without the used cache file
     * extension.
     *
     * @param  string $key The cache key for the given data.
     * @return string
     */
    protected function getCacheFileWithoutExtension($key)
    {
        if (is_string($this->cacheKey)) {
            $key = md5($key . $this->cacheKey);
        }

        $path = $this->directory->createCacheDirectory($key);
        return "{$path}/{$key}";
    }

    /**
     * Cleans old cache files.
     *
     * @param string $root
     * @return void
     */
    protected function garbageCollect($root)
    {
        $garbageCollector = new FileCacheGarbageCollector($root);
        $garbageCollector->garbageCollect();
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Util;

/**
 * Utility class that can be used to detect simpl scalars or internal types.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
final class Type
{
    /**
     * Constants for valid php data types.
     */
    const PHP_TYPE_ARRAY   = 'array',
          PHP_TYPE_BOOLEAN = 'boolean',
          PHP_TYPE_FLOAT   = 'float',
          PHP_TYPE_INTEGER = 'integer',
          PHP_TYPE_STRING  = 'string';
    /**
     * Constants with valid php data type identifiers.
     */
    const IMAGE_ARRAY    = 'array',
          IMAGE_BOOL     = 'bool',
          IMAGE_BOOLEAN  = 'boolean',
          IMAGE_DOUBLE   = 'double',
          IMAGE_FLOAT    = 'float',
          IMAGE_INT      = 'int',
          IMAGE_INTEGER  = 'integer',
          IMAGE_MIXED    = 'mixed',
          IMAGE_REAL     = 'real',
          IMAGE_RESOURCE = 'resource',
          IMAGE_OBJECT   = 'object',
          IMAGE_STRING   = 'string',
          IMAGE_STDCLASS = 'stdclass',
          IMAGE_VOID     = 'void';

    /**
     * Constants with the metaphone representation of multiple php data types.
     */
    const IMAGE_METAPHONE_ARRAY        = 'AR',
          IMAGE_METAPHONE_BOOL         = 'BL',
          IMAGE_METAPHONE_BOOLEAN      = 'BLN',
          IMAGE_METAPHONE_DOUBLE       = 'TBL',
          IMAGE_METAPHONE_FLOAT        = 'FLT',
          IMAGE_METAPHONE_INT          = 'INT',
          IMAGE_METAPHONE_INTEGER      = 'INTJR',
          IMAGE_METAPHONE_MIXED        = 'MKST',
          IMAGE_METAPHONE_REAL         = 'RL',
          IMAGE_METAPHONE_RESOURCE     = 'RSRS',
          IMAGE_METAPHONE_OBJECT       = 'OBJKT',
          IMAGE_METAPHONE_STRING       = 'STRNK',
          IMAGE_METAPHONE_STDCLASS     = 'STTKLS',
          IMAGE_METAPHONE_UNKNOWN      = 'UNKNN',
          IMAGE_METAPHONE_UNKNOWN_TYPE = 'UNKNNTP';

    /**
     * Constants with the soundex representation of multiple php data types.
     */
    const IMAGE_SOUNDEX_ARRAY        = 'A600',
          IMAGE_SOUNDEX_BOOL         = 'B450',
          IMAGE_SOUNDEX_BOOLEAN      = 'B400',
          IMAGE_SOUNDEX_DOUBLE       = 'D140',
          IMAGE_SOUNDEX_FLOAT        = 'F430',
          IMAGE_SOUNDEX_INT          = 'I530',
          IMAGE_SOUNDEX_INTEGER      = 'I532',
          IMAGE_SOUNDEX_MIXED        = 'M230',
          IMAGE_SOUNDEX_REAL         = 'R400',
          IMAGE_SOUNDEX_RESOURCE     = 'R262',
          IMAGE_SOUNDEX_OBJECT       = 'O122',
          IMAGE_SOUNDEX_STRING       = 'S365',
          IMAGE_SOUNDEX_STDCLASS     = 'S324',
          IMAGE_SOUNDEX_UNKNOWN      = 'U525';
 
    /**
     * Constants for other types/keywords frequently used.
     */
    const IMAGE_OTHER_NULL         = 'null',
          IMAGE_OTHER_FALSE        = 'false',
          IMAGE_OTHER_TRUE         = 'true',
          IMAGE_OTHER_UNKNOWN      = 'unknown',
          IMAGE_OTHER_UNKNOWN_TYPE = 'unknown_type';

    /**
     * This property contains a mapping between a unified lower case type name
     * and the corresponding PHP extension that declares this type.
     *
     * @var array(string=>string)
     */
    private static $typeNameToExtension = null;

    /**
     * Hash with all internal namespaces/extensions. Key and value are identical
     * and contain the name of the extension.
     *
     * @var   array(string=>string)
     * @since 0.9.10
     */
    private static $internalNamespaces = null;

    /**
     * List of scalar php types.
     *
     * @var array(string)
     */
    private static $scalarTypes = array(
        self::IMAGE_ARRAY                   =>  true,
        self::IMAGE_BOOL                    =>  true,
        self::IMAGE_BOOLEAN                 =>  true,
        self::IMAGE_DOUBLE                  =>  true,
        self::IMAGE_FLOAT                   =>  true,
        self::IMAGE_INT                     =>  true,
        self::IMAGE_INTEGER                 =>  true,
        self::IMAGE_MIXED                   =>  true,
        self::IMAGE_REAL                    =>  true,
        self::IMAGE_RESOURCE                =>  true,
        self::IMAGE_OBJECT                  =>  true,
        self::IMAGE_STRING                  =>  true,
        self::IMAGE_STDCLASS                =>  true,
        self::IMAGE_VOID                    =>  true,
        self::IMAGE_OTHER_NULL              =>  true,
        self::IMAGE_OTHER_FALSE             =>  true,
        self::IMAGE_OTHER_TRUE              =>  true,
        self::IMAGE_OTHER_UNKNOWN           =>  true,
        self::IMAGE_OTHER_UNKNOWN_TYPE      =>  true,
        self::IMAGE_METAPHONE_ARRAY         =>  true,
        self::IMAGE_METAPHONE_BOOL          =>  true,
        self::IMAGE_METAPHONE_BOOLEAN       =>  true,
        self::IMAGE_METAPHONE_DOUBLE        =>  true,
        self::IMAGE_METAPHONE_FLOAT         =>  true,
        self::IMAGE_METAPHONE_INT           =>  true,
        self::IMAGE_METAPHONE_INTEGER       =>  true,
        self::IMAGE_METAPHONE_MIXED         =>  true,
        self::IMAGE_METAPHONE_OBJECT        =>  true,
        self::IMAGE_METAPHONE_REAL          =>  true,
        self::IMAGE_METAPHONE_RESOURCE      =>  true,
        self::IMAGE_METAPHONE_STRING        =>  true,
        self::IMAGE_METAPHONE_STDCLASS      =>  true,
        self::IMAGE_METAPHONE_UNKNOWN       =>  true,
        self::IMAGE_METAPHONE_UNKNOWN_TYPE  =>  true,
        self::IMAGE_SOUNDEX_ARRAY           =>  true,
        self::IMAGE_SOUNDEX_BOOL            =>  true,
        self::IMAGE_SOUNDEX_BOOLEAN         =>  true,
        self::IMAGE_SOUNDEX_DOUBLE          =>  true,
        self::IMAGE_SOUNDEX_FLOAT           =>  true,
        self::IMAGE_SOUNDEX_INT             =>  true,
        self::IMAGE_SOUNDEX_INTEGER         =>  true,
        self::IMAGE_SOUNDEX_MIXED           =>  true,
        self::IMAGE_SOUNDEX_REAL            =>  true,
        self::IMAGE_SOUNDEX_RESOURCE        =>  true,
        self::IMAGE_SOUNDEX_OBJECT          =>  true,
        self::IMAGE_SOUNDEX_STRING          =>  true,
        self::IMAGE_SOUNDEX_STDCLASS        =>  true,
        self::IMAGE_SOUNDEX_UNKNOWN         =>  true,
    );

    /**
     * List of primitive php types.
     *
     * @var array(string=>string)
     */
    private static $primitiveTypes = array(
        self::IMAGE_BOOL               =>  self::PHP_TYPE_BOOLEAN,
        self::IMAGE_BOOLEAN            =>  self::PHP_TYPE_BOOLEAN,
        self::IMAGE_SOUNDEX_BOOL       =>  self::PHP_TYPE_BOOLEAN,
        self::IMAGE_SOUNDEX_BOOLEAN    =>  self::PHP_TYPE_BOOLEAN,
        self::IMAGE_OTHER_FALSE        =>  self::PHP_TYPE_BOOLEAN,
        self::IMAGE_OTHER_TRUE         =>  self::PHP_TYPE_BOOLEAN,
        self::IMAGE_METAPHONE_BOOL     =>  self::PHP_TYPE_BOOLEAN,
        self::IMAGE_METAPHONE_BOOLEAN  =>  self::PHP_TYPE_BOOLEAN,
        self::IMAGE_REAL               =>  self::PHP_TYPE_FLOAT,
        self::IMAGE_FLOAT              =>  self::PHP_TYPE_FLOAT,
        self::IMAGE_DOUBLE             =>  self::PHP_TYPE_FLOAT,
        self::IMAGE_METAPHONE_REAL     =>  self::PHP_TYPE_FLOAT,
        self::IMAGE_METAPHONE_FLOAT    =>  self::PHP_TYPE_FLOAT,
        self::IMAGE_METAPHONE_DOUBLE   =>  self::PHP_TYPE_FLOAT,
        self::IMAGE_SOUNDEX_DOUBLE     =>  self::PHP_TYPE_FLOAT,
        self::IMAGE_SOUNDEX_FLOAT      =>  self::PHP_TYPE_FLOAT,
        self::IMAGE_SOUNDEX_REAL       =>  self::PHP_TYPE_FLOAT,
        self::IMAGE_INT                =>  self::PHP_TYPE_INTEGER,
        self::IMAGE_INTEGER            =>  self::PHP_TYPE_INTEGER,
        self::IMAGE_METAPHONE_INT      =>  self::PHP_TYPE_INTEGER,
        self::IMAGE_METAPHONE_INTEGER  =>  self::PHP_TYPE_INTEGER,
        self::IMAGE_SOUNDEX_INT        =>  self::PHP_TYPE_INTEGER,
        self::IMAGE_SOUNDEX_INTEGER    =>  self::PHP_TYPE_INTEGER,
        self::IMAGE_STRING             =>  self::PHP_TYPE_STRING,
        self::IMAGE_METAPHONE_STRING   =>  self::PHP_TYPE_STRING,
        self::IMAGE_SOUNDEX_STRING     =>  self::PHP_TYPE_STRING,
    );

    /**
     * Returns <b>true</b> if the given type is internal or part of an
     * extension.
     *
     * @param string $typeName The type name.
     *
     * @return boolean
     */
    public static function isInternalType($typeName)
    {
        self::initTypeToExtension();

        $normalizedName = ltrim($typeName, '\\');
        $normalizedName = strtolower($normalizedName);

        return isset(self::$typeNameToExtension[$normalizedName]);
    }

    /**
     * Returns the package/extension for the given type name. If no package
     * exists, this method will return <b>null</b>.
     *
     * @param string $typeName The type name.
     *
     * @return string
     */
    public static function getTypePackage($typeName)
    {
        self::initTypeToExtension();

        $normalizedName = ltrim($typeName, '\\');
        $normalizedName = strtolower($normalizedName);
        if (isset(self::$typeNameToExtension[$normalizedName])) {
            return self::$typeNameToExtension[$normalizedName];
        }
        return null;
    }

    /**
     * Returns an array with all package/extension names.
     *
     * @return array(string)
     */
    public static function getInternalNamespaces()
    {
        if (self::$internalNamespaces === null) {
            $extensions = array_values(self::initTypeToExtension());
            $extensions = array_unique($extensions);

            self::$internalNamespaces = array_combine($extensions, $extensions);
        }
        return self::$internalNamespaces;
    }

    /**
     * This method will return <b>true</b> when the given package represents a
     * php extension.
     *
     * @param string $packageName Name of a package.
     *
     * @return boolean
     */
    public static function isInternalPackage($packageName)
    {
        $packageNames = self::getInternalNamespaces();
        return isset($packageNames[strtolower($packageName)]);
    }

    /**
     * This method will return <b>true</b> when the given type identifier is in
     * the list of scalar/none-object types.
     *
     * @param string $image The type identifier.
     *
     * @return boolean
     */
    public static function isScalarType($image)
    {
        $image = strtolower($image);
        if (isset(self::$scalarTypes[$image]) === true) {
            return true;
        }
        $image = metaphone($image);
        if (isset(self::$scalarTypes[$image]) === true) {
            return true;
        }
        return isset(self::$scalarTypes[soundex($image)]);
    }

    /**
     * This method will return <b>true</b> when the given type identifier is in
     * the list of primitive types.
     *
     * @param string $image The type image.
     *
     * @return boolean
     * @since  0.9.6
     */
    public static function isPrimitiveType($image)
    {
        return (self::getPrimitiveType($image) !== null);
    }

    /**
     * This method will return a unified type image for a detected source type
     * image.
     *
     * @param string $image The found primitive type image.
     *
     * @return string
     * @since  0.9.6
     */
    public static function getPrimitiveType($image)
    {
        $image = strtolower($image);
        if (isset(self::$primitiveTypes[$image]) === true) {
            return self::$primitiveTypes[$image];
        }
        $image = metaphone($image);
        if (isset(self::$primitiveTypes[$image]) === true) {
            return self::$primitiveTypes[$image];
        }
        $image = soundex($image);
        if (isset(self::$primitiveTypes[$image]) === true) {
            return self::$primitiveTypes[$image];
        }
        return null;
    }

    /**
     * This method will return <b>true</b> when the given image describes a
     * php array type.
     *
     * @param string $image The found type image.
     *
     * @return boolean
     * @since  0.9.6
     */
    public static function isArrayType($image)
    {
        return (strtolower($image) === 'array');
    }

    /**
     * This method reads all available classes and interfaces and checks whether
     * this type belongs to an extension or is internal. All internal and extension
     * classes are collected in an internal data structure.
     *
     * @return array(string=>string)
     */
    private static function initTypeToExtension()
    {
        // Skip when already done.
        if (self::$typeNameToExtension !== null) {
            return self::$typeNameToExtension;
        }

        self::$typeNameToExtension = array('iterator' => '+standard');

        $extensionNames = get_loaded_extensions();
        $extensionNames = array_map('strtolower', $extensionNames);

        foreach ($extensionNames as $extensionName) {
            $extension = new \ReflectionExtension($extensionName);

            $classNames = $extension->getClassNames();
            $classNames = array_map('strtolower', $classNames);

            foreach ($classNames as $className) {
                self::$typeNameToExtension[$className] = '+' . $extensionName;
            }
        }

        return self::$typeNameToExtension;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Util\Coverage;

use PDepend\Source\AST\AbstractASTArtifact;

/**
 * Base interface representing a coverage report.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface Report
{
    /**
     * Returns the percentage code coverage for the given item instance.
     *
     * @param  \PDepend\Source\AST\AbstractASTArtifact $artifact
     * @return float
     */
    public function getCoverage(AbstractASTArtifact $artifact);
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Util\Coverage;

/**
 * Factory used to abstract concrete coverage report formats from the pdepend
 * application.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Factory
{
    /**
     * Factory method that tries to create coverage report instance for a given
     * path name.
     *
     * @param  string $pathName Qualified path name of a coverage report file.
     * @return \PDepend\Util\Coverage\CloverReport
     * @throws \RuntimeException When the given path name does not point to a
     *         valid coverage file or onto an unsupported coverage format.
     */
    public function create($pathName)
    {
        $sxml = $this->loadXml($pathName);
        if ($sxml->project) {
            return new CloverReport($sxml);
        }
        throw new \RuntimeException('Unsupported coverage report format.');
    }

    /**
     * Creates a simple xml instance for the xml contents that are located under
     * the given path name.
     *
     * @param  string $pathName Qualified path name of a coverage report file.
     * @return \SimpleXMLElement
     * @throws \RuntimeException When the given path name does not point to a
     *         valid xml file.
     */
    private function loadXml($pathName)
    {
        $mode = libxml_use_internal_errors(true);
        $sxml = simplexml_load_file($pathName);
        libxml_use_internal_errors($mode);

        if ($sxml === false) {
            throw new \RuntimeException(trim(libxml_get_last_error()->message));
        }
        return $sxml;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Util\Coverage;

use PDepend\Source\AST\AbstractASTArtifact;

/**
 * Coverage report implementation for clover formatted xml files.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class CloverReport implements Report
{
    /**
     * Holds the line coverage for all files found in the coverage report.
     *
     * @var array(string=>array)
     */
    private $fileLineCoverage = array();

    /**
     * Constructs a new clover report instance.
     *
     * @param \SimpleXMLElement $sxml The context simple xml element.
     */
    public function __construct(\SimpleXMLElement $sxml)
    {
        $this->readProjectCoverage($sxml->project);
    }

    /**
     * Reads the coverage information for a project.
     *
     * @param  \SimpleXMLElement $sxml Element representing the clover project tag.
     * @return void
     */
    private function readProjectCoverage(\SimpleXMLElement $sxml)
    {
        $this->readFileCoverage($sxml);
        foreach ($sxml->package as $package) {
            $this->readFileCoverage($package);
        }
    }

    /**
     * Reads the coverage information for all file elements under the given
     * parent.
     *
     * @param  \SimpleXMLElement $sxml Element representing a file parent element.
     * @return void
     */
    private function readFileCoverage(\SimpleXMLElement $sxml)
    {
        foreach ($sxml->file as $file) {
            $lines = array();
            foreach ($file->line as $line) {
                $lines[(int) $line['num']] = (0 < (int) $line['count']);
            }
            $this->fileLineCoverage[(string) $file['name']] = $lines;
        }
    }

    /**
     * Returns the percentage code coverage for the given item instance.
     *
     * @param  \PDepend\Source\AST\AbstractASTArtifact $artifact
     * @return float
     */
    public function getCoverage(AbstractASTArtifact $artifact)
    {
        $lines = $this->getLines($artifact->getCompilationUnit()->getFileName());

        $startLine = $artifact->getStartLine();
        $endLine   = $artifact->getEndLine();

        $executable = 0;
        $executed   = 0;
        for ($i = $startLine; $i <= $endLine; ++$i) {
            if (!isset($lines[$i])) {
                continue;
            }
            ++$executable;
            if ($lines[$i]) {
                ++$executed;
            }
        }

        if (0 === $executed && 1 === $executable && 0 < ($endLine - $startLine)) {
            return 100;
        }
        if ($executed === 0) {
            return 0;
        }
        return (($executed / $executable) * 100);
    }

    /**
     * Returns the lines of the covered file.
     *
     * @param  string $fileName The source file name.
     * @return array(boolean)
     */
    private function getLines($fileName)
    {
        if (isset($this->fileLineCoverage[$fileName])) {
            return $this->fileLineCoverage[$fileName];
        }
        return array();
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Util;

/**
 * Simple logging class for debug messages and extended information.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
final class Log
{
    /**
     * Log debug messages.
     */
    const DEBUG = 1;

    /**
     * The log output stream, defaults for the moment to stderr.
     *
     * @var resource
     */
    private static $stream = STDERR;

    /**
     * Are debugging messages activated?
     *
     * @var boolean
     */
    private static $debug = false;

    /**
     * Sets the log severity levels, this can be an OR combined list of valid
     * severities.
     *
     * @param integer $severity The log severity levels.
     *
     * @return void
     */
    public static function setSeverity($severity)
    {
        self::$debug = ((self::DEBUG & $severity) === $severity);
    }

    /**
     * Logs the given message with debug severity.
     *
     * @param string $message The debug log message.
     *
     * @return void
     */
    public static function debug($message)
    {
        if (self::$debug) {
            self::log($message);
        }
    }

    /**
     * Generic log method for all severities.
     *
     * @param string $message The log message.
     *
     * @return void
     */
    public static function log($message)
    {
        fwrite(self::$stream, PHP_EOL . $message);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\TextUI;

use PDepend\Engine;
use PDepend\Input\ExcludePathFilter;
use PDepend\Input\ExtensionFilter;
use PDepend\ProcessListener;
use PDepend\Report\ReportGeneratorFactory;
use PDepend\Source\AST\ASTArtifactList\PackageArtifactFilter;

/**
 * The command line runner starts a PDepend process.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Runner
{
    /**
     * Marks the default success exit.
     */
    const SUCCESS_EXIT = 0;

    /**
     * Marks an internal exception exit.
     */
    const EXCEPTION_EXIT = 2;

    /**
     * List of allowed file extensions. Default file extensions are <b>php</b>
     * and <p>php5</b>.
     *
     * @var array(string)
     */
    private $extensions = array('php', 'php5');

    /**
     * List of exclude directories. Default exclude dirs are <b>.svn</b> and
     * <b>CVS</b>.
     *
     * @var array(string)
     */
    private $excludeDirectories = array('.git', '.svn', 'CVS');

    /**
     * List of exclude namespaces.
     *
     * @var array(string)
     */
    private $excludeNamespaces = array();

    /**
     * List of source code directories and files.
     *
     * @var array(string)
     */
    private $sourceArguments = array();

    /**
     * Should the parse ignore doc comment annotations?
     *
     * @var boolean
     */
    private $withoutAnnotations = false;

    /**
     * List of log identifiers and log files.
     *
     * @var array(string=>string)
     */
    private $loggerMap = array();

    /**
     * List of cli options for loggers or analyzers.
     *
     * @var array(string=>mixed)
     */
    private $options = array();

    /**
     * This of process listeners that will be hooked into PDepend's analyzing
     * process.
     *
     * @var \PDepend\ProcessListener[]
     */
    private $processListeners = array();

    /**
     * List of error messages for all parsing errors.
     *
     * @var array(string)
     */
    private $parseErrors = array();

    /**
     * @var \PDepend\Report\ReportGeneratorFactory
     */
    private $reportGeneratorFactory;

    /**
     * @var \PDepend\Engine
     */
    private $engine;

    public function __construct(ReportGeneratorFactory $reportGeneratorFactory, Engine $engine)
    {
        $this->reportGeneratorFactory = $reportGeneratorFactory;
        $this->engine = $engine;
    }

    /**
     * Sets a list of allowed file extensions.
     *
     * NOTE: If you call this method, it will replace the default file extensions.
     *
     * @param array(string) $extensions
     * @return void
     */
    public function setFileExtensions(array $extensions)
    {
        $this->extensions = $extensions;
    }

    /**
     * Sets a list of exclude directories.
     *
     * NOTE: If this method is called, it will overwrite the default settings.
     *
     * @param array(string) $excludeDirectories
     * @return void
     */
    public function setExcludeDirectories(array $excludeDirectories)
    {
        $this->excludeDirectories = $excludeDirectories;
    }

    /**
     * Sets a list of exclude packages.
     *
     * @param array(string) $excludePackages
     * @return void
     */
    public function setExcludeNamespaces(array $excludePackages)
    {
        $this->excludeNamespaces = $excludePackages;
    }

    /**
     * Sets a list of source directories and files.
     *
     * @param array(string) $sourceArguments
     * @return void
     */
    public function setSourceArguments(array $sourceArguments)
    {
        $this->sourceArguments = $sourceArguments;
    }

    /**
     * Should the parser ignore doc comment annotations?
     *
     * @return void
     */
    public function setWithoutAnnotations()
    {
        $this->withoutAnnotations = true;
    }

    /**
     * Adds a logger to this runner.
     *
     * @param string $generatorId
     * @param string $reportFile
     * @return void
     */
    public function addReportGenerator($generatorId, $reportFile)
    {
        $this->loggerMap[$generatorId] = $reportFile;
    }

    /**
     * Adds a logger or analyzer option.
     *
     * @param string $identifier
     * @param string|array $value
     * @return void
     */
    public function addOption($identifier, $value)
    {
        $this->options[$identifier] = $value;
    }

    /**
     * Adds a process listener instance that will be hooked into PDepend's
     * analyzing process.
     *
     * @param \PDepend\ProcessListener $processListener
     * @return void
     */
    public function addProcessListener(ProcessListener $processListener)
    {
        $this->processListeners[] = $processListener;
    }

    /**
     * Starts the main PDepend process and returns <b>true</b> after a successful
     * execution.
     *
     * @return boolean
     * @throws \RuntimeException An exception with a readable error message and
     * an exit code.
     */
    public function run()
    {
        $engine = $this->engine;
        $engine->setOptions($this->options);

        if (count($this->extensions) > 0) {
            $filter = new ExtensionFilter($this->extensions);
            $engine->addFileFilter($filter);
        }

        if (count($this->excludeDirectories) > 0) {
            $exclude = $this->excludeDirectories;
            $filter  = new ExcludePathFilter($exclude);
            $engine->addFileFilter($filter);
        }

        if (count($this->excludeNamespaces) > 0) {
            $exclude = $this->excludeNamespaces;
            $filter  = new PackageArtifactFilter($exclude);
            $engine->setCodeFilter($filter);
        }

        if ($this->withoutAnnotations === true) {
            $engine->setWithoutAnnotations();
        }

        // Try to set all source directories.
        try {
            foreach ($this->sourceArguments as $sourceArgument) {
                if (is_dir($sourceArgument)) {
                    $engine->addDirectory($sourceArgument);
                } else {
                    $engine->addFile($sourceArgument);
                }
            }
        } catch (\Exception $e) {
            throw new \RuntimeException($e->getMessage(), self::EXCEPTION_EXIT);
        }

        if (count($this->loggerMap) === 0) {
            throw new \RuntimeException('No output specified.', self::EXCEPTION_EXIT);
        }

        // To append all registered loggers.
        try {
            foreach ($this->loggerMap as $generatorId => $reportFile) {
                // Create a new logger
                $generator = $this->reportGeneratorFactory->createGenerator($generatorId, $reportFile);

                $engine->addReportGenerator($generator);
            }
        } catch (\Exception $e) {
            throw new \RuntimeException($e->getMessage(), self::EXCEPTION_EXIT);
        }

        foreach ($this->processListeners as $processListener) {
            $engine->addProcessListener($processListener);
        }

        try {
            $engine->analyze();

            foreach ($engine->getExceptions() as $exception) {
                $this->parseErrors[] = $exception->getMessage();
            }
        } catch (\Exception $e) {
            throw new \RuntimeException($e->getMessage(), self::EXCEPTION_EXIT);
        }

        return self::SUCCESS_EXIT;
    }

    /**
     * This method will return <b>true</b> when there were errors during the
     * parse process.
     *
     * @return boolean
     */
    public function hasParseErrors()
    {
        return (count($this->parseErrors) > 0);
    }

    /**
     * This method will return an <b>array</b> with error messages for all
     * failures that happened during the parsing process.
     *
     * @return array(string)
     */
    public function getParseErrors()
    {
        return $this->parseErrors;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\TextUI;

use PDepend\Application;
use PDepend\Util\ConfigurationInstance;
use PDepend\Util\Log;
use PDepend\Util\Workarounds;

/**
 * Handles the command line stuff and starts the text ui runner.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Command
{
    /**
     * Marks a cli error exit.
     */
    const CLI_ERROR = 1742;

    /**
     * Marks an input error exit.
     */
    const INPUT_ERROR = 1743;

    /**
     * The recieved cli options
     *
     * @var array(string=>mixed)
     */
    private $options = array();

    /**
     * The directories/files to be analyzed
     *
     * @var string
     */
    private $source;

    /**
     * The used text ui runner.
     *
     * @var \PDepend\TextUI\Runner
     */
    private $runner = null;

    /**
     * @var \PDepend\Application
     */
    private $application;

    /**
     * Performs the main cli process and returns the exit code.
     *
     * @return integer
     */
    public function run()
    {
        $this->application = new Application();

        try {
            if ($this->parseArguments() === false) {
                $this->printHelp();
                return self::CLI_ERROR;
            }
        } catch (\Exception $e) {
            echo $e->getMessage(), PHP_EOL, PHP_EOL;

            $this->printHelp();
            return self::CLI_ERROR;
        }

        if (isset($this->options['--help'])) {
            $this->printHelp();
            return Runner::SUCCESS_EXIT;
        }
        if (isset($this->options['--usage'])) {
            $this->printUsage();
            return Runner::SUCCESS_EXIT;
        }
        if (isset($this->options['--version'])) {
            $this->printVersion();
            return Runner::SUCCESS_EXIT;
        }

        $configurationFile = false;

        if (isset($this->options['--configuration'])) {
            $configurationFile = $this->options['--configuration'];

            if (false === file_exists($configurationFile)) {
                $configurationFile = getcwd() . '/' . $configurationFile;
            }
            if (false === file_exists($configurationFile)) {
                $configurationFile = $this->options['--configuration'];
            }

            unset($this->options['--configuration']);
        } elseif (file_exists(getcwd() . '/pdepend.xml')) {
            $configurationFile = getcwd() . '/pdepend.xml';
        } elseif (file_exists(getcwd() . '/pdepend.xml.dist')) {
            $configurationFile = getcwd() . '/pdepend.xml.dist';
        }

        if ($configurationFile) {
            try {
                $this->application->setConfigurationFile($configurationFile);
            } catch (\Exception $e) {
                echo $e->getMessage(), PHP_EOL, PHP_EOL;

                $this->printHelp();
                return self::CLI_ERROR;
            }
        }

        // Create a new text ui runner
        $this->runner = $this->application->getRunner();

        $this->assignArguments();

        // Get a copy of all options
        $options = $this->options;

        // Get an array with all available log options
        $logOptions = $this->application->getAvailableLoggerOptions();

        // Get an array with all available analyzer options
        $analyzerOptions = $this->application->getAvailableAnalyzerOptions();

        foreach ($options as $option => $value) {
            if (isset($logOptions[$option])) {
                // Reduce recieved option list
                unset($options[$option]);
                // Register logger
                $this->runner->addReportGenerator(substr($option, 2), $value);
            } elseif (isset($analyzerOptions[$option])) {
                // Reduce recieved option list
                unset($options[$option]);

                if (isset($analyzerOptions[$option]['value']) && is_bool($value)) {
                    echo 'Option ', $option, ' requires a value.', PHP_EOL;
                    return self::INPUT_ERROR;
                } elseif ($analyzerOptions[$option]['value'] === 'file'
                    && file_exists($value) === false
                ) {
                    echo 'Specified file ', $option, '=', $value,
                         ' not exists.', PHP_EOL;

                    return self::INPUT_ERROR;
                } elseif ($analyzerOptions[$option]['value'] === '*[,...]') {
                    $value = array_map('trim', explode(',', $value));
                }
                $this->runner->addOption(substr($option, 2), $value);
            }
        }

        if (isset($options['--without-annotations'])) {
            // Disable annotation parsing
            $this->runner->setWithoutAnnotations();
            // Remove option
            unset($options['--without-annotations']);
        }

        if (isset($options['--optimization'])) {
            // This option is deprecated.
            echo 'Option --optimization is ambiguous.', PHP_EOL;
            // Remove option
            unset($options['--optimization']);
        }

        if (isset($options['--quiet'])) {
            $runSilent = true;
            unset($options['--quiet']);
        } else {
            $runSilent = false;
            $this->runner->addProcessListener(new \PDepend\TextUI\ResultPrinter());
        }

        if (isset($options['--notify-me'])) {
            $this->runner->addProcessListener(
                new \PDepend\DbusUI\ResultPrinter()
            );
            unset($options['--notify-me']);
        }

        if (count($options) > 0) {
            $this->printHelp();
            echo "Unknown option '", key($options), "' given.", PHP_EOL;
            return self::CLI_ERROR;
        }

        try {
            // Output current pdepend version and author
            if ($runSilent === false) {
                $this->printVersion();
                $this->printWorkarounds();
            }

            $startTime = time();

            $result = $this->runner->run();

            if ($this->runner->hasParseErrors() === true) {
                $errors = $this->runner->getParseErrors();

                printf(
                    '%sThe following error%s occurred:%s',
                    PHP_EOL,
                    count($errors) > 1 ? 's' : '',
                    PHP_EOL
                );

                foreach ($errors as $error) {
                    echo $error, PHP_EOL;
                }
                echo PHP_EOL;
            }
            if ($runSilent === false) {
                $this->printStatistics($startTime);
            }

            return $result;
        } catch (\RuntimeException $e) {
            echo PHP_EOL, PHP_EOL,
                 'Critical error: ', PHP_EOL,
                 '=============== ', PHP_EOL,
                  $e->getMessage(),  PHP_EOL;

            Log::debug($e->getTraceAsString());

            return $e->getCode();
        }
    }

    /**
     * Parses the cli arguments.
     *
     * @return boolean
     */
    protected function parseArguments()
    {
        if (!isset($_SERVER['argv'])) {
            if (false === (boolean) ini_get('register_argc_argv')) {
                // @codeCoverageIgnoreStart
                echo 'Please enable register_argc_argv in your php.ini.';
            } else {
                // @codeCoverageIgnoreEnd
                echo 'Unknown error, no $argv array available.';
            }
            echo PHP_EOL, PHP_EOL;
            return false;
        }

        $argv = $_SERVER['argv'];

        // Remove the pdepend command line file
        array_shift($argv);

        if (count($argv) === 0) {
            return false;
        }

        // Last argument must be a list of source directories
        if (strpos(end($argv), '--') !== 0) {
            $this->source = explode(',', array_pop($argv));
        }

        for ($i = 0, $c = count($argv); $i < $c; ++$i) {
            // Is it an ini_set option?
            if ($argv[$i] === '-d' && isset($argv[$i + 1])) {
                if (strpos($argv[++$i], '=') === false) {
                    ini_set($argv[$i], 'on');
                } else {
                    list($key, $value) = explode('=', $argv[$i]);

                    ini_set($key, $value);
                }
            } elseif (strpos($argv[$i], '=') === false) {
                $this->options[$argv[$i]] = true;
            } else {
                list($key, $value) = explode('=', $argv[$i]);

                $this->options[$key] = $value;
            }
        }

        return true;
    }

    /**
     * Assign CLI arguments to current runner instance
     *
     * @return bool
     */
    protected function assignArguments()
    {
        if ($this->source) {
            $this->runner->setSourceArguments($this->source);
        }

        // Check for suffix option
        if (isset($this->options['--suffix'])) {
            // Get file extensions
            $extensions = explode(',', $this->options['--suffix']);
            // Set allowed file extensions
            $this->runner->setFileExtensions($extensions);

            unset($this->options['--suffix']);
        }

        // Check for ignore option
        if (isset($this->options['--ignore'])) {
            // Get exclude directories
            $directories = explode(',', $this->options['--ignore']);
            // Set exclude directories
            $this->runner->setExcludeDirectories($directories);

            unset($this->options['--ignore']);
        }

        // Check for exclude namespace option
        if (isset($this->options['--exclude'])) {
            // Get exclude directories
            $namespaces = explode(',', $this->options['--exclude']);
            // Set exclude namespace
            $this->runner->setExcludeNamespaces($namespaces);

            unset($this->options['--exclude']);
        }

        // Check for the bad documentation option
        if (isset($this->options['--bad-documentation'])) {
            echo "Option --bad-documentation is ambiguous.", PHP_EOL;

            unset($this->options['--bad-documentation']);
        }

        $configuration = $this->application->getConfiguration();

        // Store in config registry
        ConfigurationInstance::set($configuration);

        if (isset($this->options['--debug'])) {
            unset($this->options['--debug']);

            Log::setSeverity(Log::DEBUG);
        }
    }

    /**
     * Outputs the current PDepend version.
     *
     * @return void
     */
    protected function printVersion()
    {
        $build = __DIR__ . '/../../../../../build.properties';

        if (file_exists($build)) {
            $data = @parse_ini_file($build);
            $version = $data['project.version'];
        } else {
            $version = '@package_version@';
        }

        echo 'PDepend ', $version, PHP_EOL, PHP_EOL;
    }

    /**
     * If the current PHP installation requires some workarounds or limitations,
     * this method will output a message on STDOUT.
     *
     * @return void
     */
    protected function printWorkarounds()
    {
        $workarounds = new Workarounds();

        if ($workarounds->isNotRequired()) {
            return;
        }

        echo 'Your PHP version requires some workaround:', PHP_EOL;
        foreach ($workarounds->getRequiredWorkarounds() as $workaround) {
            echo '- ', $workaround, PHP_EOL;
        }
        echo PHP_EOL;
    }

    /**
     * Outputs the base usage of PDepend.
     *
     * @return void
     */
    protected function printUsage()
    {
        $this->printVersion();
        echo 'Usage: pdepend [options] [logger] <dir[,dir[,...]]>', PHP_EOL, PHP_EOL;
    }

    /**
     * Outputs the main help of PDepend.
     *
     * @return void
     */
    protected function printHelp()
    {
        $this->printUsage();

        $length = $this->printLogOptions();
        $length = $this->printAnalyzerOptions($length);

        $this->printOption(
            '--configuration=<file>',
            'Optional PDepend configuration file.',
            $length
        );
        echo PHP_EOL;

        $this->printOption(
            '--suffix=<ext[,...]>',
            'List of valid PHP file extensions.',
            $length
        );
        $this->printOption(
            '--ignore=<dir[,...]>',
            'List of exclude directories.',
            $length
        );
        $this->printOption(
            '--exclude=<pkg[,...]>',
            'List of exclude namespaces.',
            $length
        );
        echo PHP_EOL;

        $this->printOption(
            '--without-annotations',
            'Do not parse doc comment annotations.',
            $length
        );
        echo PHP_EOL;

        $this->printOption('--quiet', 'Prints errors only.', $length);
        $this->printOption('--debug', 'Prints debugging information.', $length);
        $this->printOption('--help', 'Print this help text.', $length);
        $this->printOption('--version', 'Print the current version.', $length);

        $this->printDbusOption($length);

        $this->printOption('-d key[=value]', 'Sets a php.ini value.', $length);
        echo PHP_EOL;
    }

    /**
     * Prints all available log options and returns the length of the longest
     * option.
     *
     * @return integer
     */
    protected function printLogOptions()
    {
        $maxLength = 0;
        $options   = array();
        $logOptions = $this->application->getAvailableLoggerOptions();
        foreach ($logOptions as $option => $info) {
            // Build log option identifier
            $identifier = sprintf('%s=<%s>', $option, $info['value']);
            // Store in options array
            $options[$identifier] = $info['message'];

            $length = strlen($identifier);
            if ($length > $maxLength) {
                $maxLength = $length;
            }
        }

        ksort($options);

        $last = null;
        foreach ($options as $option => $message) {
            $current = substr($option, 0, strrpos($option, '-'));
            if ($last !== null && $last !== $current) {
                echo PHP_EOL;
            }
            $last = $current;

            $this->printOption($option, $message, $maxLength);
        }
        echo PHP_EOL;

        return $maxLength;
    }

    /**
     * Prints the analyzer options.
     *
     * @param integer $length Length of the longest option.
     *
     * @return integer
     */
    protected function printAnalyzerOptions($length)
    {
        $options = $this->application->getAvailableAnalyzerOptions();

        if (count($options) === 0) {
            return $length;
        }

        ksort($options);

        foreach ($options as $option => $info) {
            if (isset($info['value'])) {
                $option .= '=<' . $info['value'] . '>';
            } else {
                $option .= '=<value>';
            }

            $this->printOption($option, $info['message'], $length);
        }
        echo PHP_EOL;

        return $length;
    }

    /**
     * Prints a single option.
     *
     * @param string  $option  The option identifier.
     * @param string  $message The option help message.
     * @param integer $length  The length of the longest option.
     *
     * @return void
     */
    private function printOption($option, $message, $length)
    {
        // Ignore the phpunit xml option
        if (0 === strpos($option, '--phpunit-xml=')) {
            return;
        }

        // Calculate the max message length
        $mlength = 77 - $length;

        $option = str_pad($option, $length, ' ', STR_PAD_RIGHT);
        echo '  ', $option, ' ';

        $lines = explode(PHP_EOL, wordwrap($message, $mlength, PHP_EOL));
        echo array_shift($lines);

        while (($line = array_shift($lines)) !== null) {
            echo PHP_EOL, str_repeat(' ', $length + 3), $line;
        }
        echo PHP_EOL;
    }

    /**
     * Optionally outputs the dbus option when the required extension
     * is loaded.
     *
     * @param integer $length Padding length for the option.
     *
     * @return void
     */
    private function printDbusOption($length)
    {
        if (extension_loaded("dbus") === false) {
            return;
        }

        $option  = '--notify-me';
        $message = 'Show a notification after analysis.';

        $this->printOption($option, $message, $length);
    }

    /**
     * Main method that starts the command line runner.
     *
     * @return integer The exit code.
     */
    public static function main()
    {
        $command = new Command();
        return $command->run();
    }

    /**
     * @param $startTime
     */
    private function printStatistics($startTime)
    {
        $duration = time() - $startTime;
        $hours = intval($duration / 3600);
        $minutes = intval(($duration - $hours * 3600) / 60);
        $seconds = $duration % 60;
        echo PHP_EOL, 'Time: ', sprintf('%d:%02d:%02d', $hours, $minutes, $seconds);
        if (function_exists('memory_get_peak_usage')) {
            $memory = (memory_get_peak_usage(true) / (1024 * 1024));
            printf('; Memory: %4.2fMb', $memory);
        }
        echo PHP_EOL;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\TextUI;

use PDepend\Metrics\Analyzer;
use PDepend\ProcessListener;
use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Source\ASTVisitor\AbstractASTVisitListener;
use PDepend\Source\Builder\Builder;
use PDepend\Source\Tokenizer\Tokenizer;

/**
 * Prints current the PDepend status information.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ResultPrinter extends AbstractASTVisitListener implements ProcessListener
{
    /**
     * The step size.
     */
    const STEP_SIZE = 20;

    /**
     * Number of processed items.
     *
     * @var integer
     */
    private $count = 0;

    /**
     * Is called when PDepend starts the file parsing process.
     *
     * @param  \PDepend\Source\Builder\Builder $builder
     * @return void
     */
    public function startParseProcess(Builder $builder)
    {
        $this->count = 0;

        echo "Parsing source files:\n";
    }

    /**
     * Is called when PDepend has finished the file parsing process.
     *
     * @param  \PDepend\Source\Builder\Builder $builder
     * @return void
     */
    public function endParseProcess(Builder $builder)
    {
        $this->finish();
    }

    /**
     * Is called when PDepend starts parsing of a new file.
     *
     * @param  \PDepend\Source\Tokenizer\Tokenizer $tokenizer
     * @return void
     */
    public function startFileParsing(Tokenizer $tokenizer)
    {
        $this->step();
    }

    /**
     * Is called when PDepend has finished a file.
     *
     * @param  \PDepend\Source\Tokenizer\Tokenizer $tokenizer
     * @return void
     */
    public function endFileParsing(Tokenizer $tokenizer)
    {

    }

    /**
     * Is called when PDepend starts the analyzing process.
     *
     * @return void
     */
    public function startAnalyzeProcess()
    {
    }

    /**
     * Is called when PDepend has finished the analyzing process.
     *
     * @return void
     */
    public function endAnalyzeProcess()
    {
    }

    /**
     * Is called when PDepend starts the logging process.
     *
     * @return void
     */
    public function startLogProcess()
    {
        echo "Generating pdepend log files, this may take a moment.\n";
    }

    /**
     * Is called when PDepend has finished the logging process.
     *
     * @return void
     */
    public function endLogProcess()
    {
    }

    /**
     * Is called when PDepend starts a new analyzer.
     *
     * @param  \PDepend\Metrics\Analyzer $analyzer
     * @return void
     */
    public function startAnalyzer(Analyzer $analyzer)
    {
        $this->count = 0;

        $parts = explode('\\', get_class($analyzer));

        $name = preg_replace('(Analyzer$)', '', end($parts));
        $name = preg_replace('/([a-zA-Z])([a-z])(?=[A-Z])/', '$1$2 ', $name);

        echo "Calculating {$name} metrics:\n";
    }

    /**
     * Is called when PDepend has finished one analyzing process.
     *
     * @param  \PDepend\Metrics\Analyzer $analyzer
     * @return void
     */
    public function endAnalyzer(Analyzer $analyzer)
    {
        $this->finish(self::STEP_SIZE);
    }

    /**
     * Generic notification method that is called for every node start.
     *
     * @param  \PDepend\Source\AST\AbstractASTArtifact $node
     * @return void
     */
    public function startVisitNode(AbstractASTArtifact $node)
    {
        $this->step(self::STEP_SIZE);
    }

    /**
     * Prints a single dot for the current step.
     *
     * @param  integer $size
     * @return void
     */
    protected function step($size = 1)
    {
        if ($this->count > 0 && $this->count % $size === 0) {
            echo '.';
        }
        if ($this->count > 0 && $this->count % ($size * 60) === 0) {
            printf("% 6s\n", $this->count);
        }
        ++$this->count;
    }

    /**
     * Closes the current dot line.
     *
     * @param  integer $size
     * @return void
     */
    protected function finish($size = 1)
    {
        $diff = ($this->count % ($size * 60));

        if ($diff === 0) {
            printf(".% 6s\n\n", $this->count);
        } elseif ($size === 1) {
            $indent = 66 - ceil($diff / $size);
            printf(".% {$indent}s\n\n", $this->count);
        } else {
            $indent = 66 - ceil($diff / $size) + 1;
            printf("% {$indent}s\n\n", $this->count);
        }
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  */

namespace PDepend;

use PDepend\Input\CompositeFilter;
use PDepend\Input\Filter;
use PDepend\Input\Iterator;
use PDepend\Metrics\AnalyzerCacheAware;
use PDepend\Metrics\AnalyzerClassFileSystemLocator;
use PDepend\Metrics\AnalyzerFactory;
use PDepend\Metrics\AnalyzerFilterAware;
use PDepend\Metrics\AnalyzerLoader;
use PDepend\Report\CodeAwareGenerator;
use PDepend\Source\AST\ASTArtifactList\ArtifactFilter;
use PDepend\Source\AST\ASTArtifactList\CollectionArtifactFilter;
use PDepend\Source\AST\ASTArtifactList\NullArtifactFilter;
use PDepend\Source\ASTVisitor\ASTVisitor;
use PDepend\Source\Builder\Builder;
use PDepend\Source\Language\PHP\PHPBuilder;
use PDepend\Source\Language\PHP\PHPParserGeneric;
use PDepend\Source\Language\PHP\PHPTokenizerInternal;
use PDepend\Source\Tokenizer\Tokenizer;
use PDepend\Util\Cache\CacheFactory;
use PDepend\Util\Configuration;

/**
 * PDepend analyzes php class files and generates metrics.
 *
 * The PDepend is a php port/adaption of the Java class file analyzer
 * <a href="http://clarkware.com/software/JDepend.html">JDepend</a>.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Engine
{
    /**
     * Marks the storage used for runtime tokens.
     */
    const TOKEN_STORAGE = 1;

    /**
     * Marks the storag engine used for parser artifacts.
     */
    const PARSER_STORAGE = 2;

    /**
     * The system configuration.
     *
     * @var   \PDepend\Util\Configuration
     * @since 0.10.0
     */
    protected $configuration = null;

    /**
     * List of source directories.
     *
     * @var array(string)
     */
    private $directories = array();

    /**
     * List of source code file names.
     *
     * @var array(string)
     */
    private $files = array();

    /**
     * The used code node builder.
     *
     * @var \PDepend\Source\Builder\Builder
     */
    private $builder = null;

    /**
     * Generated {@link \PDepend\Source\AST\ASTNamespace} objects.
     *
     * @var \PDepend\Source\AST\ASTNamespace[]
     */
    private $namespaces = null;

    /**
     * List of all registered {@link \PDepend\Report\ReportGenerator} instances.
     *
     * @var \PDepend\Report\ReportGenerator[]
     */
    private $generators = array();

    /**
     * A composite filter for input files.
     *
     * @var \PDepend\Input\CompositeFilter
     */
    private $fileFilter = null;

    /**
     * A filter for namespace.
     *
     * @var \PDepend\Source\AST\ASTArtifactList\ArtifactFilter
     */
    private $codeFilter = null;

    /**
     * Should the parse ignore doc comment annotations?
     *
     * @var boolean
     */
    private $withoutAnnotations = false;

    /**
     * List or registered listeners.
     *
     * @var \PDepend\ProcessListener[]
     */
    private $listeners = array();

    /**
     * List of analyzer options.
     *
     * @var array(string=>mixed)
     */
    private $options = array();

    /**
     * List of all {@link \PDepend\Source\Parser\ParserException} that were caught during
     * the parsing process.
     *
     * @var \PDepend\Source\Parser\ParserException[]
     */
    private $parseExceptions = array();

    /**
     * The configured cache factory.
     *
     * @var   \PDepend\Util\Cache\CacheFactory
     * @since 1.0.0
     */
    private $cacheFactory;

    /**
     * @var \PDepend\Metrics\AnalyzerFactory
     */
    private $analyzerFactory;

    /**
     * Constructs a new php depend facade.
     *
     * @param \PDepend\Util\Configuration      $configuration   The system configuration.
     * @param \PDepend\Util\Cache\CacheFactory $cacheFactory
     * @param \PDepend\Metrics\AnalyzerFactory $analyzerFactory
     */
    public function __construct(
        Configuration $configuration,
        CacheFactory $cacheFactory,
        AnalyzerFactory $analyzerFactory
    ) {
        $this->configuration = $configuration;

        $this->codeFilter = new NullArtifactFilter();
        $this->fileFilter = new CompositeFilter();

        $this->cacheFactory = $cacheFactory;
        $this->analyzerFactory = $analyzerFactory;
    }

    /**
     * Adds the specified directory to the list of directories to be analyzed.
     *
     * @param  string $directory The php source directory.
     * @return void
     */
    public function addDirectory($directory)
    {
        $dir = realpath($directory);

        if (!is_dir($dir)) {
            throw new \InvalidArgumentException("Invalid directory '{$directory}' added.");
        }

        $this->directories[] = $dir;
    }

    /**
     * Adds a single source code file to the list of files to be analysed.
     *
     * @param  string $file The source file name.
     * @return void
     */
    public function addFile($file)
    {
        if ($file === '-' || $file === 'php://stdin') {
            $fileName = 'php://stdin';
        } else {
            $fileName = realpath($file);

            if (!is_file($fileName)) {
                throw new \InvalidArgumentException(sprintf('The given file "%s" does not exist.', $file));
            }
        }

        $this->files[] = $fileName;
    }

    /**
     * Adds a logger to the output list.
     *
     * @param  \PDepend\Report\ReportGenerator $generator The logger instance.
     * @return void
     */
    public function addReportGenerator(\PDepend\Report\ReportGenerator $generator)
    {
        $this->generators[] = $generator;
    }

    /**
     * Adds a new input/file filter.
     *
     * @param  \PDepend\Input\Filter $filter New input/file filter instance.
     * @return void
     */
    public function addFileFilter(Filter $filter)
    {
        $this->fileFilter->append($filter);
    }

    /**
     * Sets an additional code filter. These filters could be used to hide
     * external libraries and global stuff from the PDepend output.
     *
     * @param  \PDepend\Source\AST\ASTArtifactList\ArtifactFilter $filter
     * @return void
     */
    public function setCodeFilter(ArtifactFilter $filter)
    {
        $this->codeFilter = $filter;
    }

    /**
     * Sets analyzer options.
     *
     * @param  array(string=>mixed) $options The analyzer options.
     * @return void
     */
    public function setOptions(array $options = array())
    {
        $this->options = $options;
    }

    /**
     * Should the parse ignore doc comment annotations?
     *
     * @return void
     */
    public function setWithoutAnnotations()
    {
        $this->withoutAnnotations = true;
    }

    /**
     * Adds a process listener.
     *
     * @param  \PDepend\ProcessListener $listener The listener instance.
     * @return void
     */
    public function addProcessListener(ProcessListener $listener)
    {
        if (in_array($listener, $this->listeners, true) === false) {
            $this->listeners[] = $listener;
        }
    }

    /**
     * Analyzes the registered directories and returns the collection of
     * analyzed namespace.
     *
     * @return \PDepend\Source\AST\ASTNamespace[]
     */
    public function analyze()
    {
        $this->builder = new PHPBuilder();

        $this->performParseProcess();

        // Get global filter collection
        $collection = CollectionArtifactFilter::getInstance();
        $collection->setFilter($this->codeFilter);

        $collection->setFilter();

        $this->performAnalyzeProcess();

        // Set global filter for logging
        $collection->setFilter($this->codeFilter);

        $namespaces = $this->builder->getNamespaces();

        $this->fireStartLogProcess();

        foreach ($this->generators as $generator) {
            // Check for code aware loggers
            if ($generator instanceof CodeAwareGenerator) {
                $generator->setArtifacts($namespaces);
            }
            $generator->close();
        }

        $this->fireEndLogProcess();

        return ($this->namespaces = $namespaces);
    }

    /**
     * Returns the number of analyzed php classes and interfaces.
     *
     * @return integer
     */
    public function countClasses()
    {
        if ($this->namespaces === null) {
            $msg = 'countClasses() doesn\'t work before the source was analyzed.';
            throw new \RuntimeException($msg);
        }

        $classes = 0;
        foreach ($this->namespaces as $namespace) {
            $classes += $namespace->getTypes()->count();
        }
        return $classes;
    }

    /**
     * Returns an <b>array</b> with all {@link \PDepend\Source\Parser\ParserException}
     * that were caught during the parsing process.
     *
     * @return \PDepend\Source\Parser\ParserException[]
     */
    public function getExceptions()
    {
        return $this->parseExceptions;
    }

    /**
     *  Returns the number of analyzed namespaces.
     *
     * @return integer
     */
    public function countNamespaces()
    {
        if ($this->namespaces === null) {
            $msg = 'countNamespaces() doesn\'t work before the source was analyzed.';
            throw new \RuntimeException($msg);
        }

        $count = 0;
        foreach ($this->namespaces as $namespace) {
            if ($namespace->isUserDefined()) {
                ++$count;
            }
        }
        return $count;
    }

    /**
     * Returns the analyzed namespace for the given name.
     *
     * @param  string $name
     * @return \PDepend\Source\AST\ASTNamespace
     * @throws \OutOfBoundsException
     * @throws \RuntimeException
     */
    public function getNamespace($name)
    {
        if ($this->namespaces === null) {
            $msg = 'getNamespace() doesn\'t work before the source was analyzed.';
            throw new \RuntimeException($msg);
        }
        foreach ($this->namespaces as $namespace) {
            if ($namespace->getName() === $name) {
                return $namespace;
            }
        }
        throw new \OutOfBoundsException(sprintf('Unknown namespace "%s".', $name));
    }

    /**
     * Returns an array with the analyzed namespace.
     *
     * @return \PDepend\Source\AST\ASTNamespace[]
     * @throws \RuntimeException
     */
    public function getNamespaces()
    {
        if ($this->namespaces === null) {
            $msg = 'getNamespaces() doesn\'t work before the source was analyzed.';
            throw new \RuntimeException($msg);
        }
        return $this->namespaces;
    }

    /**
     * Send the start parsing process event.
     *
     * @param  \PDepend\Source\Builder\Builder $builder The used node builder instance.
     * @return void
     */
    protected function fireStartParseProcess(Builder $builder)
    {
        foreach ($this->listeners as $listener) {
            $listener->startParseProcess($builder);
        }
    }

    /**
     * Send the end parsing process event.
     *
     * @param  \PDepend\Source\Builder\Builder $builder The used node builder instance.
     * @return void
     */
    protected function fireEndParseProcess(Builder $builder)
    {
        foreach ($this->listeners as $listener) {
            $listener->endParseProcess($builder);
        }
    }

    /**
     * Sends the start file parsing event.
     *
     * @param  \PDepend\Source\Tokenizer\Tokenizer $tokenizer
     * @return void
     */
    protected function fireStartFileParsing(Tokenizer $tokenizer)
    {
        foreach ($this->listeners as $listener) {
            $listener->startFileParsing($tokenizer);
        }
    }

    /**
     * Sends the end file parsing event.
     *
     * @param  \PDepend\Source\Tokenizer\Tokenizer $tokenizer
     * @return void
     */
    protected function fireEndFileParsing(Tokenizer $tokenizer)
    {
        foreach ($this->listeners as $listener) {
            $listener->endFileParsing($tokenizer);
        }
    }

    /**
     * Sends the start analyzing process event.
     *
     * @return void
     */
    protected function fireStartAnalyzeProcess()
    {
        foreach ($this->listeners as $listener) {
            $listener->startAnalyzeProcess();
        }
    }

    /**
     * Sends the end analyzing process event.
     *
     * @return void
     */
    protected function fireEndAnalyzeProcess()
    {
        foreach ($this->listeners as $listener) {
            $listener->endAnalyzeProcess();
        }
    }

    /**
     * Sends the start log process event.
     *
     * @return void
     */
    protected function fireStartLogProcess()
    {
        foreach ($this->listeners as $listener) {
            $listener->startLogProcess();
        }
    }

    /**
     * Sends the end log process event.
     *
     * @return void
     */
    protected function fireEndLogProcess()
    {
        foreach ($this->listeners as $listener) {
            $listener->endLogProcess();
        }
    }

    /**
     * This method performs the parsing process of all source files. It expects
     * that the <b>$_builder</b> property was initialized with a concrete builder
     * implementation.
     *
     * @return void
     */
    private function performParseProcess()
    {
        // Reset list of thrown exceptions
        $this->parseExceptions = array();

        $tokenizer = new PHPTokenizerInternal();

        $this->fireStartParseProcess($this->builder);

        foreach ($this->createFileIterator() as $file) {
            $tokenizer->setSourceFile($file);

            $parser = new PHPParserGeneric(
                $tokenizer,
                $this->builder,
                $this->cacheFactory->create()
            );
            $parser->setMaxNestingLevel($this->configuration->parser->nesting);

            // Disable annotation parsing?
            if ($this->withoutAnnotations === true) {
                $parser->setIgnoreAnnotations();
            }

            $this->fireStartFileParsing($tokenizer);

            try {
                $parser->parse();
            } catch (\PDepend\Source\Parser\ParserException $e) {
                $this->parseExceptions[] = $e;
            }
            $this->fireEndFileParsing($tokenizer);
        }

        $this->fireEndParseProcess($this->builder);
    }

    /**
     * This method performs the analysing process of the parsed source files. It
     * creates the required analyzers for the registered listeners and then
     * applies them to the source tree.
     *
     * @return void
     */
    private function performAnalyzeProcess()
    {
        $analyzerLoader = $this->createAnalyzers($this->options);

        $collection = CollectionArtifactFilter::getInstance();

        $this->fireStartAnalyzeProcess();

        ini_set('xdebug.max_nesting_level', $this->configuration->parser->nesting);

        foreach ($analyzerLoader as $analyzer) {
            // Add filters if this analyzer is filter aware
            if ($analyzer instanceof AnalyzerFilterAware) {
                $collection->setFilter($this->codeFilter);
            }

            $analyzer->analyze($this->builder->getNamespaces());

            // Remove filters if this analyzer is filter aware
            $collection->setFilter();

            foreach ($this->generators as $logger) {
                $logger->log($analyzer);
            }
        }

        ini_restore('xdebug.max_nesting_level');

        $this->fireEndAnalyzeProcess();
    }

    /**
     * This method will create an iterator instance which contains all files
     * that are part of the parsing process.
     *
     * @return \Iterator
     */
    private function createFileIterator()
    {
        if (count($this->directories) === 0 && count($this->files) === 0) {
            throw new \RuntimeException('No source directory and file set.');
        }

        $fileIterator = new \AppendIterator();

        foreach ($this->files as $file) {
            $fileIterator->append(new Iterator(new \GlobIterator($file), $this->fileFilter));
        }

        foreach ($this->directories as $directory) {
            $fileIterator->append(
                new Iterator(
                    new \RecursiveIteratorIterator(
                        new \RecursiveDirectoryIterator(
                            $directory . '/',
                            \RecursiveDirectoryIterator::FOLLOW_SYMLINKS
                        )
                    ),
                    $this->fileFilter,
                    $directory
                )
            );
        }

        // TODO: It's important to validate this behavior, imho there is something
        //       wrong in the iterator code used above.
        // Strange: why is the iterator not unique and why does this loop fix it?
        $files = array();
        foreach ($fileIterator as $file) {
            if (is_string($file)) {
                $files[$file] = $file;
            } else {
                $pathname         = realpath($file->getPathname());
                $files[$pathname] = $pathname;
            }
        }

        foreach ($files as $key => $file) {
            if (!$this->fileFilter->accept($file, $file)) {
                unset($files[$key]);
            }
        }

        ksort($files);
        // END

        return new \ArrayIterator(array_values($files));
    }

    private function createAnalyzers($options)
    {
        $analyzers = $this->analyzerFactory->createRequiredForGenerators($this->generators);

        $cacheKey = md5(serialize($this->files) . serialize($this->directories));
        $cache = $this->cacheFactory->create($cacheKey);

        foreach ($analyzers as $analyzer) {
            if ($analyzer instanceof AnalyzerCacheAware) {
                $analyzer->setCache($cache);
            }
            $analyzer->setOptions($options);

            foreach ($this->listeners as $listener) {
                $analyzer->addAnalyzeListener($listener);

                if ($analyzer instanceof ASTVisitor) {
                    $analyzer->addVisitListener($listener);
                }
            }
        }

        return $analyzers;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend;

use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;

/**
 * PDepend Application
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Application
{
    private $container;

    /**
     * @var string
     */
    private $configurationFile;

    /**
     * @param string $configurationFile
     */
    public function setConfigurationFile($configurationFile)
    {
        if (!file_exists($configurationFile)) {
            throw new \InvalidArgumentException(
                sprintf('The configuration file "%s" doesn\'t exist.', $configurationFile)
            );
        }

        $this->configurationFile = $configurationFile;
    }

    /**
     * @return \PDepend\Util\Configuration
     */
    public function getConfiguration()
    {
        return $this->getContainer()->get('pdepend.configuration');
    }

    /**
     * @return \PDepend\Engine
     */
    public function getEngine()
    {
        return $this->getContainer()->get('pdepend.engine');
    }

    /**
     * @return \PDepend\TextUI\Runner
     */
    public function getRunner()
    {
        return $this->getContainer()->get('pdepend.textui.runner'); // TODO: Use standard name? textui is detail.
    }

    /**
     * @return \PDepend\Report\ReportGeneratorFactory
     */
    public function getReportGeneratorFactory()
    {
        return $this->getContainer()->get('pdepend.report_generator_factory');
    }

    /**
     * @return \PDepend\Metrics\AnalyzerFactory
     */
    public function getAnalyzerFactory()
    {
        return $this->getContainer()->get('pdepend.analyzer_factory');
    }

    private function getContainer()
    {
        if ($this->container === null) {
            $this->container = $this->createContainer();
        }

        return $this->container;
    }

    /**
     * @return \Symfony\Component\DependencyInjection\ContainerInterface
     */
    private function createContainer()
    {
        $extensions = array(new DependencyInjection\PdependExtension());

        $container = new ContainerBuilder(new ParameterBag(array()));
        $container->prependExtensionConfig('pdepend', array());
        $container->addCompilerPass(new DependencyInjection\Compiler\ProcessListenerPass());

        $loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../../../resources'));

        foreach ($extensions as $extension) {
            $container->registerExtension($extension);
        }

        if ($this->configurationFile) {
            $loader->load($this->configurationFile);
        }

        $container->compile();

        return $container;
    }

    /**
     * Returns available logger options and documentation messages.
     *
     * @return array(string => string)
     */
    public function getAvailableLoggerOptions()
    {
        return $this->getAvailableOptionsFor('pdepend.logger');
    }

    /**
     * Returns available analyzer options and documentation messages.
     *
     * @return array(string => string)
     */
    public function getAvailableAnalyzerOptions()
    {
        return $this->getAvailableOptionsFor('pdepend.analyzer');
    }

    /**
     * @return array(string => string)
     */
    private function getAvailableOptionsFor($serviceTag)
    {
        $container = $this->getContainer();

        $loggerServices = $container->findTaggedServiceIds($serviceTag);

        $options = array();

        foreach ($loggerServices as $loggerServiceTags) {
            foreach ($loggerServiceTags as $loggerServiceTag) {
                if (isset($loggerServiceTag['option']) && isset($loggerServiceTag['message'])) {
                    $options[$loggerServiceTag['option']] = array(
                        'message' => $loggerServiceTag['message'],
                        'value' => isset($loggerServiceTag['value']) ? $loggerServiceTag['value'] : 'file'
                    );
                }
            }
        }

        return $options;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Report\Jdepend;

use PDepend\Metrics\Analyzer;
use PDepend\Metrics\Analyzer\DependencyAnalyzer;
use PDepend\Report\CodeAwareGenerator;
use PDepend\Report\FileAwareGenerator;
use PDepend\Report\NoLogOutputException;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\ASTVisitor\AbstractASTVisitor;
use PDepend\Util\Utf8Util;

/**
 * Generates an xml document with the aggregated metrics. The format is borrowed
 * from <a href="http://clarkware.com/software/JDepend.html">JDepend</a>.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Xml extends AbstractASTVisitor implements CodeAwareGenerator, FileAwareGenerator
{
    /**
     * The output log file.
     *
     * @var string
     */
    private $logFile = null;

    /**
     * The raw {@link \PDepend\Source\AST\ASTNamespace} instances.
     *
     * @var \PDepend\Source\AST\ASTArtifactList
     */
    protected $code = null;

    /**
     * Set of all analyzed files.
     *
     * @var \PDepend\Source\AST\ASTCompilationUnit[]
     */
    protected $fileSet = array();

    /**
     * List of all generated project metrics.
     *
     * @var array(string=>mixed)
     */
    protected $projectMetrics = array();

    /**
     * List of all collected node metrics.
     *
     * @var array(string=>array)
     */
    protected $nodeMetrics = array();

    /**
     * The dependency result set.
     *
     * @var DependencyAnalyzer
     */
    protected $analyzer = null;

    /**
     * The Packages dom element.
     *
     * @var \DOMElement
     */
    protected $packages = null;

    /**
     * The Cycles dom element.
     *
     * @var \DOMElement
     */
    protected $cycles = null;

    /**
     * The concrete classes element for the current package.
     *
     * @var \DOMElement
     */
    protected $concreteClasses = null;

    /**
     * The abstract classes element for the current package.
     *
     * @var \DOMElement
     */
    protected $abstractClasses = null;

    /**
     * Sets the output log file.
     *
     * @param string $logFile The output log file.
     *
     * @return void
     */
    public function setLogFile($logFile)
    {
        $this->logFile = $logFile;
    }

    /**
     * Returns an <b>array</b> with accepted analyzer types. These types can be
     * concrete analyzer classes or one of the descriptive analyzer interfaces.
     *
     * @return array(string)
     */
    public function getAcceptedAnalyzers()
    {
        return array('pdepend.analyzer.dependency');
    }

    /**
     * Sets the context code nodes.
     *
     * @param  \PDepend\Source\AST\ASTArtifactList $artifacts
     * @return void
     */
    public function setArtifacts(ASTArtifactList $artifacts)
    {
        $this->code = $artifacts;
    }

    /**
     * Adds an analyzer to log. If this logger accepts the given analyzer it
     * with return <b>true</b>, otherwise the return value is <b>false</b>.
     *
     * @param  \PDepend\Metrics\Analyzer $analyzer The analyzer to log.
     * @return boolean
     */
    public function log(Analyzer $analyzer)
    {
        if ($analyzer instanceof DependencyAnalyzer) {
            $this->analyzer = $analyzer;

            return true;
        }
        return false;
    }

    /**
     * Closes the logger process and writes the output file.
     *
     * @return void
     * @throws \PDepend\Report\NoLogOutputException If the no log target exists.
     */
    public function close()
    {
        // Check for configured output
        if ($this->logFile === null) {
            throw new NoLogOutputException($this);
        }

        $dom = new \DOMDocument('1.0', 'UTF-8');

        $dom->formatOutput = true;

        $jdepend = $dom->createElement('PDepend');

        $this->packages = $jdepend->appendChild($dom->createElement('Packages'));
        $this->cycles   = $jdepend->appendChild($dom->createElement('Cycles'));

        foreach ($this->code as $node) {
            $node->accept($this);
        }

        $dom->appendChild($jdepend);
        $buffer = $dom->saveXML();
        file_put_contents($this->logFile, $buffer);
    }

    /**
     * Visits a class node.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     */
    public function visitClass(ASTClass $class)
    {
        if (!$class->isUserDefined()) {
            return;
        }

        $doc = $this->packages->ownerDocument;

        $classXml = $doc->createElement('Class');
        $classXml->setAttribute('sourceFile', (string) $class->getCompilationUnit());
        $classXml->appendChild(
            $doc->createTextNode(
                Utf8Util::ensureEncoding($class->getName())
            )
        );

        if ($class->isAbstract()) {
            $this->abstractClasses->appendChild($classXml);
        } else {
            $this->concreteClasses->appendChild($classXml);
        }
    }

    /**
     * Visits a code interface object.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function visitInterface(ASTInterface $interface)
    {
        if (!$interface->isUserDefined()) {
            return;
        }

        $doc = $this->abstractClasses->ownerDocument;

        $classXml = $doc->createElement('Class');
        $classXml->setAttribute('sourceFile', (string) $interface->getCompilationUnit());
        $classXml->appendChild(
            $doc->createTextNode(
                Utf8Util::ensureEncoding($interface->getName())
            )
        );

        $this->abstractClasses->appendChild($classXml);
    }

    /**
     * Visits a package node.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespace
     * @return void
     */
    public function visitNamespace(ASTNamespace $namespace)
    {
        if (!$namespace->isUserDefined()) {
            return;
        }

        $stats = $this->analyzer->getStats($namespace);
        if (count($stats) === 0) {
            return;
        }

        $doc = $this->packages->ownerDocument;

        $this->concreteClasses = $doc->createElement('ConcreteClasses');
        $this->abstractClasses = $doc->createElement('AbstractClasses');

        $packageXml = $doc->createElement('Package');
        $packageXml->setAttribute('name', Utf8Util::ensureEncoding($namespace->getName()));

        $statsXml = $doc->createElement('Stats');
        $statsXml->appendChild($doc->createElement('TotalClasses'))
            ->appendChild($doc->createTextNode($stats['tc']));
        $statsXml->appendChild($doc->createElement('ConcreteClasses'))
            ->appendChild($doc->createTextNode($stats['cc']));
        $statsXml->appendChild($doc->createElement('AbstractClasses'))
            ->appendChild($doc->createTextNode($stats['ac']));
        $statsXml->appendChild($doc->createElement('Ca'))
            ->appendChild($doc->createTextNode($stats['ca']));
        $statsXml->appendChild($doc->createElement('Ce'))
            ->appendChild($doc->createTextNode($stats['ce']));
        $statsXml->appendChild($doc->createElement('A'))
            ->appendChild($doc->createTextNode($stats['a']));
        $statsXml->appendChild($doc->createElement('I'))
            ->appendChild($doc->createTextNode($stats['i']));
        $statsXml->appendChild($doc->createElement('D'))
            ->appendChild($doc->createTextNode($stats['d']));

        $dependsUpon = $doc->createElement('DependsUpon');
        foreach ($this->analyzer->getEfferents($namespace) as $efferent) {
            $efferentXml = $doc->createElement('Package');
            $efferentXml->appendChild(
                $doc->createTextNode(
                    Utf8Util::ensureEncoding($efferent->getName())
                )
            );

            $dependsUpon->appendChild($efferentXml);
        }

        $usedBy = $doc->createElement('UsedBy');
        foreach ($this->analyzer->getAfferents($namespace) as $afferent) {
            $afferentXml = $doc->createElement('Package');
            $afferentXml->appendChild(
                $doc->createTextNode(
                    Utf8Util::ensureEncoding($afferent->getName())
                )
            );

            $usedBy->appendChild($afferentXml);
        }

        $packageXml->appendChild($statsXml);
        $packageXml->appendChild($this->concreteClasses);
        $packageXml->appendChild($this->abstractClasses);
        $packageXml->appendChild($dependsUpon);
        $packageXml->appendChild($usedBy);

        if (($cycles = $this->analyzer->getCycle($namespace)) !== null) {
            $cycleXml = $doc->createElement('Package');
            $cycleXml->setAttribute('Name', Utf8Util::ensureEncoding($namespace->getName()));

            foreach ($cycles as $cycle) {
                $cycleXml->appendChild($doc->createElement('Package'))
                    ->appendChild(
                        $doc->createTextNode(
                            Utf8Util::ensureEncoding($cycle->getName())
                        )
                    );
            }

            $this->cycles->appendChild($cycleXml);
        }

        foreach ($namespace->getTypes() as $type) {
            $type->accept($this);
        }

        if ($this->concreteClasses->firstChild === null
            && $this->abstractClasses->firstChild === null
        ) {
            return;
        }

        $this->packages->appendChild($packageXml);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Report\Jdepend;

use PDepend\Metrics\Analyzer;
use PDepend\Metrics\Analyzer\DependencyAnalyzer;
use PDepend\Report\CodeAwareGenerator;
use PDepend\Report\FileAwareGenerator;
use PDepend\Report\NoLogOutputException;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\ASTVisitor\AbstractASTVisitor;
use PDepend\Util\Utf8Util;
use PDepend\Util\FileUtil;
use PDepend\Util\ImageConvert;

/**
 * Generates a chart with the aggregated metrics.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Chart extends AbstractASTVisitor implements CodeAwareGenerator, FileAwareGenerator
{
    /**
     * The output file name.
     *
     * @var string
     */
    private $logFile = null;

    /**
     * The context source code.
     *
     * @var \PDepend\Source\AST\ASTArtifactList
     */
    private $code = null;

    /**
     * The context analyzer instance.
     *
     * @var \PDepend\Metrics\Analyzer\DependencyAnalyzer
     */
    private $analyzer = null;

    /**
     * Sets the output log file.
     *
     * @param string $logFile The output log file.
     *
     * @return void
     */
    public function setLogFile($logFile)
    {
        $this->logFile = $logFile;
    }

    /**
     * Returns an <b>array</b> with accepted analyzer types. These types can be
     * concrete analyzer classes or one of the descriptive analyzer interfaces.
     *
     * @return array(string)
     */
    public function getAcceptedAnalyzers()
    {
        return array('pdepend.analyzer.dependency');
    }

    /**
     * Sets the context code nodes.
     *
     * @param  \PDepend\Source\AST\ASTArtifactList $artifacts
     * @return void
     */
    public function setArtifacts(ASTArtifactList $artifacts)
    {
        $this->code = $artifacts;
    }

    /**
     * Adds an analyzer to log. If this logger accepts the given analyzer it
     * with return <b>true</b>, otherwise the return value is <b>false</b>.
     *
     * @param  \PDepend\Metrics\Analyzer $analyzer The analyzer to log.
     * @return boolean
     */
    public function log(Analyzer $analyzer)
    {
        if ($analyzer instanceof DependencyAnalyzer) {
            $this->analyzer = $analyzer;

            return true;
        }
        return false;
    }

    /**
     * Closes the logger process and writes the output file.
     *
     * @return void
     * @throws \PDepend\Report\NoLogOutputException If the no log target exists.
     */
    public function close()
    {
        // Check for configured log file
        if ($this->logFile === null) {
            throw new NoLogOutputException($this);
        }

        $bias = 0.1;

        $svg = new \DOMDocument('1.0', 'UTF-8');
        $svg->loadXML(file_get_contents(dirname(__FILE__) . '/chart.svg'));

        $layer = $svg->getElementById('jdepend.layer');

        $bad = $svg->getElementById('jdepend.bad');
        $bad->removeAttribute('xml:id');

        $good = $svg->getElementById('jdepend.good');
        $good->removeAttribute('xml:id');

        $legendTemplate = $svg->getElementById('jdepend.legend');
        $legendTemplate->removeAttribute('xml:id');

        $max = 0;
        $min = 0;

        $items = array();
        foreach ($this->code as $namespace) {
            if (!$namespace->isUserDefined()) {
                continue;
            }

            $metrics = $this->analyzer->getStats($namespace);

            if (count($metrics) === 0) {
                continue;
            }

            $size = $metrics['cc'] + $metrics['ac'];
            if ($size > $max) {
                $max = $size;
            } elseif ($min === 0 || $size < $min) {
                $min = $size;
            }

            $items[] = array(
                'size'         =>  $size,
                'abstraction'  =>  $metrics['a'],
                'instability'  =>  $metrics['i'],
                'distance'     =>  $metrics['d'],
                'name'         =>  Utf8Util::ensureEncoding($namespace->getName())
            );
        }

        $diff = (($max - $min) / 10);

        // Sort items by size
        usort(
            $items,
            create_function('$a, $b', 'return ($a["size"] - $b["size"]);')
        );

        foreach ($items as $item) {
            if ($item['distance'] < $bias) {
                $ellipse = $good->cloneNode(true);
            } else {
                $ellipse = $bad->cloneNode(true);
            }
            $r = 15;
            if ($diff !== 0) {
                $r = 5 + (($item['size'] - $min) / $diff);
            }

            $a = $r / 15;
            $e = (50 - $r) + ($item['abstraction'] * 320);
            $f = (20 - $r + 190) - ($item['instability'] * 190);

            $transform = "matrix({$a}, 0, 0, {$a}, {$e}, {$f})";

            $ellipse->setAttribute('id', uniqid('pdepend_'));
            $ellipse->setAttribute('title', $item['name']);
            $ellipse->setAttribute('transform', $transform);

            $layer->appendChild($ellipse);

            $result = preg_match('#\\\\([^\\\\]+)$#', $item['name'], $found);
            if ($result && count($found)) {
                $angle = rand(0, 314) / 100 - 1.57;
                $legend = $legendTemplate->cloneNode(true);
                $legend->setAttribute('x', $e + $r * (1 + cos($angle)));
                $legend->setAttribute('y', $f + $r * (1 + sin($angle)));
                $legend->nodeValue = $found[1];
                $legendTemplate->parentNode->appendChild($legend);
            }

        }

        $bad->parentNode->removeChild($bad);
        $good->parentNode->removeChild($good);
        $legendTemplate->parentNode->removeChild($legendTemplate);

        $temp  = FileUtil::getSysTempDir();
        $temp .= '/' . uniqid('pdepend_') . '.svg';
        $svg->save($temp);

        ImageConvert::convert($temp, $this->logFile);

        // Remove temp file
        unlink($temp);
    }
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:xlink="http://www.w3.org/1999/xlink"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="390"
   height="250"
   id="svg2924"
   sodipodi:version="0.32"
   inkscape:version="0.46"
   version="1.0"
   sodipodi:docname="chart.svg"
   inkscape:output_extension="org.inkscape.output.svg.inkscape">
  <defs
     id="defs2926">
    <linearGradient
       id="Definition_LinearGradient_76_64_78_66_b3ff4400_619e2400">
      <stop
         offset="0"
         style="stop-color: #b3ff44; stop-opacity: 1.00;"
         id="stop24" />
      <stop
         offset="1"
         style="stop-color: #619e24; stop-opacity: 1.00;"
         id="stop26" />
    </linearGradient>
    <linearGradient
       inkscape:collect="always"
       xlink:href="#Definition_LinearGradient_76_64_78_66_b3ff4400_619e2400"
       id="linearGradient2905"
       gradientUnits="userSpaceOnUse"
       x1="76.3702"
       y1="64.2934"
       x2="78.8554"
       y2="66.7786" />
    <linearGradient
       id="Definition_LinearGradient_318_84_320_87_ff9d0000_ac550000">
      <stop
         offset="0"
         style="stop-color: #ff9d00; stop-opacity: 1.00;"
         id="stop156" />
      <stop
         offset="1"
         style="stop-color: #ac5500; stop-opacity: 1.00;"
         id="stop158" />
    </linearGradient>
    <linearGradient
       inkscape:collect="always"
       xlink:href="#Definition_LinearGradient_318_84_320_87_ff9d0000_ac550000"
       id="jdepend.bad.gradient"
       gradientUnits="userSpaceOnUse"
       x1="0"
       y1="15"
       x2="15"
       y2="30" />
    <inkscape:perspective
       sodipodi:type="inkscape:persp3d"
       inkscape:vp_x="0 : 526.18109 : 1"
       inkscape:vp_y="0 : 1000 : 0"
       inkscape:vp_z="744.09448 : 526.18109 : 1"
       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
       id="perspective2932" />
    <linearGradient
       inkscape:collect="always"
       xlink:href="#Definition_LinearGradient_76_64_78_66_b3ff4400_619e2400"
       id="jdepend.good.gradient"
       gradientUnits="userSpaceOnUse"
       x1="0"
       y1="15"
       x2="15"
       y2="30" />
  </defs>
  <sodipodi:namedview
     id="base"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     gridtolerance="10000"
     guidetolerance="10"
     objecttolerance="10"
     inkscape:pageopacity="0.0"
     inkscape:pageshadow="2"
     inkscape:zoom="1.5"
     inkscape:cx="138.95468"
     inkscape:cy="125"
     inkscape:document-units="px"
     inkscape:current-layer="layer1"
     showgrid="false"
     inkscape:window-width="1280"
     inkscape:window-height="753"
     inkscape:window-x="0"
     inkscape:window-y="46" />
  <metadata
     id="metadata2929">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     inkscape:label="Layer 1"
     inkscape:groupmode="layer"
     id="layer1"
     xml:id="jdepend.layer">
    <rect
       style="opacity:1;fill:#4e9a06;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4614"
       width="373.00024"
       height="1.0000018"
       x="53.196194"
       y="-9.293786"
       transform="matrix(0.8604851,0.5094756,-0.5094738,0.8604862,0,0)" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4464"
       width="0.99999946"
       height="201"
       x="82"
       y="19.000061"
       rx="0"
       ry="0" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4466"
       width="0.99999946"
       height="201"
       x="113.99999"
       y="19.000061"
       rx="0"
       ry="0" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4468"
       width="0.99999946"
       height="201"
       x="146"
       y="19.000061"
       rx="0"
       ry="0" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4470"
       width="0.99999946"
       height="201"
       x="177.99998"
       y="19.000061"
       rx="0"
       ry="0" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4472"
       width="0.99999946"
       height="201"
       x="209.99998"
       y="19.000061"
       rx="0"
       ry="0" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4474"
       width="0.99999946"
       height="201"
       x="241.99998"
       y="19.000061"
       rx="0"
       ry="0" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4476"
       width="0.99999946"
       height="201"
       x="274"
       y="19.000061"
       rx="0"
       ry="0" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4478"
       width="0.99999946"
       height="201"
       x="305.99997"
       y="19.000061"
       rx="0"
       ry="0" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4480"
       width="0.99999946"
       height="201"
       x="337.99997"
       y="19.000061"
       rx="0"
       ry="0" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4482"
       width="0.99999946"
       height="201"
       x="369.99997"
       y="19.000061"
       rx="0"
       ry="0" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4484"
       width="331"
       height="1"
       x="40"
       y="19.000025" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4486"
       width="331"
       height="1"
       x="40"
       y="57.000023" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4488"
       width="331"
       height="1"
       x="40"
       y="38.000023" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4490"
       width="331"
       height="1"
       x="40"
       y="76.000023" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4492"
       width="331"
       height="1"
       x="40"
       y="95.000023" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4494"
       width="331"
       height="1"
       x="40"
       y="133.00003" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4496"
       width="331"
       height="1"
       x="40"
       y="114.00002" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4498"
       width="331"
       height="1"
       x="40"
       y="152.00005" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4500"
       width="331"
       height="1"
       x="40"
       y="171.00005" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4502"
       width="331"
       height="1"
       x="40"
       y="190.00006" />
    <rect
       style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4504"
       width="331"
       height="1"
       x="40"
       y="209.00006" />
    <rect
       style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4462"
       width="0.99999946"
       height="201"
       x="49.999996"
       y="19.000061"
       rx="0"
       ry="0" />
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="83.181007"
       y="231.87305"
       id="text4506"><tspan
         sodipodi:role="line"
         id="tspan4508"
         x="83.181007"
         y="231.87305">0.1</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="114.70088"
       y="231.87305"
       id="text4510"><tspan
         sodipodi:role="line"
         id="tspan4512"
         x="114.70088"
         y="231.87305">0.2</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="242.95323"
       y="231.87305"
       id="text4514"><tspan
         sodipodi:role="line"
         id="tspan4516"
         x="242.95323"
         y="231.87305">0.6</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="210.84497"
       y="231.87305"
       id="text4518"><tspan
         sodipodi:role="line"
         id="tspan4520"
         x="210.84497"
         y="231.87305">0.5</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="178.72696"
       y="231.87305"
       id="text4522"><tspan
         sodipodi:role="line"
         id="tspan4524"
         x="178.72696"
         y="231.87305">0.4</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="146.74567"
       y="231.87305"
       id="text4526"><tspan
         sodipodi:role="line"
         id="tspan4528"
         x="146.74567"
         y="231.87305">0.3</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="307.16241"
       y="231.87305"
       id="text4530"><tspan
         sodipodi:role="line"
         id="tspan4532"
         x="307.16241"
         y="231.87305">0.8</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="275.07858"
       y="231.87305"
       id="text4534"><tspan
         sodipodi:role="line"
         id="tspan4536"
         x="275.07858"
         y="231.87305">0.7</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="371.16162"
       y="231.87305"
       id="text4538"><tspan
         sodipodi:role="line"
         id="tspan4540"
         x="371.16162"
         y="231.87305">1.0</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="339.25113"
       y="231.87305"
       id="text4542"><tspan
         sodipodi:role="line"
         id="tspan4544"
         x="339.25113"
         y="231.87305">0.9</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="50.533203"
       y="231.87305"
       id="text4546"><tspan
         sodipodi:role="line"
         id="tspan4548"
         x="50.533203"
         y="231.87305">0.0</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="28.533201"
       y="193.87793"
       id="text4550"><tspan
         sodipodi:role="line"
         id="tspan4552"
         x="28.533201"
         y="193.87793">0.1</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="28.533201"
       y="174.87793"
       id="text4554"><tspan
         sodipodi:role="line"
         id="tspan4556"
         x="28.533201"
         y="174.87793">0.2</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="28.533201"
       y="98.87793"
       id="text4558"><tspan
         sodipodi:role="line"
         id="tspan4560"
         x="28.533201"
         y="98.87793">0.6</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="28.533201"
       y="117.87792"
       id="text4562"><tspan
         sodipodi:role="line"
         id="tspan4564"
         x="28.533201"
         y="117.87792">0.5</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="28.533201"
       y="136.87793"
       id="text4566"><tspan
         sodipodi:role="line"
         id="tspan4568"
         x="28.533201"
         y="136.87793">0.4</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="28.533201"
       y="155.87793"
       id="text4570"><tspan
         sodipodi:role="line"
         id="tspan4572"
         x="28.533201"
         y="155.87793">0.3</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="28.533201"
       y="60.875481"
       id="text4574"><tspan
         sodipodi:role="line"
         id="tspan4576"
         x="28.533201"
         y="60.875481">0.8</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="28.533201"
       y="79.87793"
       id="text4578"><tspan
         sodipodi:role="line"
         id="tspan4580"
         x="28.533201"
         y="79.87793">0.7</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="28.162107"
       y="22.87793"
       id="text4582"><tspan
         sodipodi:role="line"
         id="tspan4584"
         x="28.162107"
         y="22.87793">1.0</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="28.533201"
       y="41.875492"
       id="text4586"><tspan
         sodipodi:role="line"
         id="tspan4588"
         x="28.533201"
         y="41.875492">0.9</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="28.939205"
       y="212.87793"
       id="text4590"><tspan
         sodipodi:role="line"
         id="tspan4592"
         x="28.939205"
         y="212.87793">0.0</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="195.05258"
       y="247.85966"
       id="text4604"
       transform="scale(1.0000012,0.9999988)"><tspan
         sodipodi:role="line"
         id="tspan4606"
         x="195.05258"
         y="247.85966">Abstraction</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
       x="-126.09961"
       y="10.589844"
       id="text4608"
       transform="matrix(0,-1,1,0,0,0)"><tspan
         sodipodi:role="line"
         id="tspan4610"
         x="-126.09961"
         y="10.589844">Instability</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:9px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Chancery L"
       x="313.30417"
       y="246.10596"
       id="text2692"><tspan
         sodipodi:role="line"
         id="tspan2694"
         x="313.30417"
         y="246.10596"
         style="font-size:9px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#2e3436;font-family:Arial; Italic">Generated by PDepend</tspan></text>
    <ellipse
       sodipodi:ry="15"
       sodipodi:rx="15"
       sodipodi:cy="15"
       sodipodi:cx="15"
       id="jdepend.bad"
       xml:id="jdepend.bad"
       style="fill:url(#jdepend.bad.gradient);stroke:none"
       ry="15"
       rx="15"
       cy="15"
       cx="15"
       transform="translate(163,4)" />
    <ellipse
       sodipodi:ry="15"
       sodipodi:rx="15"
       sodipodi:cy="15"
       sodipodi:cx="15"
       id="jdepend.good"
       xml:id="jdepend.good"
       style="fill:url(#jdepend.good.gradient);stroke:none"
       ry="15"
       rx="15"
       cy="15"
       cx="15"
       transform="matrix(0.6,0,0,0.6,41,10)" />
  </g>
  <g>
    <text
       xml:space="preserve"
       style="font-size:4px;font-family:Arial;fill:#2e3436;"
       x="195.05258"
       y="120.85966"
       xml:id="jdepend.legend">Package</text>
  </g>
</svg>
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Report;

/**
 * Marker interface for a log file aware logger.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface FileAwareGenerator extends ReportGenerator
{
    /**
     * Sets the output log file.
     *
     * @param string $logFile The output log file.
     *
     * @return void
     */
    public function setLogFile($logFile);
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Report;

use PDepend\Source\AST\ASTArtifactList;

/**
 * A logger that implements this interface needs the analyzed code structure.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface CodeAwareGenerator extends ReportGenerator
{
    /**
     * Sets the context code nodes.
     *
     * @param  \PDepend\Source\AST\ASTArtifactList $artifacts
     * @return void
     */
    public function setArtifacts(ASTArtifactList $artifacts);
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="390"
   height="250"
   id="svg5110"
   sodipodi:version="0.32"
   inkscape:version="0.46"
   version="1.0"
   sodipodi:docname="pyramid.svg"
   inkscape:output_extension="org.inkscape.output.svg.inkscape">
  <defs
     id="defs5112">
    <inkscape:perspective
       sodipodi:type="inkscape:persp3d"
       inkscape:vp_x="0 : 526.18109 : 1"
       inkscape:vp_y="0 : 1000 : 0"
       inkscape:vp_z="744.09448 : 526.18109 : 1"
       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
       id="perspective5118" />
  </defs>
  <sodipodi:namedview
     id="base"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     gridtolerance="10000"
     guidetolerance="10"
     objecttolerance="10"
     inkscape:pageopacity="0.0"
     inkscape:pageshadow="2"
     inkscape:zoom="1.5"
     inkscape:cx="179.96345"
     inkscape:cy="96.137457"
     inkscape:document-units="px"
     inkscape:current-layer="layer1"
     showgrid="false"
     inkscape:window-width="1280"
     inkscape:window-height="753"
     inkscape:window-x="0"
     inkscape:window-y="46" />
  <metadata
     id="metadata5115">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     inkscape:label="Layer 1"
     inkscape:groupmode="layer"
     id="layer1">
    <rect
       style="fill:#555753"
       width="0"
       height="0"
       x="0"
       y="0"
       rx="0"
       ry="0"
       id="rect8982"
       xml:id="threshold.low" />
    <rect
       style="fill:#73d216"
       width="0"
       height="0"
       x="0"
       y="0"
       rx="0"
       ry="0"
       id="rect8983"
       xml:id="threshold.average" />
    <rect
       style="fill:#f57900"
       width="0"
       height="0"
       x="0"
       y="0"
       rx="0"
       ry="0"
       id="rect2834"
       xml:id="threshold.high" />
    <rect
       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4954"
       width="118.69567"
       height="16.956522"
       x="232.7668"
       y="185.67191"
       rx="2.9780269"
       ry="0" />
    <rect
       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4956"
       width="157.2332"
       height="34"
       x="232.7668"
       y="201"
       rx="3.9449191"
       ry="0" />
    <rect
       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4958"
       width="80.158104"
       height="33.913044"
       x="154.15019"
       y="122.47035"
       rx="2.0111351"
       ry="0" />
    <rect
       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4960"
       width="234.30832"
       height="34"
       x="0"
       y="201"
       rx="5.8787031"
       ry="0" />
    <rect
       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4962"
       width="195.77077"
       height="16.956522"
       x="38.537552"
       y="185.67191"
       rx="4.9118109"
       ry="0" />
    <rect
       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4964"
       width="157.2332"
       height="16.956522"
       x="77.075104"
       y="170.25687"
       rx="3.9449191"
       ry="0" />
    <rect
       style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4966"
       width="118.69567"
       height="16.956522"
       x="115.61267"
       y="154.84189"
       rx="2.9780269"
       ry="0" />
    <rect
       style="opacity:1;fill:#d3d7cf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4968"
       width="231.22531"
       height="30.83004"
       x="1.541504"
       y="202.62846"
       rx="5.8013515"
       ry="0" />
    <rect
       style="opacity:1;fill:#d3d7cf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4970"
       width="192.68774"
       height="15.41502"
       x="40.079056"
       y="187.21365"
       rx="4.8344593"
       ry="0" />
    <rect
       style="opacity:1;fill:#d3d7cf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4972"
       width="154.15019"
       height="15.41502"
       x="78.616608"
       y="171.79837"
       rx="3.8675678"
       ry="0" />
    <rect
       style="opacity:1;fill:#d3d7cf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4974"
       width="115.61266"
       height="15.41502"
       x="117.15414"
       y="156.38339"
       rx="2.9006755"
       ry="0" />
    <rect
       style="opacity:1;fill:#fcaf3e;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4976"
       width="77.075096"
       height="30.83004"
       x="155.6917"
       y="124.01187"
       rx="1.9337839"
       ry="0" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4978"
       width="154.15019"
       height="30.83004"
       x="234.3083"
       y="202.62846"
       rx="3.8675678"
       ry="0" />
    <rect
       style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4980"
       width="115.61266"
       height="15.41502"
       x="234.3083"
       y="187.21341"
       rx="2.9006755"
       ry="0" />
    <rect
       style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4982"
       xml:id="rect.andc"
       width="38.537548"
       height="15.43004"
       x="194.22925"
       y="124.01187"
       rx="0.96689194"
       ry="0" />
    <rect
       style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect2851"
       xml:id="rect.ahh"
       width="38.537548"
       height="15.4"
       x="194.22925"
       y="139.41187"
       rx="0.96689194"
       ry="0" />
    <rect
       style="opacity:1;fill:#f57900;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4984"
       xml:id="rect.noc-nop"
       width="38.537548"
       height="15.41502"
       x="117.15414"
       y="156.38339"
       rx="0.80574334" />
    <rect
       style="opacity:1;fill:#f57900;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4986"
       xml:id="rect.nom-noc"
       width="38.537548"
       height="15.41502"
       x="78.616608"
       y="171.79837"
       rx="0.80574334" />
    <rect
       style="opacity:1;fill:#73d216;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4988"
       xml:id="rect.loc-nom"
       width="38.537548"
       height="15.41502"
       x="40.079056"
       y="187.21341"
       rx="0.80574334" />
    <rect
       style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4990"
       xml:id="rect.cyclo-loc"
       width="38.537548"
       height="15.41502"
       x="1.541504"
       y="202.62846"
       rx="0.80574334" />
    <rect
       style="opacity:1;fill:#f57900;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4992"
       xml:id="rect.calls-nom"
       width="38.537548"
       height="15.41502"
       x="311.38339"
       y="187.21341"
       rx="0.80574334" />
    <rect
       style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4994"
       xml:id="rect.fanout-calls"
       width="38.537548"
       height="15.41502"
       x="349.92096"
       y="202.62846"
       rx="0.80574334" />
    <rect
       style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4996"
       width="231.22531"
       height="1"
       x="1.541504"
       y="217.04344"
       rx="5.8013515"
       ry="0" />
    <rect
       style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect4998"
       width="192.68774"
       height="1"
       x="40.079056"
       y="201.62846"
       rx="4.8344593"
       ry="0" />
    <rect
       style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect5000"
       width="154.15019"
       height="1"
       x="78.616608"
       y="186.21341"
       rx="3.8675678"
       ry="0" />
    <rect
       style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect5002"
       width="115.61266"
       height="1"
       x="117.15414"
       y="170.79837"
       rx="2.9006755"
       ry="0" />
    <rect
       style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect5004"
       width="115.61266"
       height="1"
       x="234.3083"
       y="201.62846"
       rx="2.9006755"
       ry="0" />
    <rect
       style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect5006"
       width="154.15019"
       height="1"
       x="234.3083"
       y="217.04344"
       rx="3.8675678"
       ry="0" />
    <rect
       style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="rect5008"
       width="77.075096"
       height="1"
       x="155.6917"
       y="138.42685"
       rx="1.9337839"
       ry="0" />
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       x="158"
       y="135"
       title="Average Number of Derived Classes"
       id="text5010"><tspan
         sodipodi:role="line"
         title="Average Number of Derived Classes"
         id="tspan5012"
         x="158"
         y="135">ANDC</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       x="158"
       y="151"
       title="Average Hierarchy Height"
       id="text5014"><tspan
         sodipodi:role="line"
         title="Average Hierarchy Height"
         id="tspan5016"
         x="158"
         y="151">AHH</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       x="158"
       y="168"
       title="Number Of Packages"
       id="text5018"><tspan
         sodipodi:role="line"
         title="Number Of Packages"
         id="tspan5020"
         x="158"
         y="168">NOP</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       x="119"
       y="183.00002"
       id="text5022"
       title="Number Of Classes"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Number Of Classes"
         id="tspan5024"
         x="119"
         y="183.00002">NOC</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       x="81"
       y="198.00002"
       id="text5026"
       title="Number Of Methods (Methods+Functions)"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Number Of Methods (Methods+Functions)"
         id="tspan5028"
         x="81"
         y="198.00002">NOM</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       x="42"
       y="213.00002"
       id="text5030"
       title="Lines Of Code (Non Comment and Non Whitespace Lines)"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Lines Of Code (Non Comment and Non Whitespace Lines)"
         id="tspan5032"
         x="42"
         y="213.00002">LOC</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       x="3"
       y="230.00002"
       id="text5034"
       title="Cyclomatic Complexity"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Cyclomatic Complexity"
         id="tspan5036"
         x="3"
         y="230.00002">CYCLO</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:end;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       x="308.85785"
       y="198.00043"
       id="text5038"
       title="Number Of Methods (Methods+Functions)"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Number Of Methods (Methods+Functions)"
         id="tspan5040"
         x="308.85785"
         y="198.00043">NOM</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       x="348"
       y="213.00002"
       id="text5042"
       title="Number of Operation Calls"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Number of Operation Calls"
         id="tspan5044"
         x="348"
         y="213.00002">CALLS</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       x="387"
       y="230.00002"
       id="text5046"
       title="Number of Called Classes"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Number of Called Classes"
         id="tspan5048"
         x="387"
         y="230.00002">FANOUT</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       title="Number of Called Classes"
       x="236"
       y="230.00002"
       id="text5050"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Number of Called Classes"
         id="tspan5052"
         xml:id="pdepend.fanout"
         x="236"
         y="230.00002">8590</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       title="Number of Operation Calls"
       x="236"
       y="213.00002"
       id="text5054"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Number of Operation Calls"
         id="tspan5056"
         xml:id="pdepend.calls"
         x="236"
         y="213.00002">15128</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       title="Cyclomatic Complexity"
       x="232"
       y="230.00002"
       id="text5058"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Cyclomatic Complexity"
         id="tspan5060"
         xml:id="pdepend.cyclo"
         x="232"
         y="230.00002">5579</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       title="Lines Of Code (Non Comment and Non Whitespace Lines)"
       x="232"
       y="213.00002"
       id="text5062"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         xml:id="pdepend.loc"
         title="Lines Of Code (Non Comment and Non Whitespace Lines)"
         id="tspan5064"
         x="232"
         y="213.00002">35175</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       title="Number Of Methods (Methods+Functions)"
       x="232"
       y="198.00002"
       id="text5066"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Number Of Methods (Methods+Functions)"
         id="tspan5068"
         xml:id="pdepend.nom"
         x="232"
         y="198.00002">3618</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       title="Number Of Packages"
       x="232"
       y="168.00002"
       id="text5070"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Number Of Packages"
         id="tspan5072"
         xml:id="pdepend.nop"
         x="232"
         y="168.00002">19</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       title="Number Of Classes"
       x="232"
       y="183.00002"
       id="text5074"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Number Of Classes"
         id="tspan5076"
         xml:id="pdepend.noc"
         x="232"
         y="183.00002">384</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       title="Average Number of Derived Classes"
       x="232"
       y="135.00002"
       id="text5078"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Average Number of Derived Classes"
         id="tspan5080"
         xml:id="pdepend.andc"
         x="232"
         y="135.00002">0,31</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       title="Average Hierarchy Height"
       x="232"
       y="151.00002"
       id="text5082"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Average Hierarchy Height"
         id="tspan5084"
         xml:id="pdepend.ahh"
         x="232"
         y="151.00002">0,12</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       title="Ratio: Number of Classes / Number of Packages"
       x="119"
       y="168.00002"
       id="text5086"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Ratio: Number of Classes / Number of Packages"
         id="tspan5088"
         xml:id="pdepend.noc-nop"
         x="119"
         y="168.00002">20,21</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       title="Ratio: Number of Methods / Number of Classes"
       x="81"
       y="183.00002"
       id="text5090"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Ratio: Number of Methods / Number of Classes"
         id="tspan5092"
         xml:id="pdepend.nom-noc"
         x="81"
         y="183.00002">9,42</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       title="Ratio: Lines of Code / Number of Methods"
       x="42"
       y="198.00002"
       id="text5094"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Ratio: Lines of Code / Number of Methods"
         id="tspan5096"
         xml:id="pdepend.loc-nom"
         x="42"
         y="198.00002">9,72</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       title="Ratio: Cyclomatic Complexity / Lines of Code"
       x="3"
       y="213.00002"
       id="text5098"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Ratio: Cyclomatic Complexity / Lines of Code"
         id="tspan5100"
         xml:id="pdepend.cyclo-loc"
         x="3"
         y="213.00002">0,15</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       title="Ratio: Number of Called Classes(FANOUT) / Number of Operation Calls"
       x="388.56299"
       y="213.00002"
       id="text5102"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Ratio: Number of Called Classes(FANOUT) / Number of Operation Calls"
         id="tspan5104"
         xml:id="pdepend.fanout-calls"
         x="388.56299"
         y="213.00002">0,561</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       title="Ratio: Number of Operation Calls / Number of Methods (Methods+Functions)"
       x="348"
       y="198.00002"
       id="text5106"
       transform="scale(0.9999985,1.0000015)"><tspan
         sodipodi:role="line"
         title="Ratio: Number of Operation Calls / Number of Methods (Methods+Functions)"
         id="tspan5108"
         xml:id="pdepend.calls-nom"
         x="348"
         y="198.00002">4,18</tspan></text>
    <text
       xml:space="preserve"
       style="font-size:8px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:end;text-anchor:end;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
       x="386.39493"
       y="246.10596"
       id="text2692"><tspan
         sodipodi:role="line"
         id="tspan2694"
         x="386.39493"
         y="246.10596"
         style="font-size:9px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;text-anchor:end;fill:#2e3436;font-family:Arial;">Generated  by PDepend</tspan></text>
    <path
       sodipodi:type="arc"
       style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="path3780"
       sodipodi:cx="53.333332"
       sodipodi:cy="285.66666"
       sodipodi:rx="12"
       sodipodi:ry="10.333333"
       d="M 65.333332,285.66666 A 12,10.333333 0 1 1 41.333332,285.66666 A 12,10.333333 0 1 1 65.333332,285.66666 z"
       transform="matrix(0.375,0,0,0.4354839,-5.4999995,119.09677)" />
    <text
       xml:space="preserve"
       style="font-size:8px;font-style:normal;font-weight:bold;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Chancery L;"
       x="32.386719"
       y="246.64209"
       id="text3782"><tspan
         sodipodi:role="line"
         id="tspan3784"
         x="32.386719"
         y="246.64209"
         style="font-size:9px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#2e3436;font-family:Arial;">Low</tspan></text>
    <path
       sodipodi:type="arc"
       style="opacity:1;fill:#73d216;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="path3786"
       sodipodi:cx="53.333332"
       sodipodi:cy="285.66666"
       sodipodi:rx="12"
       sodipodi:ry="10.333333"
       d="M 65.333332,285.66666 A 12,10.333333 0 1 1 41.333332,285.66666 A 12,10.333333 0 1 1 65.333332,285.66666 z"
       transform="matrix(0.375,0,0,0.4354839,54.5,119.09677)" />
    <text
       xml:space="preserve"
       style="font-size:8px;font-style:normal;font-weight:bold;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Chancery L;"
       x="102.38672"
       y="245.77417"
       id="text3788"><tspan
         sodipodi:role="line"
         id="tspan3790"
         x="102.38672"
         y="245.77417"
         style="font-size:9px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#2e3436;font-family:Arial;">Average</tspan></text>
    <path
       sodipodi:type="arc"
       style="opacity:1;fill:#f57900;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
       id="path3792"
       sodipodi:cx="53.333332"
       sodipodi:cy="285.66666"
       sodipodi:rx="12"
       sodipodi:ry="10.333333"
       d="M 65.333332,285.66666 A 12,10.333333 0 1 1 41.333332,285.66666 A 12,10.333333 0 1 1 65.333332,285.66666 z"
       transform="matrix(0.375,0,0,0.4354839,132.5,119.09677)" />
    <text
       xml:space="preserve"
       style="font-size:8px;font-style:normal;font-weight:bold;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Chancery L;"
       x="170.38672"
       y="245.77417"
       id="text3794"><tspan
         sodipodi:role="line"
         id="tspan3796"
         x="170.38672"
         y="245.77417"
         style="font-size:9px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#2e3436;font-family:Arial;">High</tspan></text>
  </g>
</svg>
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Report\Overview;

use PDepend\Metrics\Analyzer;
use PDepend\Metrics\Analyzer\CouplingAnalyzer;
use PDepend\Metrics\Analyzer\CyclomaticComplexityAnalyzer;
use PDepend\Metrics\Analyzer\InheritanceAnalyzer;
use PDepend\Metrics\Analyzer\NodeCountAnalyzer;
use PDepend\Metrics\Analyzer\NodeLocAnalyzer;
use PDepend\Report\FileAwareGenerator;
use PDepend\Report\NoLogOutputException;
use PDepend\Util\FileUtil;
use PDepend\Util\ImageConvert;

/**
 * This logger generates a system overview pyramid, as described in the book
 * <b>Object-Oriented Metrics in Practice</b>.
 *
 * http://www.springer.com/computer/programming/book/978-3-540-24429-5
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Pyramid implements FileAwareGenerator
{
    /**
     * The output file name.
     *
     * @var string
     */
    private $logFile = null;

    /**
     * The used coupling analyzer.
     *
     * @var \PDepend\Metrics\Analyzer\CouplingAnalyzer
     */
    private $coupling = null;

    /**
     * The used cyclomatic complexity analyzer.
     *
     * @var \PDepend\Metrics\Analyzer\CyclomaticComplexityAnalyzer
     */
    private $cyclomaticComplexity = null;

    /**
     * The used inheritance analyzer.
     *
     * @var \PDepend\Metrics\Analyzer\InheritanceAnalyzer
     */
    private $inheritance = null;

    /**
     * The used node count analyzer.
     *
     * @var \PDepend\Metrics\Analyzer\NodeCountAnalyzer
     */
    private $nodeCount = null;

    /**
     * The used node loc analyzer.
     *
     * @var \PDepend\Metrics\Analyzer\NodeLocAnalyzer
     */
    private $nodeLoc = null;

    /**
     * Holds defined thresholds for the computed proportions. This set is based
     * on java thresholds, we should find better values for php projects.
     *
     * @var array(string => array)
     */
    private $thresholds = array(
        'cyclo-loc'     =>  array(0.16, 0.20, 0.24),
        'loc-nom'       =>  array(7, 10, 13),
        'nom-noc'       =>  array(4, 7, 10),
        'noc-nop'       =>  array(6, 17, 26),
        'calls-nom'     =>  array(2.01, 2.62, 3.2),
        'fanout-calls'  =>  array(0.56, 0.62, 0.68),
        'andc'          =>  array(0.25, 0.41, 0.57),
        'ahh'           =>  array(0.09, 0.21, 0.32)
    );

    /**
     * Sets the output log file.
     *
     * @param string $logFile The output log file.
     *
     * @return void
     */
    public function setLogFile($logFile)
    {
        $this->logFile = $logFile;
    }

    /**
     * Returns an <b>array</b> with accepted analyzer types. These types can be
     * concrete analyzer classes or one of the descriptive analyzer interfaces.
     *
     * @return array(string)
     */
    public function getAcceptedAnalyzers()
    {
        return array(
            'pdepend.analyzer.coupling',
            'pdepend.analyzer.cyclomatic_complexity',
            'pdepend.analyzer.inheritance',
            'pdepend.analyzer.node_count',
            'pdepend.analyzer.node_loc',
        );
    }

    /**
     * Adds an analyzer to log. If this logger accepts the given analyzer it
     * with return <b>true</b>, otherwise the return value is <b>false</b>.
     *
     * @param  \PDepend\Metrics\Analyzer $analyzer The analyzer to log.
     * @return boolean
     */
    public function log(Analyzer $analyzer)
    {
        if ($analyzer instanceof CyclomaticComplexityAnalyzer) {
            $this->cyclomaticComplexity = $analyzer;
        } elseif ($analyzer instanceof CouplingAnalyzer) {
            $this->coupling = $analyzer;
        } elseif ($analyzer instanceof InheritanceAnalyzer) {
            $this->inheritance = $analyzer;
        } elseif ($analyzer instanceof NodeCountAnalyzer) {
            $this->nodeCount = $analyzer;
        } elseif ($analyzer instanceof NodeLocAnalyzer) {
            $this->nodeLoc = $analyzer;
        } else {
            return false;
        }
        return true;
    }

    /**
     * Closes the logger process and writes the output file.
     *
     * @return void
     * @throws \PDepend\Report\NoLogOutputException
     */
    public function close()
    {
        // Check for configured log file
        if ($this->logFile === null) {
            throw new NoLogOutputException($this);
        }

        $metrics     = $this->collectMetrics();
        $proportions = $this->computeProportions($metrics);

        $svg = new \DOMDocument('1.0', 'UTF-8');
        $svg->loadXML(file_get_contents(dirname(__FILE__) . '/pyramid.svg'));

        $items = array_merge($metrics, $proportions);
        foreach ($items as $name => $value) {
            $svg->getElementById("pdepend.{$name}")->nodeValue = $value;

            if (($threshold = $this->computeThreshold($name, $value)) === null) {
                continue;
            }
            if (($color = $svg->getElementById("threshold.{$threshold}")) === null) {
                continue;
            }
            if (($rect = $svg->getElementById("rect.{$name}")) === null) {
                continue;
            }
            preg_match('/fill:(#[^;"]+)/', $color->getAttribute('style'), $match);

            $style = $rect->getAttribute('style');
            $style = preg_replace('/fill:#[^;"]+/', "fill:{$match[1]}", $style);
            $rect->setAttribute('style', $style);
        }

        $temp  = FileUtil::getSysTempDir();
        $temp .= '/' . uniqid('pdepend_') . '.svg';
        $svg->save($temp);

        ImageConvert::convert($temp, $this->logFile);

        // Remove temp file
        unlink($temp);
    }

    /**
     * Computes the threshold (low, average, high) for the given value and metric.
     * If no threshold is defined for the given name, this method will return
     * <b>null</b>.
     *
     * @param  string $name  The metric/field identfier.
     * @param  mixed  $value The metric/field value.
     * @return string
     */
    private function computeThreshold($name, $value)
    {
        if (!isset($this->thresholds[$name])) {
            return null;
        }

        $threshold = $this->thresholds[$name];
        if ($value <= $threshold[0]) {
            return 'low';
        } elseif ($value >= $threshold[2]) {
            return 'high';
        } else {
            $low = $value - $threshold[0];
            $avg = $threshold[1] - $value;

            if ($low < $avg) {
                return 'low';
            }
        }
        return 'average';
    }

    /**
     * Computes the proportions between the given metrics.
     *
     * @param  array $metrics The aggregated project metrics.
     * @return array(string => float)
     */
    private function computeProportions(array $metrics)
    {
        $orders = array(
            array('cyclo', 'loc', 'nom', 'noc', 'nop'),
            array('fanout', 'calls', 'nom')
        );

        $proportions = array();
        foreach ($orders as $names) {
            for ($i = 1, $c = count($names); $i < $c; ++$i) {
                $value1 = $metrics[$names[$i]];
                $value2 = $metrics[$names[$i - 1]];

                $identifier = "{$names[$i - 1]}-{$names[$i]}";

                $proportions[$identifier] = 0;
                if ($value1 > 0) {
                    $proportions[$identifier] = round($value2 / $value1, 3);
                }
            }
        }

        return $proportions;
    }

    /**
     * Aggregates the required metrics from the registered analyzers.
     *
     * @return array(string => mixed)
     * @throws \RuntimeException If one of the required analyzers isn't set.
     */
    private function collectMetrics()
    {
        if ($this->coupling === null) {
            throw new \RuntimeException('Missing Coupling analyzer.');
        }
        if ($this->cyclomaticComplexity === null) {
            throw new \RuntimeException('Missing Cyclomatic Complexity analyzer.');
        }
        if ($this->inheritance === null) {
            throw new \RuntimeException('Missing Inheritance analyzer.');
        }
        if ($this->nodeCount === null) {
            throw new \RuntimeException('Missing Node Count analyzer.');
        }
        if ($this->nodeLoc === null) {
            throw new \RuntimeException('Missing Node LOC analyzer.');
        }

        $coupling    = $this->coupling->getProjectMetrics();
        $cyclomatic  = $this->cyclomaticComplexity->getProjectMetrics();
        $inheritance = $this->inheritance->getProjectMetrics();
        $nodeCount   = $this->nodeCount->getProjectMetrics();
        $nodeLoc     = $this->nodeLoc->getProjectMetrics();

        return array(
            'cyclo'   =>  $cyclomatic['ccn2'],
            'loc'     =>  $nodeLoc['eloc'],
            'nom'     =>  ($nodeCount['nom'] + $nodeCount['nof']),
            'noc'     =>  $nodeCount['noc'],
            'nop'     =>  $nodeCount['nop'],
            'ahh'     =>  round($inheritance['ahh'], 3),
            'andc'    =>  round($inheritance['andc'], 3),
            'fanout'  =>  $coupling['fanout'],
            'calls'   =>  $coupling['calls']
        );
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Report;

/**
 * This type of exception is thrown, if a required log target/log file wasn't
 * configured for the current logger instance.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class NoLogOutputException extends \LogicException
{
    /**
     * Creates a new log target exception for the given log instance.
     *
     * @param \PDepend\Report\ReportGenerator $logger
     */
    public function __construct(ReportGenerator $logger)
    {
        $className = get_class($logger);
        $message   = "The log target is not configured for '{$className}'.";
        
        parent::__construct($message);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Report\Dependencies;

use PDepend\Metrics\Analyzer;
use PDepend\Metrics\Analyzer\ClassDependencyAnalyzer;
use PDepend\Report\CodeAwareGenerator;
use PDepend\Report\FileAwareGenerator;
use PDepend\Report\NoLogOutputException;
use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\AbstractASTClassOrInterface;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTCompilationUnit;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\AST\ASTTrait;
use PDepend\Source\ASTVisitor\AbstractASTVisitor;
use PDepend\Util\Utf8Util;

/**
 * This logger generates a summary xml document with aggregated project, class,
 * method and file dependencies.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Xml extends AbstractASTVisitor implements CodeAwareGenerator, FileAwareGenerator
{
    /**
     * The log output file.
     *
     * @var string
     */
    private $logFile = null;

    /**
     * The raw {@link \PDepend\Source\AST\ASTNamespace} instances.
     *
     * @var \PDepend\Source\AST\ASTArtifactList
     */
    protected $code = null;

    /**
     * Set of all analyzed files.
     *
     * @var \PDepend\Source\AST\ASTCompilationUnit[]
     */
    protected $fileSet = array();

    /**
     * @var \PDepend\Metrics\Analyzer\DependencyAnalyzer
     */
    private $dependencyAnalyzer;

    /**
     * The internal used xml stack.
     *
     * @var DOMElement[]
     */
    private $xmlStack = array();

    /**
     * Sets the output log file.
     *
     * @param string $logFile The output log file.
     *
     * @return void
     */
    public function setLogFile($logFile)
    {
        $this->logFile = $logFile;
    }

    /**
     * Returns an <b>array</b> with accepted analyzer types. These types can be
     * concrete analyzer classes or one of the descriptive analyzer interfaces.
     *
     * @return array(string)
     */
    public function getAcceptedAnalyzers()
    {
        return array(
            'pdepend.analyzer.class_dependency',
        );
    }

    /**
     * Sets the context code nodes.
     *
     * @param  \PDepend\Source\AST\ASTArtifactList $artifacts
     * @return void
     */
    public function setArtifacts(ASTArtifactList $artifacts)
    {
        $this->code = $artifacts;
    }

    /**
     * Adds an analyzer to log. If this logger accepts the given analyzer it
     * with return <b>true</b>, otherwise the return value is <b>false</b>.
     *
     * @param  \PDepend\dependencies\Analyzer $analyzer The analyzer to log.
     * @return boolean
     */
    public function log(Analyzer $analyzer)
    {
        if ($analyzer instanceof ClassDependencyAnalyzer) {
            $this->dependencyAnalyzer = $analyzer;
            return true;
        }
        return false;
    }

    /**
     * Closes the logger process and writes the output file.
     *
     * @return void
     * @throws \PDepend\Report\NoLogOutputException If the no log target exists.
     */
    public function close()
    {
        if ($this->logFile === null) {
            throw new NoLogOutputException($this);
        }

        $dom = new \DOMDocument('1.0', 'UTF-8');
        $dom->formatOutput = true;

        $dependencies = $dom->createElement('dependencies');
        $dependencies->setAttribute('generated', date('Y-m-d\TH:i:s'));
        $dependencies->setAttribute('pdepend', '@package_version@');
        array_push($this->xmlStack, $dependencies);

        foreach ($this->code as $node) {
            $node->accept($this);
        }

        $dom->appendChild($dependencies);

        $buffer = $dom->saveXML();
        file_put_contents($this->logFile, $buffer);
    }

    /**
     * Visits a class node.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     */
    public function visitClass(ASTClass $class)
    {
        $this->generateTypeXml($class, 'class');
    }

    /**
     * Visits a trait node.
     *
     * @param  \PDepend\Source\AST\ASTTrait $trait
     * @return void
     */
    public function visitTrait(ASTTrait $trait)
    {
        $this->generateTypeXml($trait, 'trait');
    }

    /**
     * Generates the XML for a class or trait node.
     *
     * @param  \PDepend\Source\AST\ASTClass $type
     * @param  string                       $typeIdentifier
     * @return void
     */
    private function generateTypeXml(AbstractASTClassOrInterface $type, $typeIdentifier)
    {
        if (!$type->isUserDefined()) {
            return;
        }

        $xml = end($this->xmlStack);
        $doc = $xml->ownerDocument;

        $typeXml = $doc->createElement($typeIdentifier);
        $typeXml->setAttribute('name', Utf8Util::ensureEncoding($type->getName()));
        $xml->appendChild($typeXml);

        array_push($this->xmlStack, $typeXml);
        $this->writeNodeDependencies($typeXml, $type);
        $this->writeFileReference($typeXml, $type->getCompilationUnit());
        array_pop($this->xmlStack);
    }

    /**
     * Visits a function node.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     */
    public function visitFunction(ASTFunction $function)
    {
        // Do not care
    }

    /**
     * Visits a code interface object.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function visitInterface(ASTInterface $interface)
    {
        $this->generateTypeXml($interface, 'interface');
    }

    /**
     * Visits a namespace node.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespace
     * @return void
     */
    public function visitNamespace(ASTNamespace $namespace)
    {
        $xml = end($this->xmlStack);
        $doc = $xml->ownerDocument;

        $packageXml = $doc->createElement('package');
        $packageXml->setAttribute('name', Utf8Util::ensureEncoding($namespace->getName()));

        array_push($this->xmlStack, $packageXml);

        foreach ($namespace->getTypes() as $type) {
            $type->accept($this);
        }
        foreach ($namespace->getFunctions() as $function) {
            $function->accept($this);
        }

        array_pop($this->xmlStack);

        if ($packageXml->firstChild === null) {
            return;
        }

        $xml->appendChild($packageXml);
    }

    /**
     * Aggregates all dependencies for the given <b>$node</b> instance and adds them
     * to the <b>\DOMElement</b>
     *
     * @param  \DOMElement                             $xml
     * @param  \PDepend\Source\AST\AbstractASTArtifact $node
     * @return void
     */
    protected function writeNodeDependencies(\DOMElement $xml, AbstractASTArtifact $node)
    {
        if (!$this->dependencyAnalyzer) {
            return;
        }

        $xml = end($this->xmlStack);
        $doc = $xml->ownerDocument;

        $efferentXml = $doc->createElement('efferent');
        $xml->appendChild($efferentXml);
        foreach ($this->dependencyAnalyzer->getEfferents($node) as $type) {
            $typeXml = $doc->createElement('type');
            $typeXml->setAttribute('namespace', Utf8Util::ensureEncoding($type->getNamespaceName()));
            $typeXml->setAttribute('name', Utf8Util::ensureEncoding($type->getName()));

            $efferentXml->appendChild($typeXml);
        }

        $afferentXml = $doc->createElement('afferent');
        $xml->appendChild($afferentXml);
        foreach ($this->dependencyAnalyzer->getAfferents($node) as $type) {
            $typeXml = $doc->createElement('type');
            $typeXml->setAttribute('namespace', Utf8Util::ensureEncoding($type->getNamespaceName()));
            $typeXml->setAttribute('name', Utf8Util::ensureEncoding($type->getName()));

            $afferentXml->appendChild($typeXml);
        }
    }

    /**
     * Appends a file reference element to the given <b>$xml</b> element.
     *
     * <code>
     *   <class name="\PDepend\Engine">
     *     <file name="PDepend/Engine.php" />
     *   </class>
     * </code>
     *
     * @param  \DOMElement                            $xml             The parent xml element.
     * @param  \PDepend\Source\AST\ASTCompilationUnit $compilationUnit The code file instance.
     * @return void
     */
    protected function writeFileReference(\DOMElement $xml, ASTCompilationUnit $compilationUnit = null)
    {
        if (in_array($compilationUnit, $this->fileSet, true) === false) {
            $this->fileSet[] = $compilationUnit;
        }

        $fileXml = $xml->ownerDocument->createElement('file');
        $fileXml->setAttribute('name', Utf8Util::ensureEncoding($compilationUnit->getFileName()));

        $xml->appendChild($fileXml);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Report;

use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * This factory creates singleton instances of available loggers.
 *
 * The identifiers are used to find a matching service in the DIC
 * that is tagged with 'pdepend.logger' and has an option attribute
 * named after the identifier, prefixed with --:
 *
 * Identifier "my-custom-logger" searchs for:
 *
 *  <tag name="pdepend.logger" option="--my-custom-logger" />
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ReportGeneratorFactory
{
    /**
     * @var \Symfony\Component\DependencyInjection\ContainerInterface
     */
    private $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    /**
     * Creates a new generator or returns an existing instance for the given
     * <b>$identifier</b>.
     *
     * @param  string $identifier The generator identifier.
     * @param  string $fileName   The log output file name.
     * @return \PDepend\Report\ReportGenerator
     * @throws \RuntimeException
     */
    public function createGenerator($identifier, $fileName)
    {
        if (!isset($this->instances[$identifier])) {
            $loggerServices = $this->container->findTaggedServiceIds('pdepend.logger');

            $logger = null;

            foreach ($loggerServices as $id => $loggerServiceTags) {
                foreach ($loggerServiceTags as $loggerServiceTag) {
                    if ($loggerServiceTag['option'] === '--' . $identifier) {
                        $logger = $this->container->get($id);
                    }
                }
            }

            if (!$logger) {
                throw new \RuntimeException(sprintf('Unknown generator with identifier "%s".', $identifier));
            }

            // TODO: Refactor this into an external log configurator or a similar
            //       concept.
            if ($logger instanceof FileAwareGenerator) {
                $logger->setLogFile($fileName);
            }

            $this->instances[$identifier] = $logger;
        }
        return $this->instances[$identifier];
    }

    /**
     * Set of created logger instances.
     *
     * @var \PDepend\Report\ReportGenerator[]
     */
    protected $instances = array();
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Report\Summary;

use PDepend\Metrics\Analyzer;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Metrics\AnalyzerProjectAware;
use PDepend\Report\CodeAwareGenerator;
use PDepend\Report\FileAwareGenerator;
use PDepend\Report\NoLogOutputException;
use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTCompilationUnit;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\AST\ASTTrait;
use PDepend\Source\ASTVisitor\AbstractASTVisitor;
use PDepend\Util\Utf8Util;

/**
 * This logger generates a summary xml document with aggregated project, class,
 * method and file metrics.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Xml extends AbstractASTVisitor implements CodeAwareGenerator, FileAwareGenerator
{
    /**
     * The log output file.
     *
     * @var string
     */
    private $logFile = null;

    /**
     * The raw {@link \PDepend\Source\AST\ASTNamespace} instances.
     *
     * @var \PDepend\Source\AST\ASTArtifactList
     */
    protected $code = null;

    /**
     * Set of all analyzed files.
     *
     * @var \PDepend\Source\AST\ASTCompilationUnit[]
     */
    protected $fileSet = array();

    /**
     * List of all analyzers that implement the node aware interface
     * {@link \PDepend\Metrics\AnalyzerNodeAware}.
     *
     * @var \PDepend\Metrics\AnalyzerNodeAware[]
     */
    private $nodeAwareAnalyzers = array();

    /**
     * List of all analyzers that implement the node aware interface
     * {@link \PDepend\Metrics\AnalyzerProjectAware}.
     *
     * @var \PDepend\Metrics\AnalyzerProjectAware[]
     */
    private $projectAwareAnalyzers = array();

    /**
     * The internal used xml stack.
     *
     * @var DOMElement[]
     */
    private $xmlStack = array();

    /**
     * Sets the output log file.
     *
     * @param string $logFile The output log file.
     *
     * @return void
     */
    public function setLogFile($logFile)
    {
        $this->logFile = $logFile;
    }

    /**
     * Returns an <b>array</b> with accepted analyzer types. These types can be
     * concrete analyzer classes or one of the descriptive analyzer interfaces.
     *
     * @return array(string)
     */
    public function getAcceptedAnalyzers()
    {
        return array(
            'pdepend.analyzer.cyclomatic_complexity',
            'pdepend.analyzer.node_loc',
            'pdepend.analyzer.npath_complexity',
            'pdepend.analyzer.inheritance',
            'pdepend.analyzer.node_count',
            'pdepend.analyzer.hierarchy',
            'pdepend.analyzer.crap_index',
            'pdepend.analyzer.code_rank',
            'pdepend.analyzer.coupling',
            'pdepend.analyzer.class_level',
            'pdepend.analyzer.cohesion',
            'pdepend.analyzer.halstead',
            'pdepend.analyzer.maintainability',
        );
    }

    /**
     * Sets the context code nodes.
     *
     * @param  \PDepend\Source\AST\ASTArtifactList $artifacts
     * @return void
     */
    public function setArtifacts(ASTArtifactList $artifacts)
    {
        $this->code = $artifacts;
    }

    /**
     * Adds an analyzer to log. If this logger accepts the given analyzer it
     * with return <b>true</b>, otherwise the return value is <b>false</b>.
     *
     * @param  \PDepend\Metrics\Analyzer $analyzer The analyzer to log.
     * @return boolean
     */
    public function log(Analyzer $analyzer)
    {
        $accepted = false;
        if ($analyzer instanceof AnalyzerProjectAware) {
            $this->projectAwareAnalyzers[] = $analyzer;

            $accepted = true;
        }
        if ($analyzer instanceof AnalyzerNodeAware) {
            $this->nodeAwareAnalyzers[] = $analyzer;

            $accepted = true;
        }
        return $accepted;
    }

    /**
     * Closes the logger process and writes the output file.
     *
     * @return void
     * @throws \PDepend\Report\NoLogOutputException If the no log target exists.
     */
    public function close()
    {
        if ($this->logFile === null) {
            throw new NoLogOutputException($this);
        }

        $dom = new \DOMDocument('1.0', 'UTF-8');

        $dom->formatOutput = true;

        $metrics = $dom->createElement('metrics');
        $metrics->setAttribute('generated', date('Y-m-d\TH:i:s'));
        $metrics->setAttribute('pdepend', '@package_version@');

        foreach ($this->getProjectMetrics() as $name => $value) {
            $metrics->setAttribute($name, $value);
        }

        array_push($this->xmlStack, $metrics);

        foreach ($this->code as $node) {
            $node->accept($this);
        }

        if (count($this->fileSet) > 0) {
            $filesXml = $dom->createElement('files');
            foreach ($this->fileSet as $file) {
                $fileXml = $dom->createElement('file');
                $fileXml->setAttribute('name', Utf8Util::ensureEncoding($file->getFileName()));

                $this->writeNodeMetrics($fileXml, $file);

                $filesXml->appendChild($fileXml);
            }
            $metrics->insertBefore($filesXml, $metrics->firstChild);
        }

        $dom->appendChild($metrics);

        $buffer = $dom->saveXML();
        file_put_contents($this->logFile, $buffer);
    }

    /**
     * Returns an array with all collected project metrics.
     *
     * @return array(string=>mixed)
     * @since  0.9.10
     */
    private function getProjectMetrics()
    {
        $projectMetrics = array();
        foreach ($this->projectAwareAnalyzers as $analyzer) {
            $projectMetrics = array_merge(
                $projectMetrics,
                $analyzer->getProjectMetrics()
            );
        }
        ksort($projectMetrics);

        return $projectMetrics;
    }

    /**
     * Visits a class node.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     */
    public function visitClass(ASTClass $class)
    {
        $this->generateTypeXml($class, 'class');
    }

    /**
     * Visits a trait node.
     *
     * @param  \PDepend\Source\AST\ASTTrait $trait
     * @return void
     */
    public function visitTrait(ASTTrait $trait)
    {
        $this->generateTypeXml($trait, 'trait');
    }

    /**
     * Generates the XML for a class or trait node.
     *
     * @param  \PDepend\Source\AST\ASTClass $type
     * @param  string                       $typeIdentifier
     * @return void
     */
    private function generateTypeXml(ASTClass $type, $typeIdentifier)
    {
        if (!$type->isUserDefined()) {
            return;
        }

        $xml = end($this->xmlStack);
        $doc = $xml->ownerDocument;

        $typeXml = $doc->createElement($typeIdentifier);
        $typeXml->setAttribute('name', Utf8Util::ensureEncoding($type->getName()));
        $typeXml->setAttribute('fqname', Utf8Util::ensureEncoding($type->getNamespacedName()));
        $typeXml->setAttribute('start', Utf8Util::ensureEncoding($type->getStartLine()));
        $typeXml->setAttribute('end', Utf8Util::ensureEncoding($type->getEndLine()));

        $this->writeNodeMetrics($typeXml, $type);
        $this->writeFileReference($typeXml, $type->getCompilationUnit());

        $xml->appendChild($typeXml);

        array_push($this->xmlStack, $typeXml);

        foreach ($type->getMethods() as $method) {
            $method->accept($this);
        }
        foreach ($type->getProperties() as $property) {
            $property->accept($this);
        }

        array_pop($this->xmlStack);
    }

    /**
     * Visits a function node.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     */
    public function visitFunction(ASTFunction $function)
    {
        $xml = end($this->xmlStack);
        $doc = $xml->ownerDocument;

        $functionXml = $doc->createElement('function');
        $functionXml->setAttribute('name', Utf8Util::ensureEncoding($function->getName()));
        $functionXml->setAttribute('start', Utf8Util::ensureEncoding($function->getStartLine()));
        $functionXml->setAttribute('end', Utf8Util::ensureEncoding($function->getEndLine()));

        $this->writeNodeMetrics($functionXml, $function);
        $this->writeFileReference($functionXml, $function->getCompilationUnit());

        $xml->appendChild($functionXml);
    }

    /**
     * Visits a code interface object.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function visitInterface(ASTInterface $interface)
    {
        // Empty implementation, because we don't want interface methods.
    }

    /**
     * Visits a method node.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function visitMethod(ASTMethod $method)
    {
        $xml = end($this->xmlStack);
        $doc = $xml->ownerDocument;

        $methodXml = $doc->createElement('method');
        $methodXml->setAttribute('name', Utf8Util::ensureEncoding($method->getName()));
        $methodXml->setAttribute('start', Utf8Util::ensureEncoding($method->getStartLine()));
        $methodXml->setAttribute('end', Utf8Util::ensureEncoding($method->getEndLine()));

        $this->writeNodeMetrics($methodXml, $method);

        $xml->appendChild($methodXml);
    }

    /**
     * Visits a namespace node.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespace
     * @return void
     */
    public function visitNamespace(ASTNamespace $namespace)
    {
        $xml = end($this->xmlStack);
        $doc = $xml->ownerDocument;

        $packageXml = $doc->createElement('package');
        $packageXml->setAttribute('name', Utf8Util::ensureEncoding($namespace->getName()));

        $this->writeNodeMetrics($packageXml, $namespace);

        array_push($this->xmlStack, $packageXml);

        foreach ($namespace->getTypes() as $type) {
            $type->accept($this);
        }
        foreach ($namespace->getFunctions() as $function) {
            $function->accept($this);
        }

        array_pop($this->xmlStack);

        if ($packageXml->firstChild === null) {
            return;
        }

        $xml->appendChild($packageXml);
    }

    /**
     * Aggregates all metrics for the given <b>$node</b> instance and adds them
     * to the <b>\DOMElement</b>
     *
     * @param  \DOMElement                             $xml
     * @param  \PDepend\Source\AST\AbstractASTArtifact $node
     * @return void
     */
    protected function writeNodeMetrics(\DOMElement $xml, AbstractASTArtifact $node)
    {
        $metrics = array();
        foreach ($this->nodeAwareAnalyzers as $analyzer) {
            $metrics = array_merge($metrics, $analyzer->getNodeMetrics($node));
        }

        foreach ($metrics as $name => $value) {
            $xml->setAttribute($name, $value);
        }
    }

    /**
     * Appends a file reference element to the given <b>$xml</b> element.
     *
     * <code>
     *   <class name="\PDepend\Engine">
     *     <file name="PDepend/Engine.php" />
     *   </class>
     * </code>
     *
     * @param  \DOMElement                            $xml             The parent xml element.
     * @param  \PDepend\Source\AST\ASTCompilationUnit $compilationUnit The code file instance.
     * @return void
     */
    protected function writeFileReference(\DOMElement $xml, ASTCompilationUnit $compilationUnit = null)
    {
        if (in_array($compilationUnit, $this->fileSet, true) === false) {
            $this->fileSet[] = $compilationUnit;
        }

        $fileXml = $xml->ownerDocument->createElement('file');
        $fileXml->setAttribute('name', Utf8Util::ensureEncoding($compilationUnit->getFileName()));

        $xml->appendChild($fileXml);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Report;

use PDepend\Metrics\Analyzer;

/**
 * Base interface for all PDepend report generators.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface ReportGenerator
{
    /**
     * Adds an analyzer to log. If this logger accepts the given analyzer it
     * with return <b>true</b>, otherwise the return value is <b>false</b>.
     *
     * @param  \PDepend\Metrics\Analyzer $analyzer The analyzer to log.
     * @return boolean
     */
    public function log(Analyzer $analyzer);
    
    /**
     * Closes the logger process and writes the output file.
     *
     * @return void
     * @throws \PDepend\Report\NoLogOutputException If the no log target exists.
     */
    public function close();
    
    /**
     * Returns an <b>array</b> with accepted analyzer types. These types can be
     * concrete analyzer classes or one of the descriptive analyzer interfaces.
     *
     * @return array(string)
     */
    public function getAcceptedAnalyzers();
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\DbusUI;

// This is just fun and it is not really testable
// @codeCoverageIgnoreStart
use PDepend\Metrics\Analyzer;
use PDepend\ProcessListener;
use PDepend\Source\ASTVisitor\AbstractASTVisitListener;
use PDepend\Source\Builder\Builder;
use PDepend\Source\Tokenizer\Tokenizer;

/**
 * Fun result printer that uses dbus to show a notification window.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ResultPrinter extends AbstractASTVisitListener implements ProcessListener
{
    /**
     * Time when it the process has started.
     *
     * @var integer
     */
    private $startTime = 0;

    /**
     * Number of parsed/analyzed files.
     *
     * @var integer
     */
    private $parsedFiles = 0;

    /**
     * Is called when PDepend starts the file parsing process.
     *
     * @param  \PDepend\Source\Builder\Builder $builder The used node builder instance.
     * @return void
     */
    public function startParseProcess(Builder $builder)
    {
        $this->startTime = time();
    }

    /**
     * Is called when PDepend has finished the file parsing process.
     *
     * @param  \PDepend\Source\Builder\Builder $builder The used node builder instance.
     * @return void
     */
    public function endParseProcess(Builder $builder)
    {
    }

    /**
     * Is called when PDepend starts parsing of a new file.
     *
     * @param  \PDepend\Source\Tokenizer\Tokenizer $tokenizer
     * @return void
     */
    public function startFileParsing(Tokenizer $tokenizer)
    {
    }

    /**
     * Is called when PDepend has finished a file.
     *
     * @param  \PDepend\Source\Tokenizer\Tokenizer $tokenizer
     * @return void
     */
    public function endFileParsing(Tokenizer $tokenizer)
    {
        ++$this->parsedFiles;
    }

    /**
     * Is called when PDepend starts the analyzing process.
     *
     * @return void
     */
    public function startAnalyzeProcess()
    {
    }

    /**
     * Is called when PDepend has finished the analyzing process.
     *
     * @return void
     */
    public function endAnalyzeProcess()
    {
    }

    /**
     * Is called when PDepend starts the logging process.
     *
     * @return void
     */
    public function startLogProcess()
    {
    }

    /**
     * Is called when PDepend has finished the logging process.
     *
     * @return void
     */
    public function endLogProcess()
    {
        if (extension_loaded('dbus') === false) {
            return;
        }

        $dbus  = new Dbus(Dbus::BUS_SESSION);
        $proxy = $dbus->createProxy(
            "org.freedesktop.Notifications", // connection name
            "/org/freedesktop/Notifications", // object
            "org.freedesktop.Notifications" // interface
        );
        $proxy->Notify(
            'PDepend',
            new DBusUInt32(0),
            'pdepend',
            'PDepend',
            sprintf(
                '%d files analyzed in %s minutes...',
                $this->parsedFiles,
                (date('i:s', time() - $this->startTime))
            ),
            new DBusArray(DBus::STRING, array()),
            new DBusDict(DBus::VARIANT, array()),
            1000
        );
    }

    /**
     * Is called when PDepend starts a new analyzer.
     *
     * @param  \PDepend\Metrics\Analyzer $analyzer The context analyzer instance.
     * @return void
     */
    public function startAnalyzer(Analyzer $analyzer)
    {
    }

    /**
     * Is called when PDepend has finished one analyzing process.
     *
     * @param  \PDepend\Metrics\Analyzer $analyzer The context analyzer instance.
     * @return void
     */
    public function endAnalyzer(Analyzer $analyzer)
    {
    }
}

// @codeCoverageIgnoreEnd
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\DependencyInjection;

/**
 * Manage activation and registration of extensions for PDepend.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ExtensionManager
{
    private $extensions = array();

    /**
     * Activate an extension based on a class name.
     *
     * @throws RuntimeException
     * @param  string $className
     * @return void
     */
    public function activateExtension($className)
    {
        if (!class_exists($className)) {
            throw new \RuntimeException(
                sprintf(
                    'Cannot find extension class %s" for PDepend. Maybe the plugin is not installed?',
                    $className
                )
            );
        }

        $extension = new $className;

        if (!($extension instanceof Extension)) {
            throw new \RuntimeException(
                sprintf('Class "%s" is not a valid Extension', $className)
            );
        }

        $this->extensions[$extension->getName()] = $extension;
    }

    /**
     * Return all activated extensions.
     *
     * @return array(\PDepend\DependencyInjection\Extension)
     */
    public function getActivatedExtensions()
    {
        return $this->extensions;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\DependencyInjection;

use PDepend\Util\FileUtil;
use PDepend\Util\Workarounds;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;

/**
 * This is the class that validates and merges configuration
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Configuration implements ConfigurationInterface
{
    /**
     * @var array(Extension)
     */
    private $extensions = array();

    public function __construct(array $extensions)
    {
        $this->extensions = $extensions;
    }

    /**
     * {@inheritDoc}
     */
    public function getConfigTreeBuilder()
    {
        $home = FileUtil::getUserHomeDirOrSysTempDir();
        $workarounds = new Workarounds();

        $defaultCacheDriver = ($workarounds->hasSerializeReferenceIssue()) ? 'memory' : 'file';

        $treeBuilder = new TreeBuilder();
        $rootNode = $treeBuilder->root('pdepend');

        $rootNode
            ->children()
            ->arrayNode('cache')
            ->addDefaultsIfNotSet()
            ->children()
            ->enumNode('driver')->defaultValue($defaultCacheDriver)->values(array('file', 'memory'))->end()
            ->scalarNode('location')->defaultValue($home . '/.pdepend')->end()
            ->end()
            ->end()
            ->arrayNode('image_convert')
            ->addDefaultsIfNotSet()
            ->children()
            ->scalarNode('font_size')->defaultValue('11')->end()
            ->scalarNode('font_family')->defaultValue('Arial')->end()
            ->end()
            ->end()
            ->arrayNode('parser')
            ->addDefaultsIfNotSet()
            ->children()
            ->integerNode('nesting')->defaultValue(65536)->end()
            ->end()
            ->end()
            ->end();

        $extensionsNode = $rootNode
            ->children()
            ->arrayNode('extensions')
            ->addDefaultsIfNotSet()
            ->children();

        foreach ($this->extensions as $extension) {
            $extensionNode = $extensionsNode->arrayNode($extension->getName());
            $extension->getConfig($extensionNode);
        }

        return $treeBuilder;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

/**
 * Find Process Listeners of extensions by 'pdepend.process_listener' tag.
 *
 * Listeners are added to the PDepend\Engine service.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ProcessListenerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $engineDefinition = $container->findDefinition('pdepend.engine');

        $processListenerTags = $container->findTaggedServiceIds('pdepend.process_listener');

        foreach ($processListenerTags as $id => $tags) {
            $engineDefinition->addMethodCall('addProcessListener', array(new Reference($id)));
        }
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\DependencyInjection;

use ReflectionClass;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;

/**
 * PDepend base extension class.
 *
 * Copied from Behat
 *
 * @link   https://github.com/Behat/Behat/blob/3.0/src/Behat/Behat/Extension/Extension.php
 * @author Konstantin Kudryashov <ever.zet@gmail.com>
 */
abstract class Extension
{
    /**
     * Return name of the extension
     *
     * @return string
     */
    abstract public function getName();

    /**
     * Loads a specific configuration.
     *
     * @param array            $config    Extension configuration hash (from behat.yml)
     * @param ContainerBuilder $container ContainerBuilder instance
     */
    public function load(array $config, ContainerBuilder $container)
    {
        $path = rtrim($this->getServiceDefinitionsPath(), DIRECTORY_SEPARATOR);
        $name = $this->getServiceDefinitionsName();

        if (file_exists($path . DIRECTORY_SEPARATOR . ($file = $name . '.xml'))) {
            $loader = new XmlFileLoader($container, new FileLocator($path));
            $loader->load($file);
        }
        if (file_exists($path . DIRECTORY_SEPARATOR . ($file = $name . '.yml'))) {
            $loader = new YamlFileLoader($container, new FileLocator($path));
            $loader->load($file);
        }

        $container->setParameter($this->getName() . '.parameters', $config);
    }

    /**
     * Setups configuration for current extension.
     *
     * @param ArrayNodeDefinition $builder
     */
    public function getConfig(ArrayNodeDefinition $builder)
    {
        $builder
            ->useAttributeAsKey('name')
            ->prototype('variable');
    }

    /**
     * Returns compiler passes used by this extension.
     *
     * @return CompilerPassInterface[]
     */
    public function getCompilerPasses()
    {
        return array();
    }

    /**
     * Returns name of the service definition config without extension and path.
     *
     * @return string
     */
    protected function getServiceDefinitionsName()
    {
        return 'services';
    }

    /**
     * Returns service definition configs path.
     *
     * @return string
     */
    protected function getServiceDefinitionsPath()
    {
        $reflection = new ReflectionClass($this);

        return dirname($reflection->getFileName());
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\DependencyInjection;

use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension as SymfonyExtension;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;

/**
 * PDepend DependencyInjection Extension for Symfony DIC
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class PdependExtension extends SymfonyExtension
{
    /**
     * {@inheritDoc}
     */
    public function load(array $configs, ContainerBuilder $container)
    {
        $extensionManager = new ExtensionManager();

        foreach ($configs as $config) {
            if (!isset($config['extensions'])) {
                continue;
            }

            foreach ($config['extensions'] as $config) {
                if (!isset($config['class'])) {
                    continue;
                }

                $extensionManager->activateExtension($config['class']);
            }
        }

        $configuration = new Configuration($extensionManager->getActivatedExtensions());
        $config = $this->processConfiguration($configuration, $configs);

        $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__ . '/../../../resources'));
        $loader->load('services.xml');

        foreach ($extensionManager->getActivatedExtensions() as $extension) {
            $extensionConfig = $config['extensions'][$extension->getName()];

            $tempContainer = new ContainerBuilder(new ParameterBag(array()));
            $tempContainer->addObjectResource($extension);

            // load extension into temporary container
            $extension->load($extensionConfig, $tempContainer);

            // merge temporary container into normal one
            $container->merge($tempContainer);
        }

        $settings = $this->createSettings($config);

        $configurationDefinition = $container->findDefinition('pdepend.configuration');
        $configurationDefinition->setArguments(array($settings));
    }

    private function createSettings($config)
    {
        $settings = new \stdClass();

        $settings->cache           = new \stdClass();
        $settings->cache->driver = $config['cache']['driver'];
        $settings->cache->location = $config['cache']['location'];

        $settings->imageConvert             = new \stdClass();
        $settings->imageConvert->fontSize   = $config['image_convert']['font_size'];
        $settings->imageConvert->fontFamily = $config['image_convert']['font_family'];

        $settings->parser          = new \stdClass();
        $settings->parser->nesting = $config['parser']['nesting'];

        return $settings;
    }

    public function getNamespace()
    {
        return 'http://pdepend.org/schema/dic/pdepend';
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  */

namespace PDepend;

// @codeCoverageIgnoreStart
use PDepend\Metrics\AnalyzerListener;
use PDepend\Source\ASTVisitor\ASTVisitListener;
use PDepend\Source\Builder\Builder;
use PDepend\Source\Tokenizer\Tokenizer;

/**
 * This listener can be used to get informations about the current pdepend process.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface ProcessListener extends ASTVisitListener, AnalyzerListener
{
    /**
     * Is called when PDepend starts the file parsing process.
     *
     * @param  \PDepend\Source\Builder\Builder $builder The used node builder instance.
     * @return void
     */
    public function startParseProcess(Builder $builder);
    
    /**
     * Is called when PDepend has finished the file parsing process.
     *
     * @param  \PDepend\Source\Builder\Builder $builder The used node builder instance.
     * @return void
     */
    public function endParseProcess(Builder $builder);
    
    /**
     * Is called when PDepend starts parsing of a new file.
     *
     * @param  \PDepend\Source\Tokenizer\Tokenizer $tokenizer
     * @return void
     */
    public function startFileParsing(Tokenizer $tokenizer);
    
    /**
     * Is called when PDepend has finished a file.
     *
     * @param  \PDepend\Source\Tokenizer\Tokenizer $tokenizer
     * @return void
     */
    public function endFileParsing(Tokenizer $tokenizer);
    
    /**
     * Is called when PDepend starts the analyzing process.
     *
     * @return void
     */
    public function startAnalyzeProcess();
    
    /**
     * Is called when PDepend has finished the analyzing process.
     *
     * @return void
     */
    public function endAnalyzeProcess();
    
    /**
     * Is called when PDepend starts the logging process.
     *
     * @return void
     */
    public function startLogProcess();
    
    /**
     * Is called when PDepend has finished the logging process.
     *
     * @return void
     */
    public function endLogProcess();
}

// @codeCoverageIgnoreEnd
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\Language\PHP;

use PDepend\Source\AST\AbstractASTClassOrInterface;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTClassOrInterfaceReference;
use PDepend\Source\AST\ASTClassReference;
use PDepend\Source\AST\ASTCompilationUnit;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\AST\ASTParentReference;
use PDepend\Source\AST\ASTTrait;
use PDepend\Source\Builder\Builder;
use PDepend\Source\Builder\BuilderContext\GlobalBuilderContext;
use PDepend\Util\Cache\CacheDriver;
use PDepend\Util\Log;
use PDepend\Util\Type;

/**
 * Default code tree builder implementation.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class PHPBuilder implements Builder
{
    /**
     * The internal used cache instance.
     *
     * @var   \PDepend\Util\Cache\CacheDriver
     * @since 0.10.0
     */
    protected $cache = null;

    /**
     * The ast builder context.
     *
     * @var   \PDepend\Source\Builder\BuilderContext
     * @since 0.10.0
     */
    protected $context = null;

    /**
     * This property holds all packages found during the parsing phase.
     *
     * @param \PDepend\Source\AST\ASTNamespace[]
     * @since 0.9.12
     */
    private $preparedNamespaces = null;

    /**
     * Default package which contains all functions and classes with an unknown
     * scope.
     *
     * @var \PDepend\Source\AST\ASTNamespace
     */
    protected $defaultPackage = null;

    /**
     * Default source file that acts as a dummy.
     *
     * @var ASTCompilationUnit
     */
    protected $defaultCompilationUnit = null;

    /**
     * All generated {@link \PDepend\Source\AST\ASTTrait} objects
     *
     * @var \PDepend\Source\AST\ASTTrait[]
     */
    private $traits = array();

    /**
     * All generated {@link \PDepend\Source\AST\ASTClass} objects
     *
     * @var \PDepend\Source\AST\ASTClass[]
     */
    private $classes = array();

    /**
     * All generated {@link \PDepend\Source\AST\ASTInterface} instances.
     *
     * @var \PDepend\Source\AST\ASTInterface[]
     */
    private $interfaces = array();

    /**
     * All generated {@link \PDepend\Source\AST\ASTNamespace} objects
     *
     * @var \PDepend\Source\AST\ASTNamespace[]
     */
    private $namespaces = array();

    /**
     * Internal status flag used to check that a build request is internal.
     *
     * @var boolean
     */
    private $internal = false;

    /**
     * Internal used flag that marks the parsing process as frozen.
     *
     * @var boolean
     */
    private $frozen = false;

    /**
     * Cache of all traits created during the regular parsing process.
     *
     * @var \PDepend\Source\AST\ASTTrait[]
     */
    private $frozenTraits = array();

    /**
     * Cache of all classes created during the regular parsing process.
     *
     * @var \PDepend\Source\AST\ASTClass[]
     */
    private $frozenClasses = array();

    /**
     * Cache of all interfaces created during the regular parsing process.
     *
     * @var \PDepend\Source\AST\ASTInterface[]
     */
    private $frozenInterfaces = array();

    /**
     * Constructs a new builder instance.
     */
    public function __construct()
    {
        $this->defaultPackage = new ASTNamespace(self::DEFAULT_NAMESPACE);
        $this->defaultCompilationUnit = new ASTCompilationUnit(null);

        $this->namespaces[self::DEFAULT_NAMESPACE] = $this->defaultPackage;

        $this->context = new GlobalBuilderContext($this);
    }

    /**
     * Setter method for the currently used token cache.
     *
     * @param  \PDepend\Util\Cache\CacheDriver $cache
     * @return \PDepend\Source\Language\PHP\PHPBuilder
     * @since  0.10.0
     */
    public function setCache(CacheDriver $cache)
    {
        $this->cache = $cache;
        return $this;
    }

    /**
     * Builds a new code type reference instance.
     *
     * @param string $qualifiedName The qualified name of the referenced type.
     *
     * @return ASTClassOrInterfaceReference
     * @since  0.9.5
     */
    public function buildAstClassOrInterfaceReference($qualifiedName)
    {
        $this->checkBuilderState();

        // Debug method creation
        Log::debug(
            'Creating: \PDepend\Source\AST\ASTClassOrInterfaceReference(' .
            $qualifiedName .
            ')'
        );

        return new ASTClassOrInterfaceReference($this->context, $qualifiedName);
    }

    /**
     * This method will try to find an already existing instance for the given
     * qualified name. It will create a new {@link \PDepend\Source\AST\ASTClass}
     * instance when no matching type exists.
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\AbstractASTClassOrInterface
     * @since  0.9.5
     */
    public function getClassOrInterface($qualifiedName)
    {
        $classOrInterface = $this->findClass($qualifiedName);
        if ($classOrInterface !== null) {
            return $classOrInterface;
        }

        $classOrInterface = $this->findInterface($qualifiedName);
        if ($classOrInterface !== null) {
            return $classOrInterface;
        }
        return $this->buildClassInternal($qualifiedName);
    }

    /**
     * Builds a new php trait instance.
     *
     * @param string $qualifiedName The full qualified trait name.
     *
     * @return \PDepend\Source\AST\ASTTrait
     * @since 1.0.0
     */
    public function buildTrait($qualifiedName)
    {
        $this->checkBuilderState();

        $trait = new ASTTrait($this->extractTypeName($qualifiedName));
        $trait->setCache($this->cache)
            ->setContext($this->context)
            ->setCompilationUnit($this->defaultCompilationUnit);

        return $trait;
    }

    /**
     * This method will try to find an already existing instance for the given
     * qualified name. It will create a new {@link \PDepend\Source\AST\ASTTrait}
     * instance when no matching type exists.
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\ASTTrait
     * @since  1.0.0
     */
    public function getTrait($qualifiedName)
    {
        $trait = $this->findTrait($qualifiedName);
        if ($trait === null) {
            $trait = $this->buildTraitInternal($qualifiedName);
        }
        return $trait;
    }

    /**
     * Builds a new trait reference node.
     *
     * @param string $qualifiedName The full qualified trait name.
     *
     * @return \PDepend\Source\AST\ASTTraitReference
     * @since  1.0.0
     */
    public function buildAstTraitReference($qualifiedName)
    {
        $this->checkBuilderState();

        Log::debug(
            'Creating: \PDepend\Source\AST\ASTTraitReference(' . $qualifiedName . ')'
        );

        return new \PDepend\Source\AST\ASTTraitReference($this->context, $qualifiedName);
    }

    /**
     * Builds a new class instance or reuses a previous created class.
     *
     * Where possible you should give a qualified class name, that is prefixed
     * with the package identifier.
     *
     * <code>
     *   $builder->buildClass('php::depend::Parser');
     * </code>
     *
     * To determine the correct class, this method implements the following
     * algorithm.
     *
     * <ol>
     *   <li>Check for an exactly matching instance and reuse it.</li>
     *   <li>Check for a class instance that belongs to the default package. If
     *   such an instance exists, reuse it and replace the default package with
     *   the newly given package information.</li>
     *   <li>Check that the requested class is in the default package, if this
     *   is true, reuse the first class instance and ignore the default package.
     *   </li>
     *   <li>Create a new instance for the specified package.</li>
     * </ol>
     *
     * @param string $name The class name.
     *
     * @return \PDepend\Source\AST\ASTClass The created class object.
     */
    public function buildClass($name)
    {
        $this->checkBuilderState();
        
        $class = new ASTClass($this->extractTypeName($name));
        $class->setCache($this->cache)
            ->setContext($this->context)
            ->setCompilationUnit($this->defaultCompilationUnit);

        return $class;
    }

    /**
     * This method will try to find an already existing instance for the given
     * qualified name. It will create a new {@link \PDepend\Source\AST\ASTClass}
     * instance when no matching type exists.
     *
     * @param string $qualifiedName The full qualified type identifier.
     *
     * @return \PDepend\Source\AST\ASTClass
     * @since  0.9.5
     */
    public function getClass($qualifiedName)
    {
        $class = $this->findClass($qualifiedName);
        if ($class === null) {
            $class = $this->buildClassInternal($qualifiedName);
        }
        return $class;
    }

    /**
     * Builds an anonymous class instance.
     *
     * @return \PDepend\Source\AST\ASTAnonymousClass
     */
    public function buildAnonymousClass()
    {
        return $this->buildAstNodeInstance('ASTAnonymousClass')
            ->setCache($this->cache)
            ->setContext($this->context);
    }

    /**
     * Builds a new code type reference instance.
     *
     * @param string $qualifiedName The qualified name of the referenced type.
     *
     * @return \PDepend\Source\AST\ASTClassReference
     * @since  0.9.5
     */
    public function buildAstClassReference($qualifiedName)
    {
        $this->checkBuilderState();

        // Debug method creation
        Log::debug(
            'Creating: \PDepend\Source\AST\ASTClassReference(' . $qualifiedName . ')'
        );

        return new ASTClassReference($this->context, $qualifiedName);
    }

    /**
     * Builds a new new interface instance.
     *
     * If there is an existing class instance for the given name, this method
     * checks if this class is part of the default namespace. If this is the
     * case this method will update all references to the new interface and it
     * removes the class instance. Otherwise it creates new interface instance.
     *
     * Where possible you should give a qualified interface name, that is
     * prefixed with the package identifier.
     *
     * <code>
     *   $builder->buildInterface('php::depend::Parser');
     * </code>
     *
     * To determine the correct interface, this method implements the following
     * algorithm.
     *
     * <ol>
     *   <li>Check for an exactly matching instance and reuse it.</li>
     *   <li>Check for a interface instance that belongs to the default package.
     *   If such an instance exists, reuse it and replace the default package
     *   with the newly given package information.</li>
     *   <li>Check that the requested interface is in the default package, if
     *   this is true, reuse the first interface instance and ignore the default
     *   package.
     *   </li>
     *   <li>Create a new instance for the specified package.</li>
     * </ol>
     *
     * @param  string $name The interface name.
     * @return \PDepend\Source\AST\ASTInterface
     */
    public function buildInterface($name)
    {
        $this->checkBuilderState();
        
        $interface = new ASTInterface($this->extractTypeName($name));
        $interface->setCache($this->cache)
            ->setContext($this->context)
            ->setCompilationUnit($this->defaultCompilationUnit);

        return $interface;
    }

    /**
     * This method will try to find an already existing instance for the given
     * qualified name. It will create a new {@link \PDepend\Source\AST\ASTInterface}
     * instance when no matching type exists.
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\ASTInterface
     * @since  0.9.5
     */
    public function getInterface($qualifiedName)
    {
        $interface = $this->findInterface($qualifiedName);
        if ($interface === null) {
            $interface = $this->buildInterfaceInternal($qualifiedName);
        }
        return $interface;
    }

    /**
     * Builds a new method instance.
     *
     * @param  string $name
     * @return \PDepend\Source\AST\ASTMethod
     */
    public function buildMethod($name)
    {
        $this->checkBuilderState();

        // Debug method creation
        Log::debug("Creating: \\PDepend\\Source\\AST\\ASTMethod({$name})");

        // Create a new method instance
        $method = new ASTMethod($name);
        $method->setCache($this->cache);

        return $method;
    }

    /**
     * Builds a new package instance.
     *
     * @param  string $name The package name.
     * @return \PDepend\Source\AST\ASTNamespace
     */
    public function buildNamespace($name)
    {
        if (!isset($this->namespaces[$name])) {
            // Debug package creation
            Log::debug(
                'Creating: \\PDepend\\Source\\AST\\ASTNamespace(' . $name . ')'
            );

            $this->namespaces[$name] = new ASTNamespace($name);
        }
        return $this->namespaces[$name];
    }

    /**
     * Builds a new function instance.
     *
     * @param  string $name The function name.
     * @return ASTFunction
     */
    public function buildFunction($name)
    {
        $this->checkBuilderState();

        // Debug function creation
        Log::debug("Creating: \\PDepend\\Source\\AST\\ASTFunction({$name})");

        // Create new function
        $function = new ASTFunction($name);
        $function->setCache($this->cache)
            ->setContext($this->context)
            ->setCompilationUnit($this->defaultCompilationUnit);
 
        return $function;
    }

    /**
     * Builds a new self reference instance.
     *
     * @param  \PDepend\Source\AST\AbstractASTClassOrInterface $type
     * @return \PDepend\Source\AST\ASTSelfReference
     * @since  0.9.6
     */
    public function buildAstSelfReference(AbstractASTClassOrInterface $type)
    {
        Log::debug(
            'Creating: \PDepend\Source\AST\ASTSelfReference(' . $type->getName() . ')'
        );

        return new \PDepend\Source\AST\ASTSelfReference($this->context, $type);
    }

    /**
     * Builds a new parent reference instance.
     *
     * @param ASTClassOrInterfaceReference $reference The type
     *        instance that reference the concrete target of parent.
     *
     * @return ASTParentReference
     * @since  0.9.6
     */
    public function buildAstParentReference(ASTClassOrInterfaceReference $reference)
    {
        Log::debug('Creating: \PDepend\Source\AST\ASTParentReference()');

        return new ASTParentReference($reference);
    }

    /**
     * Builds a new static reference instance.
     *
     * @param  \PDepend\Source\AST\AbstractASTClassOrInterface $owner
     * @return \PDepend\Source\AST\ASTStaticReference
     * @since  0.9.6
     */
    public function buildAstStaticReference(AbstractASTClassOrInterface $owner)
    {
        Log::debug('Creating: \PDepend\Source\AST\ASTStaticReference()');

        return new \PDepend\Source\AST\ASTStaticReference($this->context, $owner);
    }

    /**
     * Builds a new field declaration node.
     *
     * @return \PDepend\Source\AST\ASTFieldDeclaration
     * @since  0.9.6
     */
    public function buildAstFieldDeclaration()
    {
        return $this->buildAstNodeInstance('ASTFieldDeclaration');
    }

    /**
     * Builds a new variable declarator node.
     *
     * @param string $image The source image for the variable declarator.
     *
     * @return \PDepend\Source\AST\ASTVariableDeclarator
     * @since  0.9.6
     */
    public function buildAstVariableDeclarator($image)
    {
        return $this->buildAstNodeInstance('ASTVariableDeclarator', $image);
    }

    /**
     * Builds a new static variable declaration node.
     *
     * @param string $image The source image for the statuc declaration.
     *
     * @return \PDepend\Source\AST\ASTStaticVariableDeclaration
     * @since  0.9.6
     */
    public function buildAstStaticVariableDeclaration($image)
    {
        return $this->buildAstNodeInstance('ASTStaticVariableDeclaration', $image);
    }

    /**
     * Builds a new constant node.
     *
     * @param string $image The source image for the constant.
     *
     * @return \PDepend\Source\AST\ASTConstant
     * @since  0.9.6
     */
    public function buildAstConstant($image)
    {
        return $this->buildAstNodeInstance('ASTConstant', $image);
    }

    /**
     * Builds a new variable node.
     *
     * @param string $image The source image for the variable.
     *
     * @return \PDepend\Source\AST\ASTVariable
     * @since  0.9.6
     */
    public function buildAstVariable($image)
    {
        return $this->buildAstNodeInstance('ASTVariable', $image);
    }

    /**
     * Builds a new variable variable node.
     *
     * @param string $image The source image for the variable variable.
     *
     * @return \PDepend\Source\AST\ASTVariableVariable
     * @since  0.9.6
     */
    public function buildAstVariableVariable($image)
    {
        return $this->buildAstNodeInstance('ASTVariableVariable', $image);
    }

    /**
     * Builds a new compound variable node.
     *
     * @param string $image The source image for the compound variable.
     *
     * @return \PDepend\Source\AST\ASTCompoundVariable
     * @since  0.9.6
     */
    public function buildAstCompoundVariable($image)
    {
        return $this->buildAstNodeInstance('ASTCompoundVariable', $image);
    }

    /**
     * Builds a new compound expression node.
     *
     * @return \PDepend\Source\AST\ASTCompoundExpression
     * @since  0.9.6
     */
    public function buildAstCompoundExpression()
    {
        return $this->buildAstNodeInstance('ASTCompoundExpression');
    }

    /**
     * Builds a new closure node.
     *
     * @return \PDepend\Source\AST\ASTClosure
     * @since  0.9.12
     */
    public function buildAstClosure()
    {
        return $this->buildAstNodeInstance('ASTClosure');
    }

    /**
     * Builds a new formal parameters node.
     *
     * @return \PDepend\Source\AST\ASTFormalParameters
     * @since  0.9.6
     */
    public function buildAstFormalParameters()
    {
        return $this->buildAstNodeInstance('ASTFormalParameters');
    }

    /**
     * Builds a new formal parameter node.
     *
     * @return \PDepend\Source\AST\ASTFormalParameter
     * @since  0.9.6
     */
    public function buildAstFormalParameter()
    {
        return $this->buildAstNodeInstance('ASTFormalParameter');
    }

    /**
     * Builds a new expression node.
     *
     * @param string $image
     * @return \PDepend\Source\AST\ASTExpression
     * @since 0.9.8
     */
    public function buildAstExpression($image = null)
    {
        return $this->buildAstNodeInstance('ASTExpression', $image);
    }

    /**
     * Builds a new assignment expression node.
     *
     * @param string $image The assignment operator.
     *
     * @return \PDepend\Source\AST\ASTAssignmentExpression
     * @since  0.9.8
     */
    public function buildAstAssignmentExpression($image)
    {
        return $this->buildAstNodeInstance('ASTAssignmentExpression', $image);
    }

    /**
     * Builds a new allocation expression node.
     *
     * @param string $image The source image of this expression.
     *
     * @return \PDepend\Source\AST\ASTAllocationExpression
     * @since  0.9.6
     */
    public function buildAstAllocationExpression($image)
    {
        return $this->buildAstNodeInstance('ASTAllocationExpression', $image);
    }

    /**
     * Builds a new eval-expression node.
     *
     * @param string $image The source image of this expression.
     *
     * @return \PDepend\Source\AST\ASTEvalExpression
     * @since  0.9.12
     */
    public function buildAstEvalExpression($image)
    {
        return $this->buildAstNodeInstance('ASTEvalExpression', $image);
    }

    /**
     * Builds a new exit-expression instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTExitExpression
     * @since  0.9.12
     */
    public function buildAstExitExpression($image)
    {
        return $this->buildAstNodeInstance('ASTExitExpression', $image);
    }

    /**
     * Builds a new clone-expression node.
     *
     * @param string $image The source image of this expression.
     *
     * @return \PDepend\Source\AST\ASTCloneExpression
     * @since  0.9.12
     */
    public function buildAstCloneExpression($image)
    {
        return $this->buildAstNodeInstance('ASTCloneExpression', $image);
    }

    /**
     * Builds a new list-expression node.
     *
     * @param string $image The source image of this expression.
     *
     * @return \PDepend\Source\AST\ASTListExpression
     * @since  0.9.12
     */
    public function buildAstListExpression($image)
    {
        return $this->buildAstNodeInstance('ASTListExpression', $image);
    }

    /**
     * Builds a new include- or include_once-expression.
     *
     * @return \PDepend\Source\AST\ASTIncludeExpression
     * @since  0.9.12
     */
    public function buildAstIncludeExpression()
    {
        return $this->buildAstNodeInstance('ASTIncludeExpression');
    }

    /**
     * Builds a new require- or require_once-expression.
     *
     * @return \PDepend\Source\AST\ASTRequireExpression
     * @since  0.9.12
     */
    public function buildAstRequireExpression()
    {
        return $this->buildAstNodeInstance('ASTRequireExpression');
    }

    /**
     * Builds a new array-expression node.
     *
     * @return \PDepend\Source\AST\ASTArrayIndexExpression
     * @since  0.9.12
     */
    public function buildAstArrayIndexExpression()
    {
        return $this->buildAstNodeInstance('ASTArrayIndexExpression');
    }

    /**
     * Builds a new string-expression node.
     *
     * <code>
     * //     --------
     * $string{$index}
     * //     --------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTStringIndexExpression
     * @since  0.9.12
     */
    public function buildAstStringIndexExpression()
    {
        return $this->buildAstNodeInstance('ASTStringIndexExpression');
    }

    /**
     * Builds a new php array node.
     *
     * @return \PDepend\Source\AST\ASTArray
     * @since  1.0.0
     */
    public function buildAstArray()
    {
        return $this->buildAstNodeInstance('ASTArray');
    }

    /**
     * Builds a new array element node.
     *
     * @return \PDepend\Source\AST\ASTArrayElement
     * @since  1.0.0
     */
    public function buildAstArrayElement()
    {
        return $this->buildAstNodeInstance('ASTArrayElement');
    }


    /**
     * Builds a new instanceof expression node.
     *
     * @param string $image The source image of this expression.
     *
     * @return \PDepend\Source\AST\ASTInstanceOfExpression
     * @since  0.9.6
     */
    public function buildAstInstanceOfExpression($image)
    {
        return $this->buildAstNodeInstance('ASTInstanceOfExpression', $image);
    }

    /**
     * Builds a new isset-expression node.
     *
     * <code>
     * //  -----------
     * if (isset($foo)) {
     * //  -----------
     * }
     *
     * //  -----------------------
     * if (isset($foo, $bar, $baz)) {
     * //  -----------------------
     * }
     * </code>
     *
     * @return \PDepend\Source\AST\ASTIssetExpression
     * @since  0.9.12
     */
    public function buildAstIssetExpression()
    {
        return $this->buildAstNodeInstance('ASTIssetExpression');
    }

    /**
     * Builds a new boolean conditional-expression.
     *
     * <code>
     *         --------------
     * $bar = ($foo ? 42 : 23);
     *         --------------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTConditionalExpression
     * @since  0.9.8
     */
    public function buildAstConditionalExpression()
    {
        return $this->buildAstNodeInstance('ASTConditionalExpression', '?');
    }

    /**
     * Builds a new print-expression.
     *
     * <code>
     * -------------
     * print "qafoo";
     * -------------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTConditionalExpression
     * @since 2.3
     */
    public function buildAstPrintExpression()
    {
        return $this->buildAstNodeInstance('ASTPrintExpression', 'print');
    }

    /**
     * Build a new shift left expression.
     *
     * @return \PDepend\Source\AST\ASTShiftLeftExpression
     * @since  1.0.1
     */
    public function buildAstShiftLeftExpression()
    {
        return $this->buildAstNodeInstance('ASTShiftLeftExpression');
    }

    /**
     * Build a new shift right expression.
     *
     * @return \PDepend\Source\AST\ASTShiftRightExpression
     * @since  1.0.1
     */
    public function buildAstShiftRightExpression()
    {
        return $this->buildAstNodeInstance('ASTShiftRightExpression');
    }

    /**
     * Builds a new boolean and-expression.
     *
     * @return \PDepend\Source\AST\ASTBooleanAndExpression
     * @since  0.9.8
     */
    public function buildAstBooleanAndExpression()
    {
        return $this->buildAstNodeInstance('ASTBooleanAndExpression', '&&');
    }

    /**
     * Builds a new boolean or-expression.
     *
     * @return \PDepend\Source\AST\ASTBooleanOrExpression
     * @since  0.9.8
     */
    public function buildAstBooleanOrExpression()
    {
        return $this->buildAstNodeInstance('ASTBooleanOrExpression', '||');
    }

    /**
     * Builds a new logical <b>and</b>-expression.
     *
     * @return \PDepend\Source\AST\ASTLogicalAndExpression
     * @since  0.9.8
     */
    public function buildAstLogicalAndExpression()
    {
        return $this->buildAstNodeInstance('ASTLogicalAndExpression', 'and');
    }

    /**
     * Builds a new logical <b>or</b>-expression.
     *
     * @return \PDepend\Source\AST\ASTLogicalOrExpression
     * @since  0.9.8
     */
    public function buildAstLogicalOrExpression()
    {
        return $this->buildAstNodeInstance('ASTLogicalOrExpression', 'or');
    }

    /**
     * Builds a new logical <b>xor</b>-expression.
     *
     * @return \PDepend\Source\AST\ASTLogicalXorExpression
     * @since  0.9.8
     */
    public function buildAstLogicalXorExpression()
    {
        return $this->buildAstNodeInstance('ASTLogicalXorExpression', 'xor');
    }

    /**
     * Builds a new trait use-statement node.
     *
     * @return \PDepend\Source\AST\ASTTraitUseStatement
     * @since  1.0.0
     */
    public function buildAstTraitUseStatement()
    {
        return $this->buildAstNodeInstance('ASTTraitUseStatement');
    }

    /**
     * Builds a new trait adaptation scope
     *
     * @return \PDepend\Source\AST\ASTTraitAdaptation
     * @since  1.0.0
     */
    public function buildAstTraitAdaptation()
    {
        return $this->buildAstNodeInstance('ASTTraitAdaptation');
    }

    /**
     * Builds a new trait adaptation alias statement.
     *
     * @param string $image The trait method name.
     *
     * @return \PDepend\Source\AST\ASTTraitAdaptationAlias
     * @since  1.0.0
     */
    public function buildAstTraitAdaptationAlias($image)
    {
        return $this->buildAstNodeInstance('ASTTraitAdaptationAlias', $image);
    }

    /**
     * Builds a new trait adaptation precedence statement.
     *
     * @param string $image The trait method name.
     *
     * @return \PDepend\Source\AST\ASTTraitAdaptationPrecedence
     * @since  1.0.0
     */
    public function buildAstTraitAdaptationPrecedence($image)
    {
        return $this->buildAstNodeInstance('ASTTraitAdaptationPrecedence', $image);
    }

    /**
     * Builds a new switch-statement-node.
     *
     * @return \PDepend\Source\AST\ASTSwitchStatement
     * @since  0.9.8
     */
    public function buildAstSwitchStatement()
    {
        return $this->buildAstNodeInstance('ASTSwitchStatement');
    }

    /**
     * Builds a new switch-label node.
     *
     * @param string $image The source image of this label.
     *
     * @return \PDepend\Source\AST\ASTSwitchLabel
     * @since  0.9.8
     */
    public function buildAstSwitchLabel($image)
    {
        return $this->buildAstNodeInstance('ASTSwitchLabel', $image);
    }

    /**
     * Builds a new global-statement instance.
     *
     * @return \PDepend\Source\AST\ASTGlobalStatement
     * @since  0.9.12
     */
    public function buildAstGlobalStatement()
    {
        return $this->buildAstNodeInstance('ASTGlobalStatement');
    }

    /**
     * Builds a new unset-statement instance.
     *
     * @return \PDepend\Source\AST\ASTUnsetStatement
     * @since  0.9.12
     */
    public function buildAstUnsetStatement()
    {
        return $this->buildAstNodeInstance('ASTUnsetStatement');
    }

    /**
     * Builds a new catch-statement node.
     *
     * @param  string $image
     * @return \PDepend\Source\AST\ASTCatchStatement
     * @since  0.9.8
     */
    public function buildAstCatchStatement($image)
    {
        return $this->buildAstNodeInstance('ASTCatchStatement', $image);
    }

    /**
     * Builds a new finally-statement node.
     *
     * @return \PDepend\Source\AST\ASTFinallyStatement
     * @since  2.0.0
     */
    public function buildAstFinallyStatement()
    {
        return $this->buildAstNodeInstance('ASTFinallyStatement', 'finally');
    }

    /**
     * Builds a new if statement node.
     *
     * @param string $image The source image of this statement.
     *
     * @return \PDepend\Source\AST\ASTIfStatement
     * @since  0.9.8
     */
    public function buildAstIfStatement($image)
    {
        return $this->buildAstNodeInstance('ASTIfStatement', $image);
    }

    /**
     * Builds a new elseif statement node.
     *
     * @param string $image The source image of this statement.
     *
     * @return \PDepend\Source\AST\ASTElseIfStatement
     * @since  0.9.8
     */
    public function buildAstElseIfStatement($image)
    {
        return $this->buildAstNodeInstance('ASTElseIfStatement', $image);
    }

    /**
     * Builds a new for statement node.
     *
     * @param string $image The source image of this statement.
     *
     * @return \PDepend\Source\AST\ASTForStatement
     * @since  0.9.8
     */
    public function buildAstForStatement($image)
    {
        return $this->buildAstNodeInstance('ASTForStatement', $image);
    }

    /**
     * Builds a new for-init node.
     *
     * <code>
     *      ------------------------
     * for ($x = 0, $y = 23, $z = 42; $x < $y; ++$x) {}
     *      ------------------------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTForInit
     * @since  0.9.8
     */
    public function buildAstForInit()
    {
        return $this->buildAstNodeInstance('ASTForInit');
    }

    /**
     * Builds a new for-update node.
     *
     * <code>
     *                                        -------------------------------
     * for ($x = 0, $y = 23, $z = 42; $x < $y; ++$x, $y = $x + 1, $z = $x + 2) {}
     *                                        -------------------------------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTForUpdate
     * @since  0.9.12
     */
    public function buildAstForUpdate()
    {
        return $this->buildAstNodeInstance('ASTForUpdate');
    }

    /**
     * Builds a new foreach-statement node.
     *
     * @param string $image The source image of this statement.
     *
     * @return \PDepend\Source\AST\ASTForeachStatement
     * @since  0.9.8
     */
    public function buildAstForeachStatement($image)
    {
        return $this->buildAstNodeInstance('ASTForeachStatement', $image);
    }

    /**
     * Builds a new while-statement node.
     *
     * @param string $image The source image of this statement.
     *
     * @return \PDepend\Source\AST\ASTWhileStatement
     * @since  0.9.8
     */
    public function buildAstWhileStatement($image)
    {
        return $this->buildAstNodeInstance('ASTWhileStatement', $image);
    }

    /**
     * Builds a new do/while-statement node.
     *
     * @param string $image The source image of this statement.
     *
     * @return \PDepend\Source\AST\ASTDoWhileStatement
     * @since  0.9.12
     */
    public function buildAstDoWhileStatement($image)
    {
        return $this->buildAstNodeInstance('ASTDoWhileStatement', $image);
    }

    /**
     * Builds a new declare-statement node.
     *
     * <code>
     * -------------------------------
     * declare(encoding='ISO-8859-1');
     * -------------------------------
     *
     * -------------------
     * declare(ticks=42) {
     *     // ...
     * }
     * -
     *
     * ------------------
     * declare(ticks=42):
     *     // ...
     * enddeclare;
     * -----------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTDeclareStatement
     * @since  0.10.0
     */
    public function buildAstDeclareStatement()
    {
        return $this->buildAstNodeInstance('ASTDeclareStatement');
    }

    /**
     * Builds a new member primary expression node.
     *
     * <code>
     * //--------
     * Foo::bar();
     * //--------
     *
     * //---------
     * Foo::$bar();
     * //---------
     *
     * //---------
     * $obj->bar();
     * //---------
     *
     * //----------
     * $obj->$bar();
     * //----------
     * </code>
     *
     * @param string $image The source image of this expression.
     *
     * @return \PDepend\Source\AST\ASTMemberPrimaryPrefix
     * @since  0.9.6
     */
    public function buildAstMemberPrimaryPrefix($image)
    {
        return $this->buildAstNodeInstance('ASTMemberPrimaryPrefix', $image);
    }

    /**
     * Builds a new identifier node.
     *
     * @param string $image The image of this identifier.
     *
     * @return \PDepend\Source\AST\ASTIdentifier
     * @since  0.9.6
     */
    public function buildAstIdentifier($image)
    {
        return $this->buildAstNodeInstance('ASTIdentifier', $image);
    }

    /**
     * Builds a new function postfix expression.
     *
     * <code>
     * //-------
     * foo($bar);
     * //-------
     *
     * //--------
     * $foo($bar);
     * //--------
     * </code>
     *
     * @param string $image The image of this node.
     *
     * @return \PDepend\Source\AST\ASTFunctionPostfix
     * @since  0.9.6
     */
    public function buildAstFunctionPostfix($image)
    {
        return $this->buildAstNodeInstance('ASTFunctionPostfix', $image);
    }

    /**
     * Builds a new method postfix expression.
     *
     * <code>
     * //   ---------
     * Foo::bar($baz);
     * //   ---------
     *
     * //   ----------
     * Foo::$bar($baz);
     * //   ----------
     * </code>
     *
     * @param string $image The image of this node.
     *
     * @return \PDepend\Source\AST\ASTMethodPostfix
     * @since  0.9.6
     */
    public function buildAstMethodPostfix($image)
    {
        return $this->buildAstNodeInstance('ASTMethodPostfix', $image);
    }

    /**
     * Builds a new constant postfix expression.
     *
     * <code>
     * //   ---
     * Foo::BAR;
     * //   ---
     * </code>
     *
     * @param string $image The image of this node.
     *
     * @return \PDepend\Source\AST\ASTConstantPostfix
     * @since  0.9.6
     */
    public function buildAstConstantPostfix($image)
    {
        return $this->buildAstNodeInstance('ASTConstantPostfix', $image);
    }

    /**
     * Builds a new property postfix expression.
     *
     * <code>
     * //   ----
     * Foo::$bar;
     * //   ----
     *
     * //       ---
     * $object->bar;
     * //       ---
     * </code>
     *
     * @param string $image The image of this node.
     *
     * @return \PDepend\Source\AST\ASTPropertyPostfix
     * @since  0.9.6
     */
    public function buildAstPropertyPostfix($image)
    {
        return $this->buildAstNodeInstance('ASTPropertyPostfix', $image);
    }

    /**
     * Builds a new full qualified class name postfix expression.
     *
     * <code>
     * //   -----
     * Foo::class;
     * //   -----
     *
     * //       -----
     * $object::class;
     * //       -----
     * </code>
     *
     * @return \PDepend\Source\AST\ASTClassFqnPostfix
     * @since  2.0.0
     */
    public function buildAstClassFqnPostfix()
    {
        return $this->buildAstNodeInstance('ASTClassFqnPostfix', 'class');
    }

    /**
     * Builds a new arguments list.
     *
     * <code>
     * //      ------------
     * Foo::bar($x, $y, $z);
     * //      ------------
     *
     * //       ------------
     * $foo->bar($x, $y, $z);
     * //       ------------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTArguments
     * @since  0.9.6
     */
    public function buildAstArguments()
    {
        return $this->buildAstNodeInstance('ASTArguments');
    }

    /**
     * Builds a new array type node.
     *
     * @return \PDepend\Source\AST\ASTTypeArray
     * @since  0.9.6
     */
    public function buildAstTypeArray()
    {
        return $this->buildAstNodeInstance('ASTTypeArray');
    }

    /**
     * Builds a new node for the callable type.
     *
     * @return \PDepend\Source\AST\ASTTypeCallable
     * @since  1.0.0
     */
    public function buildAstTypeCallable()
    {
        return $this->buildAstNodeInstance('ASTTypeCallable');
    }

    /**
     * Builds a new primitive type node.
     *
     * @param string $image The source image for the primitive type.
     *
     * @return \PDepend\Source\AST\ASTScalarType
     * @since  0.9.6
     */
    public function buildAstScalarType($image)
    {
        return $this->buildAstNodeInstance('ASTScalarType', $image);
    }

    /**
     * Builds a new literal node.
     *
     * @param string $image The source image for the literal node.
     *
     * @return \PDepend\Source\AST\ASTLiteral
     * @since  0.9.6
     */
    public function buildAstLiteral($image)
    {
        return $this->buildAstNodeInstance('ASTLiteral', $image);
    }

    /**
     * Builds a new php string node.
     *
     * <code>
     * $string = "Manuel $Pichler <{$email}>";
     *
     * // \PDepend\Source\AST\ASTString
     * // |-- ASTLiteral             -  "Manuel ")
     * // |-- ASTVariable            -  $Pichler
     * // |-- ASTLiteral             -  " <"
     * // |-- ASTCompoundExpression  -  {...}
     * // |   |-- ASTVariable        -  $email
     * // |-- ASTLiteral             -  ">"
     * </code>
     *
     * @return \PDepend\Source\AST\ASTString
     * @since  0.9.10
     */
    public function buildAstString()
    {
        return $this->buildAstNodeInstance('ASTString');
    }

    /**
     * Builds a new heredoc node.
     *
     * @return \PDepend\Source\AST\ASTHeredoc
     * @since  0.9.12
     */
    public function buildAstHeredoc()
    {
        return $this->buildAstNodeInstance('ASTHeredoc');
    }

    /**
     * Builds a new constant definition node.
     *
     * <code>
     * class Foo
     * {
     * //  ------------------------
     *     const FOO = 42, BAR = 23;
     * //  ------------------------
     * }
     * </code>
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTConstantDefinition
     * @since  0.9.6
     */
    public function buildAstConstantDefinition($image)
    {
        return $this->buildAstNodeInstance('ASTConstantDefinition', $image);
    }

    /**
     * Builds a new constant declarator node.
     *
     * <code>
     * class Foo
     * {
     *     //    --------
     *     const BAR = 42;
     *     //    --------
     * }
     * </code>
     *
     * Or in a comma separated constant defintion:
     *
     * <code>
     * class Foo
     * {
     *     //    --------
     *     const BAR = 42,
     *     //    --------
     *
     *     //    --------------
     *     const BAZ = 'Foobar',
     *     //    --------------
     *
     *     //    ----------
     *     const FOO = 3.14;
     *     //    ----------
     * }
     * </code>
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTConstantDeclarator
     * @since  0.9.6
     */
    public function buildAstConstantDeclarator($image)
    {
        return $this->buildAstNodeInstance('ASTConstantDeclarator', $image);
    }

    /**
     * Builds a new comment node instance.
     *
     * @param string $cdata The comment text.
     *
     * @return \PDepend\Source\AST\ASTComment
     * @since  0.9.8
     */
    public function buildAstComment($cdata)
    {
        return $this->buildAstNodeInstance('ASTComment', $cdata);
    }

    /**
     * Builds a new unary expression node instance.
     *
     * @param string $image The unary expression image/character.
     *
     * @return \PDepend\Source\AST\ASTUnaryExpression
     * @since  0.9.11
     */
    public function buildAstUnaryExpression($image)
    {
        return $this->buildAstNodeInstance('ASTUnaryExpression', $image);
    }

    /**
     * Builds a new cast-expression node instance.
     *
     * @param string $image The cast-expression image/character.
     *
     * @return \PDepend\Source\AST\ASTCastExpression
     * @since  0.10.0
     */
    public function buildAstCastExpression($image)
    {
        return $this->buildAstNodeInstance('ASTCastExpression', $image);
    }

    /**
     * Builds a new postfix-expression node instance.
     *
     * @param string $image The postfix-expression image/character.
     *
     * @return \PDepend\Source\AST\ASTPostfixExpression
     * @since  0.10.0
     */
    public function buildAstPostfixExpression($image)
    {
        return $this->buildAstNodeInstance('ASTPostfixExpression', $image);
    }

    /**
     * Builds a new pre-increment-expression node instance.
     *
     * @return \PDepend\Source\AST\ASTPreIncrementExpression
     * @since  0.10.0
     */
    public function buildAstPreIncrementExpression()
    {
        return $this->buildAstNodeInstance('ASTPreIncrementExpression');
    }

    /**
     * Builds a new pre-decrement-expression node instance.
     *
     * @return \PDepend\Source\AST\ASTPreDecrementExpression
     * @since  0.10.0
     */
    public function buildAstPreDecrementExpression()
    {
        return $this->buildAstNodeInstance('ASTPreDecrementExpression');
    }

    /**
     * Builds a new function/method scope instance.
     *
     * @return \PDepend\Source\AST\ASTScope
     * @since  0.9.12
     */
    public function buildAstScope()
    {
        return $this->buildAstNodeInstance('ASTScope');
    }

    /**
     * Builds a new statement instance.
     *
     * @return \PDepend\Source\AST\ASTStatement
     * @since  0.9.12
     */
    public function buildAstStatement()
    {
        return $this->buildAstNodeInstance('ASTStatement');
    }

    /**
     * Builds a new return statement node instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTReturnStatement
     * @since  0.9.12
     */
    public function buildAstReturnStatement($image)
    {
        return $this->buildAstNodeInstance('ASTReturnStatement', $image);
    }

    /**
     * Builds a new break-statement node instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTBreakStatement
     * @since  0.9.12
     */
    public function buildAstBreakStatement($image)
    {
        return $this->buildAstNodeInstance('ASTBreakStatement', $image);
    }

    /**
     * Builds a new continue-statement node instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTContinueStatement
     * @since  0.9.12
     */
    public function buildAstContinueStatement($image)
    {
        return $this->buildAstNodeInstance('ASTContinueStatement', $image);
    }

    /**
     * Builds a new scope-statement instance.
     *
     * @return \PDepend\Source\AST\ASTScopeStatement
     * @since  0.9.12
     */
    public function buildAstScopeStatement()
    {
        return $this->buildAstNodeInstance('ASTScopeStatement');
    }

    /**
     * Builds a new try-statement instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTTryStatement
     * @since  0.9.12
     */
    public function buildAstTryStatement($image)
    {
        return $this->buildAstNodeInstance('ASTTryStatement', $image);
    }

    /**
     * Builds a new throw-statement instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTThrowStatement
     * @since  0.9.12
     */
    public function buildAstThrowStatement($image)
    {
        return $this->buildAstNodeInstance('ASTThrowStatement', $image);
    }

    /**
     * Builds a new goto-statement instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTGotoStatement
     * @since  0.9.12
     */
    public function buildAstGotoStatement($image)
    {
        return $this->buildAstNodeInstance('ASTGotoStatement', $image);
    }

    /**
     * Builds a new label-statement instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTLabelStatement
     * @since  0.9.12
     */
    public function buildAstLabelStatement($image)
    {
        return $this->buildAstNodeInstance('ASTLabelStatement', $image);
    }

    /**
     * Builds a new exit-statement instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTEchoStatement
     * @since  0.9.12
     */
    public function buildAstEchoStatement($image)
    {
        return $this->buildAstNodeInstance('ASTEchoStatement', $image);
    }

    /**
     * Builds a new yield-statement instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTYieldStatement
     * @since  $version$
     */
    public function buildAstYieldStatement($image)
    {
        return $this->buildAstNodeInstance('ASTYieldStatement', $image);
    }

    /**
     * Returns an iterator with all generated {@link \PDepend\Source\AST\ASTNamespace}
     * objects.
     *
     * @return \PDepend\Source\AST\ASTArtifactList
     */
    public function getIterator()
    {
        return $this->getNamespaces();
    }

    /**
     * Returns an iterator with all generated {@link \PDepend\Source\AST\ASTNamespace}
     * objects.
     *
     * @return \PDepend\Source\AST\ASTNamespace[]
     */
    public function getNamespaces()
    {
        if ($this->preparedNamespaces === null) {
            $this->preparedNamespaces = $this->getPreparedNamespaces();
        }
        return new ASTArtifactList($this->preparedNamespaces);
    }

    /**
     * Returns an iterator with all generated {@link \PDepend\Source\AST\ASTNamespace}
     * objects.
     *
     * @return \PDepend\Source\AST\ASTArtifactList
     * @since  0.9.12
     */
    private function getPreparedNamespaces()
    {
        // Create a package array copy
        $namespaces = $this->namespaces;

        // Remove default package if empty
        if ($this->defaultPackage->getTypes()->count() === 0
            && $this->defaultPackage->getFunctions()->count() === 0
        ) {
            unset($namespaces[self::DEFAULT_NAMESPACE]);
        }
        return $namespaces;
    }

    /**
     * Builds a new trait instance or reuses a previous created trait.
     *
     * Where possible you should give a qualified trait name, that is prefixed
     * with the package identifier.
     *
     * <code>
     *   $builder->buildTrait('php::depend::Parser');
     * </code>
     *
     * To determine the correct trait, this method implements the following
     * algorithm.
     *
     * <ol>
     *   <li>Check for an exactly matching instance and reuse it.</li>
     *   <li>Check for a class instance that belongs to the default package. If
     *   such an instance exists, reuse it and replace the default package with
     *   the newly given package information.</li>
     *   <li>Check that the requested trait is in the default package, if this
     *   is true, reuse the first trait instance and ignore the default package.
     *   </li>
     *   <li>Create a new instance for the specified package.</li>
     * </ol>
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\ASTTrait
     * @since  0.9.5
     */
    protected function buildTraitInternal($qualifiedName)
    {
        $this->internal = true;

        $trait = $this->buildTrait($qualifiedName);
        $trait->setNamespace(
            $this->buildNamespace($this->extractNamespaceName($qualifiedName))
        );

        $this->restoreTrait($trait);

        return $trait;
    }

    /**
     * This method tries to find a trait instance matching for the given
     * qualified name in all scopes already processed. It will return the best
     * matching instance or <b>null</b> if no match exists.
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\ASTTrait
     * @since  0.9.5
     */
    protected function findTrait($qualifiedName)
    {
        $this->freeze();

        $trait = $this->findType(
            $this->frozenTraits,
            $qualifiedName
        );

        if ($trait === null) {
            $trait = $this->findType($this->traits, $qualifiedName);
        }
        return $trait;
    }

    /**
     * Builds a new new interface instance.
     *
     * If there is an existing interface instance for the given name, this method
     * checks if this interface is part of the default namespace. If this is the
     * case this method will update all references to the new interface and it
     * removes the class instance. Otherwise it creates new interface instance.
     *
     * Where possible you should give a qualified interface name, that is
     * prefixed with the package identifier.
     *
     * <code>
     *   $builder->buildInterface('php::depend::Parser');
     * </code>
     *
     * To determine the correct interface, this method implements the following
     * algorithm.
     *
     * <ol>
     *   <li>Check for an exactly matching instance and reuse it.</li>
     *   <li>Check for a interface instance that belongs to the default package.
     *   If such an instance exists, reuse it and replace the default package
     *   with the newly given package information.</li>
     *   <li>Check that the requested interface is in the default package, if
     *   this is true, reuse the first interface instance and ignore the default
     *   package.
     *   </li>
     *   <li>Create a new instance for the specified package.</li>
     * </ol>
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\ASTInterface
     * @since  0.9.5
     */
    protected function buildInterfaceInternal($qualifiedName)
    {
        $this->internal = true;

        $interface = $this->buildInterface($qualifiedName);
        $interface->setNamespace(
            $this->buildNamespace($this->extractNamespaceName($qualifiedName))
        );

        $this->restoreInterface($interface);

        return $interface;
    }

    /**
     * This method tries to find an interface instance matching for the given
     * qualified name in all scopes already processed. It will return the best
     * matching instance or <b>null</b> if no match exists.
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\ASTInterface
     * @since  0.9.5
     */
    protected function findInterface($qualifiedName)
    {
        $this->freeze();

        $interface = $this->findType(
            $this->frozenInterfaces,
            $qualifiedName
        );

        if ($interface === null) {
            $interface = $this->findType(
                $this->interfaces,
                $qualifiedName
            );
        }
        return $interface;
    }

    /**
     * Builds a new class instance or reuses a previous created class.
     *
     * Where possible you should give a qualified class name, that is prefixed
     * with the package identifier.
     *
     * <code>
     *   $builder->buildClass('php::depend::Parser');
     * </code>
     *
     * To determine the correct class, this method implements the following
     * algorithm.
     *
     * <ol>
     *   <li>Check for an exactly matching instance and reuse it.</li>
     *   <li>Check for a class instance that belongs to the default package. If
     *   such an instance exists, reuse it and replace the default package with
     *   the newly given package information.</li>
     *   <li>Check that the requested class is in the default package, if this
     *   is true, reuse the first class instance and ignore the default package.
     *   </li>
     *   <li>Create a new instance for the specified package.</li>
     * </ol>
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\ASTClass
     * @since  0.9.5
     */
    protected function buildClassInternal($qualifiedName)
    {
        $this->internal = true;

        $class = $this->buildClass($qualifiedName);
        $class->setNamespace(
            $this->buildNamespace($this->extractNamespaceName($qualifiedName))
        );

        $this->restoreClass($class);

        return $class;
    }

    /**
     * This method tries to find a class instance matching for the given
     * qualified name in all scopes already processed. It will return the best
     * matching instance or <b>null</b> if no match exists.
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\ASTClass
     * @since  0.9.5
     */
    protected function findClass($qualifiedName)
    {
        $this->freeze();

        $class = $this->findType(
            $this->frozenClasses,
            $qualifiedName
        );

        if ($class === null) {
            $class = $this->findType($this->classes, $qualifiedName);
        }
        return $class;
    }

    /**
     * This method tries to find an interface or class instance matching for the
     * given qualified name in all scopes already processed. It will return the
     * best matching instance or <b>null</b> if no match exists.
     *
     * @param  array  $instances
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\AbstractASTType
     * @since  0.9.5
     */
    protected function findType(array $instances, $qualifiedName)
    {
        $classOrInterfaceName = $this->extractTypeName($qualifiedName);
        $namespaceName = $this->extractNamespaceName($qualifiedName);

        $caseInsensitiveName = strtolower($classOrInterfaceName);

        if (!isset($instances[$caseInsensitiveName])) {
            return null;
        }

        // Check for exact match and return first matching instance
        if (isset($instances[$caseInsensitiveName][$namespaceName])) {
            return reset($instances[$caseInsensitiveName][$namespaceName]);
        }

        if (!$this->isDefault($namespaceName)) {
            return null;
        }

        $classesOrInterfaces = reset($instances[$caseInsensitiveName]);
        return reset($classesOrInterfaces);
    }

    /**
     * This method will freeze the actual builder state and create a second
     * runtime scope.
     *
     * @return void
     * @since  0.9.5
     */
    protected function freeze()
    {
        if ($this->frozen === true) {
            return;
        }

        $this->frozen = true;

        $this->frozenTraits     = $this->copyTypesWithPackage($this->traits);
        $this->frozenClasses    = $this->copyTypesWithPackage($this->classes);
        $this->frozenInterfaces = $this->copyTypesWithPackage($this->interfaces);

        $this->traits     = array();
        $this->classes    = array();
        $this->interfaces = array();
    }

    /**
     * Creates a copy of the given input array, but skips all types that do not
     * contain a parent package.
     *
     * @param array $originalTypes The original types created during the parsing
     *        process.
     *
     * @return array
     */
    private function copyTypesWithPackage(array $originalTypes)
    {
        $copiedTypes = array();
        foreach ($originalTypes as $typeName => $namespaces) {
            foreach ($namespaces as $namespaceName => $types) {
                foreach ($types as $index => $type) {
                    if (is_object($type->getNamespace())) {
                        $copiedTypes[$typeName][$namespaceName][$index] = $type;
                    }
                }
            }
        }
        return $copiedTypes;
    }

    /**
     * Restores a function within the internal type scope.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     * @since  0.10.0
     */
    public function restoreFunction(ASTFunction $function)
    {
        $this->buildNamespace($function->getNamespaceName())
            ->addFunction($function);
    }

    /**
     * Restores a trait within the internal type scope.
     *
     * @param  \PDepend\Source\AST\ASTTrait $trait
     * @return void
     * @since  0.10.0
     */
    public function restoreTrait(ASTTrait $trait)
    {
        $this->storeTrait(
            $trait->getName(),
            $trait->getNamespaceName(),
            $trait
        );
    }

    /**
     * Restores a class within the internal type scope.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     * @since  0.10.0
     */
    public function restoreClass(ASTClass $class)
    {
        $this->storeClass(
            $class->getName(),
            $class->getNamespaceName(),
            $class
        );
    }

    /**
     * Restores an interface within the internal type scope.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     * @since  0.10.0
     */
    public function restoreInterface(ASTInterface $interface)
    {
        $this->storeInterface(
            $interface->getName(),
            $interface->getNamespaceName(),
            $interface
        );
    }

    /**
     * This method will persist a trait instance for later reuse.
     *
     * @param  string                       $traitName
     * @param  string                       $namespaceName
     * @param  \PDepend\Source\AST\ASTTrait $trait
     * @return void
     * @@since 1.0.0
     */
    protected function storeTrait($traitName, $namespaceName, ASTTrait $trait)
    {
        $traitName = strtolower($traitName);
        if (!isset($this->traits[$traitName][$namespaceName])) {
            $this->traits[$traitName][$namespaceName] = array();
        }
        $this->traits[$traitName][$namespaceName][$trait->getId()] = $trait;

        $namespace = $this->buildNamespace($namespaceName);
        $namespace->addType($trait);
    }

    /**
     * This method will persist a class instance for later reuse.
     *
     * @param  string                       $className
     * @param  string                       $namespaceName
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     * @@since 0.9.5
     */
    protected function storeClass($className, $namespaceName, ASTClass $class)
    {
        $className = strtolower($className);
        if (!isset($this->classes[$className][$namespaceName])) {
            $this->classes[$className][$namespaceName] = array();
        }
        $this->classes[$className][$namespaceName][$class->getId()] = $class;

        $namespace = $this->buildNamespace($namespaceName);
        $namespace->addType($class);
    }

    /**
     * This method will persist an interface instance for later reuse.
     *
     * @param  string                           $interfaceName
     * @param  string                           $namespaceName
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     * @@since 0.9.5
     */
    protected function storeInterface($interfaceName, $namespaceName, ASTInterface $interface)
    {
        $interfaceName = strtolower($interfaceName);
        if (!isset($this->interfaces[$interfaceName][$namespaceName])) {
            $this->interfaces[$interfaceName][$namespaceName] = array();
        }
        $this->interfaces[$interfaceName][$namespaceName][$interface->getId()]
            = $interface;

        $namespace = $this->buildNamespace($namespaceName);
        $namespace->addType($interface);
    }

    /**
     * Checks that the parser is not frozen or a request is flagged as internal.
     *
     * @param  boolean $internal The new internal flag value.
     * @return void
     * @throws \BadMethodCallException
     * @since  0.9.5
     */
    protected function checkBuilderState($internal = false)
    {
        if ($this->frozen === true && $this->internal === false) {
            throw new \BadMethodCallException(
                'Cannot create new nodes, when internal state is frozen.'
            );
        }
        $this->internal = $internal;
    }


    /**
     * Returns <b>true</b> if the given package is the default package.
     *
     * @param  string $namespaceName The package name.
     * @return boolean
     */
    protected function isDefault($namespaceName)
    {
        return ($namespaceName === self::DEFAULT_NAMESPACE);
    }

    /**
     * Extracts the type name of a qualified PHP 5.3 type identifier.
     *
     * <code>
     *   $typeName = $this->extractTypeName('foo\bar\foobar');
     *   var_dump($typeName);
     *   // Results in:
     *   // string(6) "foobar"
     * </code>
     *
     * @param string $qualifiedName The qualified PHP 5.3 type identifier.
     *
     * @return string
     */
    protected function extractTypeName($qualifiedName)
    {
        if (($pos = strrpos($qualifiedName, '\\')) !== false) {
            return substr($qualifiedName, $pos + 1);
        }
        return $qualifiedName;
    }

    /**
     * Extracts the package name of a qualified PHP 5.3 class identifier.
     *
     * If the class name doesn't contain a package identifier this method will
     * return the default identifier.
     *
     * <code>
     *   $namespaceName = $this->extractPackageName('foo\bar\foobar');
     *   var_dump($namespaceName);
     *   // Results in:
     *   // string(8) "foo\bar"
     *
     *   $namespaceName = $this->extractPackageName('foobar');
     *   var_dump($namespaceName);
     *   // Results in:
     *   // string(6) "+global"
     * </code>
     *
     * @param string $qualifiedName The qualified PHP 5.3 class identifier.
     *
     * @return string
     */
    protected function extractNamespaceName($qualifiedName)
    {
        if (($pos = strrpos($qualifiedName, '\\')) !== false) {
            return ltrim(substr($qualifiedName, 0, $pos), '\\');
        } elseif (Type::isInternalType($qualifiedName)) {
            return Type::getTypePackage($qualifiedName);
        }
        return self::DEFAULT_NAMESPACE;
    }

    /**
     * Creates a {@link \PDepend\Source\AST\ASTNode} instance.
     *
     * @param string $className
     * @param string $image
     * @return \PDepend\Source\AST\ASTNode
     * @since 0.9.12
     */
    private function buildAstNodeInstance($className, $image = null)
    {
        $className = "\\PDepend\\Source\\AST\\{$className}";

        Log::debug("Creating: {$className}({$image})");

        return new $className($image);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.20
 */

namespace PDepend\Source\Language\PHP;

use PDepend\Source\AST\ASTValue;
use PDepend\Source\Parser\TokenStreamEndException;
use PDepend\Source\Parser\UnexpectedTokenException;
use PDepend\Source\Tokenizer\Tokenizer;
use PDepend\Source\Tokenizer\Tokens;

/**
 * Concrete parser implementation that is very tolerant and accepts language
 * constructs and keywords that are reserved in newer php versions, but not in
 * older versions.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.20
 */
class PHPParserGeneric extends PHPParserVersion71
{
    /**
     * Tests if the given token type is a reserved keyword in the supported PHP
     * version.
     *
     * @param  $tokenType
     * @return boolean
     * @since  1.1.1
     */
    protected function isKeyword($tokenType)
    {
        switch ($tokenType) {
            case Tokens::T_CLASS:
            case Tokens::T_INTERFACE:
                return true;
        }
        return false;
    }

    /**
     * Will return <b>true</b> if the given <b>$tokenType</b> is a valid class
     * name part.
     *
     * @param integer $tokenType The type of a parsed token.
     *
     * @return boolean
     * @since  0.10.6
     */
    protected function isClassName($tokenType)
    {
        switch ($tokenType) {
            case Tokens::T_DIR:
            case Tokens::T_USE:
            case Tokens::T_GOTO:
            case Tokens::T_NULL:
            case Tokens::T_NS_C:
            case Tokens::T_TRUE:
            case Tokens::T_CLONE:
            case Tokens::T_FALSE:
            case Tokens::T_TRAIT:
            case Tokens::T_STRING:
            case Tokens::T_TRAIT_C:
            case Tokens::T_CALLABLE:
            case Tokens::T_INSTEADOF:
            case Tokens::T_NAMESPACE:
                return true;
        }
        return false;
    }

    /**
     * Tests if the give token is a valid function name in the supported PHP
     * version.
     *
     * @param integer $tokenType
     * @return boolean
     * @since 2.3
     */
    protected function isFunctionName($tokenType)
    {
        switch ($tokenType) {
            case Tokens::T_CLONE:
            case Tokens::T_STRING:
            case Tokens::T_USE:
            case Tokens::T_GOTO:
            case Tokens::T_NULL:
            case Tokens::T_SELF:
            case Tokens::T_TRUE:
            case Tokens::T_FALSE:
            case Tokens::T_TRAIT:
            case Tokens::T_INSTEADOF:
            case Tokens::T_NAMESPACE:
            case Tokens::T_DIR:
            case Tokens::T_NS_C:
            case Tokens::T_YIELD:
            case Tokens::T_PARENT:
            case Tokens::T_TRAIT_C:
                return true;
        }
        return false;
    }

    /**
     * Implements some quirks and hacks to support php here- and now-doc for
     * PHP 5.2.x versions :/
     *
     * @return \PDepend\Source\AST\ASTHeredoc
     * @since 1.0.0
     */
    protected function parseHeredoc()
    {
        $heredoc = parent::parseHeredoc();
        if (version_compare(phpversion(), "5.3.0alpha") >= 0) {
            return $heredoc;
        }

        // Consume dangling semicolon
        $this->tokenizer->next();

        $token = $this->tokenizer->next();
        preg_match('(/\*(\'|")\*/)', $token->image, $match);

        return $heredoc;
    }

    /**
     * Parses additional static values that are valid in the supported php version.
     *
     * @param \PDepend\Source\AST\ASTValue $value
     * @return \PDepend\Source\AST\ASTValue
     * @throws \PDepend\Source\Parser\UnexpectedTokenException
     * @todo Handle shift left/right expressions in ASTValue
     */ /*
    protected function parseStaticValueVersionSpecific(ASTValue $value)
    {
        switch ($this->tokenizer->peek()) {
            case Tokens::T_SL:
                $shift = $this->parseShiftLeftExpression();
                $this->parseStaticValue();
                break;
            case Tokens::T_SR:
                $shift = $this->parseShiftRightExpression();
                $this->parseStaticValue();
                break;
            default:
                throw new UnexpectedTokenException(
                    $this->tokenizer->next(),
                    $this->tokenizer->getSourceFile()
                );
        }

        return $value;
    }*/

    /**
     * Parses constant default values as they are supported by the most recent
     * PHP version.
     *
     * @return \PDepend\Source\AST\ASTValue
     * @since 2.2.x
     */
    protected function parseConstantDeclaratorValue()
    {
        return $this->parseStaticValueOrStaticArray();
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.3
 */

namespace PDepend\Source\Language\PHP;

use PDepend\Source\AST\ASTArray;
use PDepend\Source\Parser\UnexpectedTokenException;
use PDepend\Source\Tokenizer\Tokens;

/**
 * Concrete parser implementation that supports features up to PHP version 5.4.
 *
 * TODO:
 * - Non constant operands are forbidden now in break and continue
 *   - break $var
 *   - continue $var
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.3
 */
abstract class PHPParserVersion54 extends PHPParserVersion53
{
    /**
     * Will return <b>true</b> if the given <b>$tokenType</b> is a valid class
     * name part.
     *
     * @param  integer $tokenType The type of a parsed token.
     * @return boolean
     * @since  0.10.6
     */
    protected function isClassName($tokenType)
    {
        switch ($tokenType) {
            case Tokens::T_NULL:
            case Tokens::T_TRUE:
            case Tokens::T_FALSE:
            case Tokens::T_STRING:
                return true;
        }
        return false;
    }

    /**
     * @param integer $tokenType
     * @return boolean
     */
    protected function isConstantName($tokenType)
    {
        return $this->isFunctionName($tokenType);
    }

    /**
     * @param integer $tokenType
     * @return bool
     */
    protected function isMethodName($tokenType)
    {
        return $this->isFunctionName($tokenType);
    }

    /**
     * Tests if the give token is a valid function name in the supported PHP
     * version.
     *
     * @param integer $tokenType
     * @return boolean
     * @since 2.3
     */
    protected function isFunctionName($tokenType)
    {
        switch ($tokenType) {
            case Tokens::T_STRING:
            case Tokens::T_NULL:
            case Tokens::T_SELF:
            case Tokens::T_TRUE:
            case Tokens::T_FALSE:
            case Tokens::T_PARENT:
                return true;
        }
        return false;
    }

    /**
     * Tests if the given token type is a reserved keyword in the supported PHP
     * version.
     *
     * @param integer $tokenType
     * @return boolean
     */
    protected function isKeyword($tokenType)
    {
        switch ($tokenType) {
            case Tokens::T_CLASS:
            case Tokens::T_TRAIT:
            case Tokens::T_CALLABLE:
            case Tokens::T_INSTEADOF:
            case Tokens::T_INTERFACE:
                return true;
        }
        return false;
    }

    /**
     * Tests if the given token type is a valid type hint in the supported
     * PHP version.
     *
     * @param integer $tokenType
     * @return boolean
     * @since 1.0.0
     */
    protected function isTypeHint($tokenType)
    {
        switch ($tokenType) {
            case Tokens::T_CALLABLE:
                return true;
            default:
                return parent::isTypeHint($tokenType);
        }
    }

    /**
     * Parses a type hint that is valid in the supported PHP version.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @since 1.0.0
     */
    protected function parseTypeHint()
    {
        switch ($this->tokenizer->peek()) {
            case Tokens::T_CALLABLE:
                $this->consumeToken(Tokens::T_CALLABLE);
                $type = $this->builder->buildAstTypeCallable();
                break;
            default:
                $type = parent::parseTypeHint();
                break;
        }
        return $type;
    }

    /**
     * Tests if the next token is a valid array start delimiter in the supported
     * PHP version.
     *
     * @return boolean
     * @since 1.0.0
     */
    protected function isArrayStartDelimiter()
    {
        switch ($this->tokenizer->peek()) {
            case Tokens::T_ARRAY:
            case Tokens::T_SQUARED_BRACKET_OPEN:
                return true;
        }
        return false;
    }

    /**
     * Parses a php array declaration.
     *
     * @param \PDepend\Source\AST\ASTArray $array
     * @param boolean $static
     * @return \PDepend\Source\AST\ASTArray
     * @since 1.0.0
     */
    protected function parseArray(ASTArray $array, $static = false)
    {
        switch ($this->tokenizer->peek()) {
            case Tokens::T_SQUARED_BRACKET_OPEN:
                $this->consumeToken(Tokens::T_SQUARED_BRACKET_OPEN);
                $this->parseArrayElements($array, Tokens::T_SQUARED_BRACKET_CLOSE, $static);
                $this->consumeToken(Tokens::T_SQUARED_BRACKET_CLOSE);
                break;
            default:
                parent::parseArray($array, $static);
                break;
        }
        return $array;
    }

    /**
     * Parses an integer value.
     *
     * @return \PDepend\Source\AST\ASTLiteral
     * @throws \PDepend\Source\Parser\UnexpectedTokenException
     */
    protected function parseIntegerNumber()
    {
        $token = $this->consumeToken(Tokens::T_LNUMBER);

        if ('0' !== substr($token->image, 0, 1)) {
            goto BUILD_LITERAL;
        }

        if (Tokens::T_STRING !== $this->tokenizer->peek()) {
            goto BUILD_LITERAL;
        }

        $token1 = $this->consumeToken(Tokens::T_STRING);
        if (0 === preg_match('(^b[01]+$)', $token1->image)) {
            throw new UnexpectedTokenException(
                $token1,
                $this->tokenizer->getSourceFile()
            );
        }

        $token->image = $token->image . $token1->image;
        $token->endLine = $token1->endLine;
        $token->endColumn = $token1->endColumn;

        BUILD_LITERAL:

        $literal = $this->builder->buildAstLiteral($token->image);
        $literal->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );

        return $literal;
    }

    /**
     * Parses the class expr syntax supported since PHP 5.4.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @since 2.3
     */
    protected function parsePostfixIdentifier()
    {
        switch ($this->tokenizer->peek()) {
            case Tokens::T_CURLY_BRACE_OPEN:
                $node = $this->parseCompoundExpression();
                break;
            default:
                $node = parent::parsePostfixIdentifier();
                break;
        }
        return $this->parseOptionalIndexExpression($node);
    }

    /**
     * @return \PDepend\Source\AST\ASTNode
     */
    protected function parseOptionalExpressionForVersion()
    {
        switch ($this->tokenizer->peek()) {
            case Tokens::T_TRAIT_C:
                return $this->parseConstant();
            default:
                return parent::parseOptionalExpressionForVersion();
        }
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\Language\PHP;

use PDepend\Source\AST\AbstractASTCallable;
use PDepend\Source\AST\AbstractASTClassOrInterface;
use PDepend\Source\AST\AbstractASTType;
use PDepend\Source\AST\ASTAllocationExpression;
use PDepend\Source\AST\ASTArguments;
use PDepend\Source\AST\ASTArray;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTDeclareStatement;
use PDepend\Source\AST\ASTExpression;
use PDepend\Source\AST\ASTIndexExpression;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\AST\ASTNode;
use PDepend\Source\AST\ASTStatement;
use PDepend\Source\AST\ASTSwitchStatement;
use PDepend\Source\AST\ASTTrait;
use PDepend\Source\AST\ASTValue;
use PDepend\Source\AST\State;
use PDepend\Source\Builder\Builder;
use PDepend\Source\Parser\InvalidStateException;
use PDepend\Source\Parser\MissingValueException;
use PDepend\Source\Parser\NoActiveScopeException;
use PDepend\Source\Parser\TokenStreamEndException;
use PDepend\Source\Parser\UnexpectedTokenException;
use PDepend\Source\Tokenizer\Token;
use PDepend\Source\Tokenizer\Tokenizer;
use PDepend\Source\Tokenizer\Tokens;
use PDepend\Util\Cache\CacheDriver;
use PDepend\Util\Log;
use PDepend\Util\Type;

/**
 * The php source parser.
 *
 * With the default settings the parser includes annotations, better known as
 * doc comment tags, in the generated result. This means it extracts the type
 * information of @var tags for properties, and types in @return + @throws tags
 * of functions and methods. The current implementation tries to ignore all
 * scalar types from <b>boolean</b> to <b>void</b>. You should disable this
 * feature for project that have more or less invalid doc comments, because it
 * could produce invalid results.
 *
 * <code>
 *   $parser->setIgnoreAnnotations();
 * </code>
 *
 * <b>Note</b>: Due to the fact that it is possible to use the same name for
 * multiple classes and interfaces, and there is no way to determine to which
 * package it belongs, while the parser handles class, interface or method
 * signatures, the parser could/will create a code tree that doesn't reflect the
 * real source structure.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
abstract class AbstractPHPParser
{
    /**
     * Regular expression for inline type definitions in regular comments. This
     * kind of type is supported by IDEs like Netbeans or eclipse.
     */
    const REGEXP_INLINE_TYPE = '(^\s*/\*\s*
                                 @var\s+
                                   \$[a-zA-Z_\x7f-\xff\\\\][a-zA-Z0-9_\x7f-\xff]*\s+
                                   (.*?)
                                \s*\*/\s*$)ix';

    /**
     * Regular expression for types defined in <b>throws</b> annotations of
     * method or function doc comments.
     */
    const REGEXP_THROWS_TYPE = '(\*\s*
                             @throws\s+
                               ([a-zA-Z_\x7f-\xff\\\\][a-zA-Z0-9_\x7f-\xff\\\\]*)
                            )ix';

    /**
     * Regular expression for types defined in annotations like <b>return</b> or
     * <b>var</b> in doc comments of functions and methods.
     */
    const REGEXP_RETURN_TYPE = '(\*\s*
                     @return\s+
                      (array\(\s*
                        (\w+\s*=>\s*)?
                        ([a-zA-Z_\x7f-\xff\\\\][a-zA-Z0-9_\x7f-\xff\|\\\\]*)\s*
                      \)
                      |
                      ([a-zA-Z_\x7f-\xff\\\\][a-zA-Z0-9_\x7f-\xff\|\\\\]*))\s+
                      |
                       ([a-zA-Z_\x7f-\xff\\\\][a-zA-Z0-9_\x7f-\xff\|\\\\]*)\[\]
                    )ix';

    /**
     * Regular expression for types defined in annotations like <b>return</b> or
     * <b>var</b> in doc comments of functions and methods.
     */
    const REGEXP_VAR_TYPE = '(\*\s*
                      @var\s+
                       (array\(\s*
                         (\w+\s*=>\s*)?
                         ([a-zA-Z_\x7f-\xff\\\\][a-zA-Z0-9_\x7f-\xff\|\\\\]*)\s*
                       \)
                       |
                       ([a-zA-Z_\x7f-\xff\\\\][a-zA-Z0-9_\x7f-\xff\|\\\\]*))\s+
                       |
                       ([a-zA-Z_\x7f-\xff\\\\][a-zA-Z0-9_\x7f-\xff\|\\\\]*)\[\]\s+
                       |
                       (array)\(\s*\)\s+
                     )ix';

    /**
     * Internal state flag, that will be set to <b>true</b> when the parser has
     * prefixed a qualified name with the actual namespace.
     *
     * @var boolean
     */
    protected $namespacePrefixReplaced = false;

    /**
     * The name of the last detected namespace.
     *
     * @var string
     */
    private $namespaceName;

    /**
     * Last parsed package tag.
     *
     * @var string
     */
    private $packageName = Builder::DEFAULT_NAMESPACE;

    /**
     * The package defined in the file level comment.
     *
     * @var string
     */
    private $globalPackageName = Builder::DEFAULT_NAMESPACE;

    /**
     * The used data structure builder.
     *
     * @var Builder
     */
    protected $builder;

    /**
     * The currently parsed file instance.
     *
     * @var \PDepend\Source\AST\ASTCompilationUnit
     */
    protected $compilationUnit;

    /**
     * The symbol table used to handle PHP 5.3 use statements.
     *
     * @var \PDepend\Source\Parser\SymbolTable
     */
    protected $useSymbolTable;

    /**
     * The last parsed doc comment or <b>null</b>.
     *
     * @var string
     */
    private $docComment;

    /**
     * Bitfield of last parsed modifiers.
     *
     * @var integer
     */
    private $modifiers = 0;

    /**
     * The actually parsed class or interface instance.
     *
     * @var \PDepend\Source\AST\AbstractASTClassOrInterface
     */
    protected $classOrInterface;

    /**
     * If this property is set to <b>true</b> the parser will ignore all doc
     * comment annotations.
     *
     * @var boolean
     */
    private $ignoreAnnotations = false;

    /**
     * Stack with all active token scopes.
     *
     * @var \PDepend\Source\Tokenizer\TokenStack
     */
    protected $tokenStack;

    /**
     * Used identifier builder instance.
     *
     * @var \PDepend\Util\IdBuilder
     * @since 0.9.12
     */
    private $idBuilder = null;

    /**
     * The maximum valid nesting level allowed.
     *
     * @var   integer
     * @since 0.9.12
     */
    private $maxNestingLevel = 1024;

    /**
     *
     * @var \PDepend\Util\Cache\CacheDriver
     * @since 0.10.0
     */
    protected $cache;

    /*
     * The used code tokenizer.
     *
     * @var \PDepend\Source\Tokenizer\Tokenizer
     */
    protected $tokenizer;

    /**
     * Constructs a new source parser.
     *
     * @param \PDepend\Source\Tokenizer\Tokenizer $tokenizer
     * @param \PDepend\Source\Builder\Builder $builder
     * @param \PDepend\Util\Cache\CacheDriver $cache
     */
    public function __construct(Tokenizer $tokenizer, Builder $builder, CacheDriver $cache)
    {
        $this->tokenizer = $tokenizer;
        $this->builder   = $builder;
        $this->cache     = $cache;

        $this->idBuilder    = new \PDepend\Util\IdBuilder();
        $this->tokenStack     = new \PDepend\Source\Parser\TokenStack();
        $this->useSymbolTable = new \PDepend\Source\Parser\SymbolTable();

        $this->builder->setCache($this->cache);
    }

    /**
     * Sets the ignore annotations flag. This means that the parser will ignore
     * doc comment annotations.
     *
     * @return void
     */
    public function setIgnoreAnnotations()
    {
        $this->ignoreAnnotations = true;
    }

    /**
     * Configures the maximum allowed nesting level.
     *
     * @param integer $maxNestingLevel The maximum allowed nesting level.
     *
     * @return void
     * @since 0.9.12
     */
    public function setMaxNestingLevel($maxNestingLevel)
    {
        $this->maxNestingLevel = $maxNestingLevel;
    }

    /**
     * Returns the maximum allowed nesting/recursion level.
     *
     * @return integer
     * @since 0.9.12
     */
    protected function getMaxNestingLevel()
    {
        return $this->maxNestingLevel;
    }

    /**
     * Parses the contents of the tokenizer and generates a node tree based on
     * the found tokens.
     *
     * @return void
     */
    public function parse()
    {
        $this->compilationUnit = $this->tokenizer->getSourceFile();
        $this->compilationUnit
            ->setCache($this->cache)
            ->setId($this->idBuilder->forFile($this->compilationUnit));

        if ($this->compilationUnit->getFileName() === 'php://stdin') {
            $hash = md5('php://stdin');
        } else {
            $hash = md5_file($this->compilationUnit->getFileName());
        }

        if ($this->cache->restore($this->compilationUnit->getId(), $hash)) {
            return;
        }

        $this->cache->remove($this->compilationUnit->getId());

        $this->setUpEnvironment();

        $this->tokenStack->push();

        Log::debug('Processing file ' . $this->compilationUnit);

        $tokenType = $this->tokenizer->peek();
        while ($tokenType !== Tokenizer::T_EOF) {
            switch ($tokenType) {
                case Tokens::T_COMMENT:
                    $this->consumeToken(Tokens::T_COMMENT);
                    break;
                case Tokens::T_DOC_COMMENT:
                    $comment = $this->consumeToken(Tokens::T_DOC_COMMENT)->image;

                    $this->packageName = $this->parsePackageAnnotation($comment);
                    $this->docComment  = $comment;
                    break;
                case Tokens::T_USE:
                    // Parse a use statement. This method has no return value but it
                    // creates a new entry in the symbol map.
                    $this->parseUseDeclarations();
                    break;
                case Tokens::T_NAMESPACE:
                    $this->parseNamespaceDeclaration();
                    break;
                case Tokens::T_NO_PHP:
                case Tokens::T_OPEN_TAG:
                case Tokens::T_OPEN_TAG_WITH_ECHO:
                    $this->consumeToken($tokenType);
                    $this->reset();
                    break;
                case Tokens::T_CLOSE_TAG:
                    $this->parseNonePhpCode();
                    $this->reset();
                    break;
                default:
                    if (null === $this->parseOptionalStatement()) {
                        // Consume whatever token
                        $this->consumeToken($tokenType);
                    }
                    break;
            }

            $tokenType = $this->tokenizer->peek();
        }

        $this->compilationUnit->setTokens($this->tokenStack->pop());
        $this->cache->store(
            $this->compilationUnit->getId(),
            $this->compilationUnit,
            $hash
        );

        $this->tearDownEnvironment();
    }

    /**
     * Initializes the parser environment.
     *
     * @return void
     * @since 0.9.12
     */
    protected function setUpEnvironment()
    {
        ini_set('xdebug.max_nesting_level', $this->getMaxNestingLevel());

        $this->useSymbolTable->createScope();

        $this->reset();
    }

    /**
     * Restores the parser environment back.
     *
     * @throws NoActiveScopeException
     *
     * @return void
     * @since 0.9.12
     */
    protected function tearDownEnvironment()
    {
        ini_restore('xdebug.max_nesting_level');

        $this->useSymbolTable->destroyScope();
    }

    /**
     * Resets some object properties.
     *
     * @param integer $modifiers Optional default modifiers.
     *
     * @return void
     */
    protected function reset($modifiers = 0)
    {
        $this->packageName = Builder::DEFAULT_NAMESPACE;
        $this->docComment  = null;
        $this->modifiers   = $modifiers;
    }

    /**
     * Tests if the given token type is a reserved keyword in the supported PHP
     * version.
     *
     * @param  $tokenType
     * @return boolean
     * @since 1.1.1
     */
    abstract protected function isKeyword($tokenType);

    /**
     * Parses a valid class or interface name and returns the image of the parsed
     * token.
     *
     * @return string
     * @throws \PDepend\Source\Parser\TokenStreamEndException
     * @throws \PDepend\Source\Parser\UnexpectedTokenException
     */
    protected function parseClassName()
    {
        $type = $this->tokenizer->peek();

        if ($this->isClassName($type)) {
            return $this->consumeToken($type)->image;
        } elseif ($type === Tokenizer::T_EOF) {
            throw new TokenStreamEndException($this->tokenizer);
        }

        $this->throwUnexpectedTokenException();
    }

    /**
     * Will return <b>true</b> if the given <b>$tokenType</b> is a valid class
     * name part.
     *
     * @param integer $tokenType
     * @return boolean
     * @since 0.10.6
     */
    protected function isClassName($tokenType)
    {
        switch ($tokenType) {
            case Tokens::T_NULL:
            case Tokens::T_TRUE:
            case Tokens::T_FALSE:
            case Tokens::T_TRAIT:
            case Tokens::T_YIELD:
            case Tokens::T_STRING:
            case Tokens::T_TRAIT_C:
            case Tokens::T_CALLABLE:
            case Tokens::T_INSTEADOF:
                return true;
        }
        return false;
    }

    /**
     * Parses a function name from the given tokenizer and returns the string
     * literal representing the function name. If no valid token exists in the
     * token stream, this method will throw an exception.
     *
     * @return string
     * @throws \PDepend\Source\Parser\UnexpectedTokenException
     * @throws \PDepend\Source\Parser\TokenStreamEndException
     * @since 0.10.0
     */
    protected function parseFunctionName()
    {
        $tokenType = $this->tokenizer->peek();

        if ($this->isFunctionName($tokenType)) {
            return $this->consumeToken($tokenType)->image;
        } elseif ($tokenType === Tokenizer::T_EOF) {
            throw new TokenStreamEndException($this->tokenizer);
        }

        $this->throwUnexpectedTokenException();
    }

    /**
     * @param integer $tokenType
     * @return boolean
     */
    private function isAllowedName($tokenType)
    {
        switch ($tokenType) {
            case Tokens::T_NULL:
            case Tokens::T_SELF:
            case Tokens::T_TRUE:
            case Tokens::T_FALSE:
            case Tokens::T_TRAIT:
            case Tokens::T_YIELD:
            case Tokens::T_PARENT:
            case Tokens::T_STRING:
            case Tokens::T_TRAIT_C:
            case Tokens::T_CALLABLE:
            case Tokens::T_INSTEADOF:
                return true;
        }
        return false;
    }

    /**
     * @param integer $tokenType
     * @return boolean
     */
    protected function isConstantName($tokenType)
    {
        return $this->isAllowedName($tokenType);
    }

    /**
     * Tests if the give token is a valid function name in the supported PHP
     * version.
     *
     * @param integer $tokenType
     * @return boolean
     * @since 2.3
     */
    protected function isFunctionName($tokenType)
    {
        return $this->isAllowedName($tokenType);
    }

    /**
     * @return string
     * @throws \PDepend\Source\Parser\UnexpectedTokenException
     * @throws \PDepend\Source\Parser\TokenStreamEndException
     */
    protected function parseMethodName()
    {
        $tokenType = $this->tokenizer->peek();

        if ($this->isMethodName($tokenType)) {
            return $this->consumeToken($tokenType)->image;
        } elseif ($tokenType === Tokenizer::T_EOF) {
            throw new TokenStreamEndException($this->tokenizer);
        }

        $this->throwUnexpectedTokenException();
    }

    /**
     * @param integer $tokenType
     * @return bool
     */
    protected function isMethodName($tokenType)
    {
        return $this->isAllowedName($tokenType);
    }

    /**
     * Parses a trait declaration.
     *
     * @return \PDepend\Source\AST\ASTTrait
     * @since 1.0.0
     */
    private function parseTraitDeclaration()
    {
        $this->tokenStack->push();

        $trait = $this->parseTraitSignature();
        $trait = $this->parseTypeBody($trait);
        $trait->setTokens($this->tokenStack->pop());

        $this->reset();

        return $trait;
    }

    /**
     * Parses the signature of a trait.
     *
     * @return \PDepend\Source\AST\ASTTrait
     */
    private function parseTraitSignature()
    {
        $this->consumeToken(Tokens::T_TRAIT);
        $this->consumeComments();

        $qualifiedName = $this->createQualifiedTypeName($this->parseClassName());

        $trait = $this->builder->buildTrait($qualifiedName);
        $trait->setCompilationUnit($this->compilationUnit);
        $trait->setComment($this->docComment);
        $trait->setId($this->idBuilder->forClassOrInterface($trait));
        $trait->setUserDefined();

        return $trait;
    }

    /**
     * Parses the dependencies in a interface signature.
     *
     * @return \PDepend\Source\AST\ASTInterface
     */
    private function parseInterfaceDeclaration()
    {
        $this->tokenStack->push();

        $interface = $this->parseInterfaceSignature();
        $interface = $this->parseTypeBody($interface);
        $interface->setTokens($this->tokenStack->pop());

        $this->reset();

        return $interface;
    }

    /**
     * Parses the signature of an interface and finally returns a configured
     * interface instance.
     *
     * @return \PDepend\Source\AST\ASTInterface
     * @since 0.10.2
     */
    private function parseInterfaceSignature()
    {
        $this->consumeToken(Tokens::T_INTERFACE);
        $this->consumeComments();

        $qualifiedName = $this->createQualifiedTypeName($this->parseClassName());

        $interface = $this->builder->buildInterface($qualifiedName);
        $interface->setCompilationUnit($this->compilationUnit);
        $interface->setComment($this->docComment);
        $interface->setId($this->idBuilder->forClassOrInterface($interface));
        $interface->setUserDefined();

        return $this->parseOptionalExtendsList($interface);
    }

    /**
     * Parses an optional interface list of an interface declaration.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return \PDepend\Source\AST\ASTInterface
     * @since 0.10.2
     */
    private function parseOptionalExtendsList(ASTInterface $interface)
    {
        $this->consumeComments();
        $tokenType = $this->tokenizer->peek();

        if ($tokenType === Tokens::T_EXTENDS) {
            $this->consumeToken(Tokens::T_EXTENDS);
            $this->parseInterfaceList($interface);
        }
        return $interface;
    }

    /**
     * Parses the dependencies in a class signature.
     *
     * @return \PDepend\Source\AST\ASTClass
     */
    protected function parseClassDeclaration()
    {
        $this->tokenStack->push();

        $class = $this->parseClassSignature();
        $class = $this->parseTypeBody($class);
        $class->setTokens($this->tokenStack->pop());

        $this->reset();

        return $class;
    }

    /**
     * Parses the signature of a class.
     *
     * The signature of a class consists of optional class modifiers like, final
     * or abstract, the T_CLASS token, the class name, an optional parent class
     * and an optional list of implemented interfaces.
     *
     * @return \PDepend\Source\AST\ASTClass
     * @since 1.0.0
     */
    protected function parseClassSignature()
    {
        $this->parseClassModifiers();
        $this->consumeToken(Tokens::T_CLASS);
        $this->consumeComments();

        $qualifiedName = $this->createQualifiedTypeName($this->parseClassName());

        $class = $this->builder->buildClass($qualifiedName);
        $class->setCompilationUnit($this->compilationUnit);
        $class->setModifiers($this->modifiers);
        $class->setComment($this->docComment);
        $class->setId($this->idBuilder->forClassOrInterface($class));
        $class->setUserDefined();

        $this->consumeComments();
        $tokenType = $this->tokenizer->peek();

        if ($tokenType === Tokens::T_EXTENDS) {
            $class = $this->parseClassExtends($class);

            $this->consumeComments();
            $tokenType = $this->tokenizer->peek();
        }

        if ($tokenType === Tokens::T_IMPLEMENTS) {
            $this->consumeToken(Tokens::T_IMPLEMENTS);
            $this->parseInterfaceList($class);
        }

        return $class;
    }

    /**
     * This method parses an optional class modifier. Valid class modifiers are
     * <b>final</b> or <b>abstract</b>.
     *
     * @return void
     */
    private function parseClassModifiers()
    {
        $this->consumeComments();
        $tokenType = $this->tokenizer->peek();

        if ($tokenType === Tokens::T_ABSTRACT) {
            $this->consumeToken(Tokens::T_ABSTRACT);
            $this->modifiers |= State::IS_EXPLICIT_ABSTRACT;
        } elseif ($tokenType === Tokens::T_FINAL) {
            $this->consumeToken(Tokens::T_FINAL);
            $this->modifiers |= State::IS_FINAL;
        }

        $this->consumeComments();
    }

    /**
     * Parses a parent class declaration for the given <b>$class</b>.
     *
     * @param \PDepend\Source\AST\ASTClass $class
     * @return \PDepend\Source\AST\ASTClass
     * @since 1.0.0
     */
    protected function parseClassExtends(ASTClass $class)
    {
        $this->consumeToken(Tokens::T_EXTENDS);
        $this->tokenStack->push();

        $class->setParentClassReference(
            $this->setNodePositionsAndReturn(
                $this->builder->buildAstClassReference(
                    $this->parseQualifiedName()
                )
            )
        );

        return $class;
    }

    /**
     * This method parses a list of interface names as used in the <b>extends</b>
     * part of a interface declaration or in the <b>implements</b> part of a
     * class declaration.
     *
     * @param \PDepend\Source\AST\AbstractASTClassOrInterface $abstractType
     * @return void
     */
    protected function parseInterfaceList(AbstractASTClassOrInterface $abstractType)
    {
        while (true) {
            $this->tokenStack->push();

            $abstractType->addInterfaceReference(
                $this->setNodePositionsAndReturn(
                    $this->builder->buildAstClassOrInterfaceReference(
                        $this->parseQualifiedName()
                    )
                )
            );

            $this->consumeComments();
            $tokenType = $this->tokenizer->peek();

            if ($tokenType === Tokens::T_CURLY_BRACE_OPEN) {
                break;
            }
            $this->consumeToken(Tokens::T_COMMA);
        }
    }

    /**
     * Parses a class/interface/trait body.
     *
     * @param \PDepend\Source\AST\AbstractASTType $type
     * @return \PDepend\Source\AST\AbstractASTType
     * @throws \PDepend\Source\Parser\UnexpectedTokenException
     * @throws \PDepend\Source\Parser\TokenStreamEndException
     */
    protected function parseTypeBody(AbstractASTType $type)
    {
        $this->classOrInterface = $type;

        // Consume comments and read opening curly brace
        $this->consumeComments();
        $this->consumeToken(Tokens::T_CURLY_BRACE_OPEN);

        $defaultModifier = State::IS_PUBLIC;
        if ($type instanceof ASTInterface) {
            $defaultModifier |= State::IS_ABSTRACT;
        }
        $this->reset();

        $tokenType = $this->tokenizer->peek();

        while ($tokenType !== Tokenizer::T_EOF) {
            switch ($tokenType) {
                case Tokens::T_ABSTRACT:
                case Tokens::T_PUBLIC:
                case Tokens::T_PRIVATE:
                case Tokens::T_PROTECTED:
                case Tokens::T_STATIC:
                case Tokens::T_FINAL:
                case Tokens::T_FUNCTION:
                case Tokens::T_VARIABLE:
                case Tokens::T_VAR:
                    $methodOrProperty = $this->parseMethodOrFieldDeclaration(
                        $defaultModifier
                    );

                    if ($methodOrProperty instanceof \PDepend\Source\AST\ASTNode) {
                        $type->addChild($methodOrProperty);
                    }

                    $this->reset();
                    break;
                case Tokens::T_CONST:
                    $type->addChild($this->parseConstantDefinition());
                    $this->reset();
                    break;
                case Tokens::T_CURLY_BRACE_CLOSE:
                    $this->consumeToken(Tokens::T_CURLY_BRACE_CLOSE);

                    $this->reset();

                    // Reset context class or interface instance
                    $this->classOrInterface = null;

                    // Stop processing
                    return $type;
                case Tokens::T_COMMENT:
                    $token = $this->consumeToken(Tokens::T_COMMENT);

                    $comment = $this->builder->buildAstComment($token->image);
                    $comment->configureLinesAndColumns(
                        $token->startLine,
                        $token->endLine,
                        $token->startColumn,
                        $token->endColumn
                    );

                    $type->addChild($comment);
                    break;
                case Tokens::T_DOC_COMMENT:
                    $token = $this->consumeToken(Tokens::T_DOC_COMMENT);

                    $comment = $this->builder->buildAstComment($token->image);
                    $comment->configureLinesAndColumns(
                        $token->startLine,
                        $token->endLine,
                        $token->startColumn,
                        $token->endColumn
                    );

                    $type->addChild($comment);

                    $this->docComment = $token->image;
                    break;
                case Tokens::T_USE:
                    $type->addChild($this->parseTraitUseStatement());
                    break;
                default:
                    $this->throwUnexpectedTokenException();
            }

            $tokenType = $this->tokenizer->peek();
        }

        throw new TokenStreamEndException($this->tokenizer);
    }

    /**
     * This method will parse a list of modifiers and a following property or
     * method.
     *
     * @param  integer $modifiers
     * @return \PDepend\Source\AST\ASTMethod|\PDepend\Source\AST\ASTFieldDeclaration
     * @since 0.9.6
     */
    private function parseMethodOrFieldDeclaration($modifiers = 0)
    {
        $this->tokenStack->push();

        $tokenType = $this->tokenizer->peek();
        while ($tokenType !== Tokenizer::T_EOF) {
            switch ($tokenType) {
                case Tokens::T_PRIVATE:
                    $modifiers |= State::IS_PRIVATE;
                    $modifiers = $modifiers & ~State::IS_PUBLIC;
                    break;
                case Tokens::T_PROTECTED:
                    $modifiers |= State::IS_PROTECTED;
                    $modifiers = $modifiers & ~State::IS_PUBLIC;
                    break;
                case Tokens::T_VAR:
                case Tokens::T_PUBLIC:
                    $modifiers |= State::IS_PUBLIC;
                    break;
                case Tokens::T_STATIC:
                    $modifiers |= State::IS_STATIC;
                    break;
                case Tokens::T_ABSTRACT:
                    $modifiers |= State::IS_ABSTRACT;
                    break;
                case Tokens::T_FINAL:
                    $modifiers |= State::IS_FINAL;
                    break;
                case Tokens::T_FUNCTION:
                    $method = $this->parseMethodDeclaration();
                    $method->setModifiers($modifiers);
                    $method->setCompilationUnit($this->compilationUnit);
                    $method->setId($this->idBuilder->forMethod($method));
                    $method->setTokens($this->tokenStack->pop());

                    return $method;
                case Tokens::T_VARIABLE:
                    $declaration = $this->parseFieldDeclaration();
                    $declaration->setModifiers($modifiers);

                    return $declaration;
                default:
                    break 2;
            }

            $this->consumeToken($tokenType);
            $this->consumeComments();

            $tokenType = $this->tokenizer->peek();
        }

        $this->throwUnexpectedTokenException();
    }

    /**
     * This method will parse a class field declaration with all it's variables.
     *
     * <code>
     * // Simple field declaration
     * class Foo {
     *     protected $foo;
     * }
     *
     * // Field declaration with multiple properties
     * class Foo {
     *     protected $foo = 23
     *               $bar = 42,
     *               $baz = null;
     * }
     * </code>
     *
     * @return \PDepend\Source\AST\ASTFieldDeclaration
     * @since 0.9.6
     */
    private function parseFieldDeclaration()
    {
        $declaration = $this->builder->buildAstFieldDeclaration();
        $declaration->setComment($this->docComment);

        $type = $this->parseFieldDeclarationType();
        if ($type !== null) {
            $declaration->addChild($type);
        }

        $this->consumeComments();
        $tokenType = $this->tokenizer->peek();

        while ($tokenType !== Tokenizer::T_EOF) {
            $declaration->addChild($this->parseVariableDeclarator());

            $this->consumeComments();
            $tokenType = $this->tokenizer->peek();

            if ($tokenType !== Tokens::T_COMMA) {
                break;
            }
            $this->consumeToken(Tokens::T_COMMA);

            $this->consumeComments();
            $tokenType = $this->tokenizer->peek();
        }

        $this->setNodePositionsAndReturn($declaration);

        $this->consumeToken(Tokens::T_SEMICOLON);

        return $declaration;
    }

    /**
     * This method parses a simple function or a PHP 5.3 lambda function or
     * closure.
     *
     * @return \PDepend\Source\AST\AbstractASTCallable
     * @since 0.9.5
     */
    private function parseFunctionOrClosureDeclaration()
    {
        $this->tokenStack->push();

        $this->consumeToken(Tokens::T_FUNCTION);
        $this->consumeComments();

        $returnReference = $this->parseOptionalByReference();

        if ($this->isNextTokenFormalParameterList()) {
            $callable = $this->parseClosureDeclaration();
            return $this->setNodePositionsAndReturn($callable);
        } else {
            $callable = $this->parseFunctionDeclaration();
            $this->compilationUnit->addChild($callable);
        }

        $callable->setComment($this->docComment);
        $callable->setTokens($this->tokenStack->pop());
        $this->prepareCallable($callable);

        if ($returnReference) {
            $callable->setReturnsReference();
        }

        $this->reset();

        return $callable;
    }

    /**
     * Parses an optional by reference token. The return value will be
     * <b>true</b> when a reference token was found, otherwise this method will
     * return <b>false</b>.
     *
     * @return boolean
     * @since 0.9.8
     */
    private function parseOptionalByReference()
    {
        if ($this->isNextTokenByReference()) {
            return $this->parseByReference();
        }
        return false;
    }

    /**
     * Tests that the next available token is the returns by reference token.
     *
     * @return boolean
     * @since 0.9.8
     */
    private function isNextTokenByReference()
    {
        return ($this->tokenizer->peek() === Tokens::T_BITWISE_AND);
    }

    /**
     * This method parses a returns by reference token and returns <b>true</b>.
     *
     * @return boolean
     */
    private function parseByReference()
    {
        $this->consumeToken(Tokens::T_BITWISE_AND);
        $this->consumeComments();

        return true;
    }

    /**
     * Tests that the next available token is an opening parenthesis.
     *
     * @return boolean
     * @since 0.9.10
     */
    private function isNextTokenFormalParameterList()
    {
        $this->consumeComments();
        return ($this->tokenizer->peek() === Tokens::T_PARENTHESIS_OPEN);
    }

    /**
     * This method parses a function declaration.
     *
     * @return \PDepend\Source\AST\ASTFunction
     * @since 0.9.5
     */
    private function parseFunctionDeclaration()
    {
        $this->consumeComments();

        // Next token must be the function identifier
        $functionName = $this->parseFunctionName();

        $function = $this->builder->buildFunction($functionName);
        $function->setCompilationUnit($this->compilationUnit);
        $function->setId($this->idBuilder->forFunction($function));

        $this->parseCallableDeclaration($function);

        // First check for an existing namespace
        if ($this->namespaceName !== null) {
            $namespaceName = $this->namespaceName;
        } elseif ($this->packageName !== Builder::DEFAULT_NAMESPACE) {
            $namespaceName = $this->packageName;
        } else {
            $namespaceName = $this->globalPackageName;
        }

        $namespace = $this->builder->buildNamespace($namespaceName);
        $namespace->setPackageAnnotation(null === $this->namespaceName);
        $namespace->addFunction($function);

        // Store function in source file, because we need them during the file's
        // __wakeup() phase for function declarations within another function or
        // method declaration.
        $this->compilationUnit->addChild($function);

        return $function;
    }

    /**
     * This method parses a method declaration.
     *
     * @return \PDepend\Source\AST\ASTMethod
     * @since 0.9.5
     */
    private function parseMethodDeclaration()
    {
        // Read function keyword
        $this->consumeToken(Tokens::T_FUNCTION);
        $this->consumeComments();

        $returnsReference = $this->parseOptionalByReference();

        $methodName = $this->parseMethodName();

        $method = $this->builder->buildMethod($methodName);
        $method->setComment($this->docComment);
        $method->setCompilationUnit($this->compilationUnit);

        $this->classOrInterface->addMethod($method);

        $this->parseCallableDeclaration($method);
        $this->prepareCallable($method);

        if ($returnsReference === true) {
            $method->setReturnsReference();
        }

        return $method;
    }

    /**
     * This method parses a PHP 5.3 closure or lambda function.
     *
     * @return \PDepend\Source\AST\ASTClosure
     * @since 0.9.5
     */
    private function parseClosureDeclaration()
    {
        $this->tokenStack->push();

        if (Tokens::T_FUNCTION === $this->tokenizer->peek()) {
            $this->consumeToken(Tokens::T_FUNCTION);
        }

        $closure = $this->builder->buildAstClosure();
        $closure->setReturnsByReference($this->parseOptionalByReference());
        $closure->addChild($this->parseFormalParameters());
        $closure = $this->parseOptionalBoundVariables($closure);
        $closure = $this->parseCallableDeclarationAddition($closure);
        $closure->addChild($this->parseScope());

        return $this->setNodePositionsAndReturn($closure);
    }

    /**
     * Parses a function or a method and adds it to the parent context node.
     *
     * @param  \PDepend\Source\AST\AbstractASTCallable $callable
     * @return void
     */
    private function parseCallableDeclaration(AbstractASTCallable $callable)
    {
        $callable->addChild($this->parseFormalParameters());
        $callable = $this->parseCallableDeclarationAddition($callable);

        $this->consumeComments();
        if ($this->tokenizer->peek() == Tokens::T_CURLY_BRACE_OPEN) {
            $callable->addChild($this->parseScope());
        } else {
            $this->consumeToken(Tokens::T_SEMICOLON);
        }
    }

    /**
     * Extension for version specific additions.
     *
     * @param \PDepend\Source\AST\AbstractASTCallable $callable
     * @return \PDepend\Source\AST\AbstractASTCallable
     */
    protected function parseCallableDeclarationAddition($callable)
    {
        return $callable;
    }

    /**
     * Parses a trait use statement.
     *
     * @return \PDepend\Source\AST\ASTTraitUseStatement
     * @since 1.0.0
     */
    private function parseTraitUseStatement()
    {
        $this->tokenStack->push();
        $this->consumeToken(Tokens::T_USE);

        $useStatement = $this->builder->buildAstTraitUseStatement();
        $useStatement->addChild($this->parseTraitReference());

        $this->consumeComments();
        while (Tokens::T_COMMA === $this->tokenizer->peek()) {
            $this->consumeToken(Tokens::T_COMMA);
            $useStatement->addChild($this->parseTraitReference());
        }

        return $this->setNodePositionsAndReturn(
            $this->parseOptionalTraitAdaptation($useStatement)
        );
    }

    /**
     * Parses a trait reference instance.
     *
     * @return \PDepend\Source\AST\ASTTraitReference
     * @since 1.0.0
     */
    private function parseTraitReference()
    {
        $this->consumeComments();
        $this->tokenStack->push();

        return $this->setNodePositionsAndReturn(
            $this->builder->buildAstTraitReference(
                $this->parseQualifiedName()
            )
        );
    }

    /**
     * Parses the adaptation list of the given use statement or simply reads
     * the terminating semicolon, when no adaptation list exists.
     *
     * @param \PDepend\Source\AST\ASTTraitUseStatement $useStatement
     * @return \PDepend\Source\AST\ASTTraitUseStatement
     * @since 1.0.0
     */
    private function parseOptionalTraitAdaptation(
        \PDepend\Source\AST\ASTTraitUseStatement $useStatement
    ) {
        $this->consumeComments();
        if (Tokens::T_CURLY_BRACE_OPEN === $this->tokenizer->peek()) {
            $useStatement->addChild($this->parseTraitAdaptation());
        } else {
            $this->consumeToken(Tokens::T_SEMICOLON);
        }
        return $useStatement;
    }

    /**
     * Parses the adaptation expression of a trait use statement.
     *
     * @return \PDepend\Source\AST\ASTTraitAdaptation
     * @since 1.0.0
     */
    private function parseTraitAdaptation()
    {
        $this->tokenStack->push();

        $adaptation = $this->builder->buildAstTraitAdaptation();

        $this->consumeToken(Tokens::T_CURLY_BRACE_OPEN);

        do {
            $this->tokenStack->push();

            $reference = $this->parseTraitMethodReference();
            $this->consumeComments();

            if (Tokens::T_AS === $this->tokenizer->peek()) {
                $stmt = $this->parseTraitAdaptationAliasStatement($reference);
            } else {
                $stmt = $this->parseTraitAdaptationPrecedenceStatement($reference);
            }

            $this->consumeComments();
            $this->consumeToken(Tokens::T_SEMICOLON);

            $adaptation->addChild($this->setNodePositionsAndReturn($stmt));

            $this->consumeComments();
        } while (Tokens::T_CURLY_BRACE_CLOSE !== $this->tokenizer->peek());

        $this->consumeToken(Tokens::T_CURLY_BRACE_CLOSE);

        return $this->setNodePositionsAndReturn($adaptation);
    }

    /**
     * Parses a trait method reference and returns the found reference as an
     * <b>array</b>.
     *
     * The returned array with contain only one element, when the referenced
     * method is specified by the method's name, without the declaring trait.
     * When the method reference contains the declaring trait the returned
     * <b>array</b> will contain two elements. The first element is the plain
     * method name and the second element is an instance of the
     * {@link \PDepend\Source\AST\ASTTraitReference} class that represents the
     * declaring trait.
     *
     * @return array
     * @since 1.0.0
     */
    private function parseTraitMethodReference()
    {
        $this->tokenStack->push();

        $qualifiedName = $this->parseQualifiedName();

        $this->consumeComments();
        if (Tokens::T_DOUBLE_COLON === $this->tokenizer->peek()) {
            $traitReference = $this->setNodePositionsAndReturn(
                $this->builder->buildAstTraitReference($qualifiedName)
            );

            $this->consumeToken(Tokens::T_DOUBLE_COLON);
            $this->consumeComments();

            return array($this->parseMethodName(), $traitReference);
        }
        $this->tokenStack->pop();

        return array($qualifiedName);
    }

    /**
     * Parses a trait adaptation alias statement.
     *
     * @param array $reference Parsed method reference array.
     *
     * @return \PDepend\Source\AST\ASTTraitAdaptationAlias
     * @since 1.0.0
     */
    private function parseTraitAdaptationAliasStatement(array $reference)
    {
        $stmt = $this->builder->buildAstTraitAdaptationAlias($reference[0]);

        if (2 === count($reference)) {
            $stmt->addChild($reference[1]);
        }

        $this->consumeToken(Tokens::T_AS);
        $this->consumeComments();

        switch ($this->tokenizer->peek()) {
            case Tokens::T_PUBLIC:
                $stmt->setNewModifier(State::IS_PUBLIC);
                $this->consumeToken(Tokens::T_PUBLIC);
                $this->consumeComments();
                break;
            case Tokens::T_PROTECTED:
                $stmt->setNewModifier(State::IS_PROTECTED);
                $this->consumeToken(Tokens::T_PROTECTED);
                $this->consumeComments();
                break;
            case Tokens::T_PRIVATE:
                $stmt->setNewModifier(State::IS_PRIVATE);
                $this->consumeToken(Tokens::T_PRIVATE);
                $this->consumeComments();
                break;
        }

        if (Tokens::T_SEMICOLON !== $this->tokenizer->peek()) {
            $stmt->setNewName($this->parseMethodName());
        }
        return $stmt;
    }

    /**
     * Parses a trait adaptation precedence statement.
     *
     * @param  array $reference Parsed method reference array.
     * @return \PDepend\Source\AST\ASTTraitAdaptationPrecedence
     * @throws \PDepend\Source\Parser\InvalidStateException
     * @since 1.0.0
     */
    private function parseTraitAdaptationPrecedenceStatement(array $reference)
    {
        if (count($reference) < 2) {
            throw new InvalidStateException(
                $this->tokenizer->next()->startLine,
                $this->compilationUnit->getFileName(),
                'Expecting full qualified trait method name.'
            );
        }

        $stmt = $this->builder->buildAstTraitAdaptationPrecedence($reference[0]);
        $stmt->addChild($reference[1]);

        $this->consumeToken(Tokens::T_INSTEADOF);
        $this->consumeComments();

        $stmt->addChild($this->parseTraitReference());

        $this->consumeComments();
        while (Tokens::T_COMMA === $this->tokenizer->peek()) {
            $this->consumeToken(Tokens::T_COMMA);
            $stmt->addChild($this->parseTraitReference());
            $this->consumeComments();
        }

        return $stmt;
    }

    /**
     * Parses an allocation expression.
     *
     * <code>
     * function foo()
     * {
     * //  -------------
     *     new bar\Baz();
     * //  -------------
     *
     * //  ---------
     *     new Foo();
     * //  ---------
     * }
     * </code>
     *
     * @return \PDepend\Source\AST\ASTAllocationExpression
     * @since 0.9.6
     */
    private function parseAllocationExpression()
    {
        $this->tokenStack->push();

        $token = $this->consumeToken(Tokens::T_NEW);

        $allocation = $this->builder->buildAstAllocationExpression($token->image);
        $allocation = $this->parseAllocationExpressionTypeReference($allocation);

        if ($this->isNextTokenArguments()) {
            $allocation->addChild($this->parseArguments());
        }
        return $this->setNodePositionsAndReturn($allocation);
    }

    /**
     * Parse the type reference used in an allocation expression.
     *
     * @param \PDepend\Source\AST\ASTAllocationExpression $allocation
     * @return \PDepend\Source\AST\ASTNode
     * @since 2.3
     */
    protected function parseAllocationExpressionTypeReference(ASTAllocationExpression $allocation)
    {
        return $this->parseExpressionTypeReference($allocation, true);
    }

    /**
     * Parses a eval-expression node.
     *
     * @return \PDepend\Source\AST\ASTEvalExpression
     * @since 0.9.12
     */
    private function parseEvalExpression()
    {
        $this->tokenStack->push();
        $token = $this->consumeToken(Tokens::T_EVAL);

        $expr = $this->builder->buildAstEvalExpression($token->image);
        $expr->addChild($this->parseParenthesisExpression());

        return $this->setNodePositionsAndReturn($expr);
    }

    /**
     * This method parses an exit-expression.
     *
     * @return \PDepend\Source\AST\ASTExitExpression
     * @since 0.9.12
     */
    private function parseExitExpression()
    {
        $this->tokenStack->push();
        $token = $this->consumeToken(Tokens::T_EXIT);

        $expr = $this->builder->buildAstExitExpression($token->image);

        $this->consumeComments();
        if ($this->tokenizer->peek() === Tokens::T_PARENTHESIS_OPEN) {
            $expr->addChild($this->parseParenthesisExpression());
        }
        return $this->setNodePositionsAndReturn($expr);
    }

    /**
     * Parses a clone-expression node.
     *
     * @return \PDepend\Source\AST\ASTCloneExpression
     * @since 0.9.12
     */
    private function parseCloneExpression()
    {
        $this->tokenStack->push();
        $token = $this->consumeToken(Tokens::T_CLONE);

        $expr = $this->builder->buildAstCloneExpression($token->image);
        $expr->addChild($this->parseExpression());

        return $this->setNodePositionsAndReturn($expr);
    }

    /**
     * This method parses a single list-statement node.
     *
     * @return \PDepend\Source\AST\ASTListExpression
     * @since 0.9.12
     */
    private function parseListExpression()
    {
        $this->tokenStack->push();

        $token = $this->consumeToken(Tokens::T_LIST);
        $this->consumeComments();

        $list = $this->builder->buildAstListExpression($token->image);

        $this->consumeToken(Tokens::T_PARENTHESIS_OPEN);
        $this->consumeComments();

        while (($tokenType = $this->tokenizer->peek()) !== Tokenizer::T_EOF) {
            // The variable is optional:
            //   list(, , , , $something) = ...;
            // is valid.
            switch ($tokenType) {
                case Tokens::T_COMMA:
                    $this->consumeToken(Tokens::T_COMMA);
                    $this->consumeComments();
                    break;
                case Tokens::T_PARENTHESIS_CLOSE:
                    break 2;
                case Tokens::T_LIST:
                    $list->addChild($this->parseListExpression());
                    $this->consumeComments();
                    break;
                default:
                    $list->addChild($this->parseVariableOrConstantOrPrimaryPrefix());
                    $this->consumeComments();
                    break;
            }
        }

        $this->consumeToken(Tokens::T_PARENTHESIS_CLOSE);

        return $this->setNodePositionsAndReturn($list);
    }

    /**
     * Parses a include-expression node.
     *
     * @return \PDepend\Source\AST\ASTIncludeExpression
     * @since 0.9.12
     */
    private function parseIncludeExpression()
    {
        $expr = $this->builder->buildAstIncludeExpression();

        return $this->parseRequireOrIncludeExpression($expr, Tokens::T_INCLUDE);
    }

    /**
     * Parses a include_once-expression node.
     *
     * @return \PDepend\Source\AST\ASTIncludeExpression
     * @since 0.9.12
     */
    private function parseIncludeOnceExpression()
    {
        $expr = $this->builder->buildAstIncludeExpression();
        $expr->setOnce();

        return $this->parseRequireOrIncludeExpression($expr, Tokens::T_INCLUDE_ONCE);
    }

    /**
     * Parses a require-expression node.
     *
     * @return \PDepend\Source\AST\ASTRequireExpression
     * @since 0.9.12
     */
    private function parseRequireExpression()
    {
        $expr = $this->builder->buildAstRequireExpression();

        return $this->parseRequireOrIncludeExpression($expr, Tokens::T_REQUIRE);
    }

    /**
     * Parses a require_once-expression node.
     *
     * @return \PDepend\Source\AST\ASTRequireExpression
     * @since 0.9.12
     */
    private function parseRequireOnceExpression()
    {
        $expr = $this->builder->buildAstRequireExpression();
        $expr->setOnce();

        return $this->parseRequireOrIncludeExpression($expr, Tokens::T_REQUIRE_ONCE);
    }

    /**
     * Parses a <b>require_once</b>-, <b>require</b>-, <b>include_once</b>- or
     * <b>include</b>-expression node.
     *
     * @param  \PDepend\Source\AST\ASTExpression $expr
     * @param  integer                           $type
     * @return \PDepend\Source\AST\ASTExpression
     * @since 0.9.12
     */
    private function parseRequireOrIncludeExpression(ASTExpression $expr, $type)
    {
        $this->tokenStack->push();

        $this->consumeToken($type);
        $this->consumeComments();

        if ($this->tokenizer->peek() === Tokens::T_PARENTHESIS_OPEN) {
            $this->consumeToken(Tokens::T_PARENTHESIS_OPEN);
            $expr->addChild($this->parseOptionalExpression());
            $this->consumeToken(Tokens::T_PARENTHESIS_CLOSE);
        } else {
            $expr->addChild($this->parseOptionalExpression());
        }

        return $this->setNodePositionsAndReturn($expr);
    }

    /**
     * Parses a cast-expression node.
     *
     * @return \PDepend\Source\AST\ASTCaseExpression
     * @since 0.10.0
     */
    protected function parseCastExpression()
    {
        $token = $this->consumeToken($this->tokenizer->peek());

        $expr = $this->builder->buildAstCastExpression($token->image);
        $expr->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );

        return $expr;
    }

    /**
     * This method will parse an increment-expression. Depending on the previous
     * node this can be a {@link \PDepend\Source\AST\ASTPostIncrementExpression} or
     * {@link \PDepend\Source\AST\ASTPostfixExpression}.
     *
     * @param  array &$expressions List of previous parsed expression nodes.
     * @return \PDepend\Source\AST\ASTExpression
     * @since 0.10.0
     */
    private function parseIncrementExpression(array &$expressions)
    {
        if ($this->isReadWriteVariable(end($expressions))) {
            return $this->parsePostIncrementExpression(array_pop($expressions));
        }
        return $this->parsePreIncrementExpression();
    }

    /**
     * Parses a post increment-expression and adds the given child to that node.
     *
     * @param \PDepend\Source\AST\ASTNode $child The child expression node.
     *
     * @return \PDepend\Source\AST\ASTPostfixExpression
     * @since 0.10.0
     */
    private function parsePostIncrementExpression(ASTNode $child)
    {
        $token = $this->consumeToken(Tokens::T_INC);

        $expr = $this->builder->buildAstPostfixExpression($token->image);
        $expr->addChild($child);
        $expr->configureLinesAndColumns(
            $child->getStartLine(),
            $token->endLine,
            $child->getStartColumn(),
            $token->endColumn
        );

        return $expr;
    }

    /**
     * Parses a pre increment-expression and adds the given child to that node.
     *
     * @return \PDepend\Source\AST\ASTPreIncrementExpression
     * @since 0.10.0
     */
    private function parsePreIncrementExpression()
    {
        $token = $this->consumeToken(Tokens::T_INC);

        $expr = $this->builder->buildAstPreIncrementExpression();
        $expr->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );

        return $expr;
    }

    /**
     * This method will parse an decrement-expression. Depending on the previous
     * node this can be a {@link \PDepend\Source\AST\ASTPostDecrementExpression} or
     * {@link \PDepend\Source\AST\ASTPostfixExpression}.
     *
     * @param array &$expressions List of previous parsed expression nodes.
     *
     * @return \PDepend\Source\AST\ASTExpression
     * @since 0.10.0
     */
    private function parseDecrementExpression(array &$expressions)
    {
        if ($this->isReadWriteVariable(end($expressions))) {
            return $this->parsePostDecrementExpression(array_pop($expressions));
        }
        return $this->parsePreDecrementExpression();
    }

    /**
     * Parses a post decrement-expression and adds the given child to that node.
     *
     * @param \PDepend\Source\AST\ASTNode $child The child expression node.
     *
     * @return \PDepend\Source\AST\ASTPostfixExpression
     * @since 0.10.0
     */
    private function parsePostDecrementExpression(ASTNode $child)
    {
        $token = $this->consumeToken(Tokens::T_DEC);

        $expr = $this->builder->buildAstPostfixExpression($token->image);
        $expr->addChild($child);
        $expr->configureLinesAndColumns(
            $child->getStartLine(),
            $token->endLine,
            $child->getStartColumn(),
            $token->endColumn
        );

        return $expr;
    }

    /**
     * Parses a pre decrement-expression and adds the given child to that node.
     *
     * @return \PDepend\Source\AST\ASTPreDecrementExpression
     * @since 0.10.0
     */
    private function parsePreDecrementExpression()
    {
        $token = $this->consumeToken(Tokens::T_DEC);

        $expr = $this->builder->buildAstPreDecrementExpression();
        $expr->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );

        return $expr;
    }

    /**
     * Parses one or more optional php <b>array</b> or <b>string</b> expressions.
     *
     * <code>
     * ---------
     * $array[0];
     * ---------
     *
     * ----------------
     * $array[1]['foo'];
     * ----------------
     *
     * ----------------
     * $string{1}[0]{0};
     * ----------------
     * </code>
     *
     * @param \PDepend\Source\AST\ASTNode $node The parent/context node instance.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @since 0.9.12
     */
    protected function parseOptionalIndexExpression(ASTNode $node)
    {
        $this->consumeComments();

        switch ($this->tokenizer->peek()) {
            case Tokens::T_CURLY_BRACE_OPEN:
                return $this->parseStringIndexExpression($node);
            case Tokens::T_SQUARED_BRACKET_OPEN:
                return $this->parseArrayIndexExpression($node);
        }

        return $node;
    }

    /**
     * Parses an index expression as it is valid to access elements in a php
     * string or array.
     *
     * @param \PDepend\Source\AST\ASTNode       $node  The context source node.
     * @param \PDepend\Source\AST\ASTExpression $expr  The concrete index expression.
     * @param integer                           $open  The open token type.
     * @param integer                           $close The close token type.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @since 0.9.12
     */
    private function parseIndexExpression(
        \PDepend\Source\AST\ASTNode $node,
        \PDepend\Source\AST\ASTExpression $expr,
        $open,
        $close
    ) {
        $this->consumeToken($open);

        if (($child = $this->parseOptionalExpression()) != null) {
            $expr->addChild($child);
        }

        $token = $this->consumeToken($close);

        $expr->configureLinesAndColumns(
            $node->getStartLine(),
            $token->endLine,
            $node->getStartColumn(),
            $token->endColumn
        );

        return $this->parseOptionalIndexExpression($expr);
    }

    /**
     * Parses a mandatory array index expression.
     *
     * <code>
     * //    ---
     * $array[0];
     * //    ---
     * </code>
     *
     * @param \PDepend\Source\AST\ASTNode $node The context source node.
     *
     * @return \PDepend\Source\AST\ASTArrayIndexExpression
     * @since 0.9.12
     */
    private function parseArrayIndexExpression(ASTNode $node)
    {
        $expr = $this->builder->buildAstArrayIndexExpression();
        $expr->addChild($node);

        return $this->parseIndexExpression(
            $node,
            $expr,
            Tokens::T_SQUARED_BRACKET_OPEN,
            Tokens::T_SQUARED_BRACKET_CLOSE
        );
    }

    /**
     * Parses a mandatory array index expression.
     *
     * <code>
     * //     ---
     * $string{0};
     * //     ---
     * </code>
     *
     * @param \PDepend\Source\AST\ASTNode $node The context source node.
     *
     * @return \PDepend\Source\AST\ASTStringIndexExpression
     * @since 0.9.12
     */
    private function parseStringIndexExpression(ASTNode $node)
    {
        $expr = $this->builder->buildAstStringIndexExpression();
        $expr->addChild($node);

        return $this->parseIndexExpression(
            $node,
            $expr,
            Tokens::T_CURLY_BRACE_OPEN,
            Tokens::T_CURLY_BRACE_CLOSE
        );
    }

    /**
     * This method checks if the next available token starts an arguments node.
     *
     * @return boolean
     * @since 0.9.8
     */
    protected function isNextTokenArguments()
    {
        $this->consumeComments();
        return $this->tokenizer->peek() === Tokens::T_PARENTHESIS_OPEN;
    }

    /**
     * This method configures the given node with its start and end positions.
     *
     * @param \PDepend\Source\AST\ASTNode $node
     * @param array &$tokens
     * @return \PDepend\Source\AST\ASTNode
     * @since 0.9.8
     */
    protected function setNodePositionsAndReturn(ASTNode $node, array &$tokens = null)
    {
        $tokens = $this->stripTrailingComments($this->tokenStack->pop());

        $end   = $tokens[count($tokens) - 1];
        $start = $tokens[0];

        $node->configureLinesAndColumns(
            $start->startLine,
            $end->endLine,
            $start->startColumn,
            $end->endColumn
        );

        return $node;
    }

    /**
     * Strips all trailing comments from the given token stream.
     *
     * @param  Token[] $tokens Original token stream.
     * @return Token[]
     * @since 1.0.0
     */
    private function stripTrailingComments(array $tokens)
    {
        $comments = array(Tokens::T_COMMENT, Tokens::T_DOC_COMMENT);

        while (count($tokens) > 1 && in_array(end($tokens)->type, $comments)) {
            array_pop($tokens);
        }
        return $tokens;
    }

    /**
     * This method parse an instance of expression with its associated class or
     * interface reference.
     *
     * <code>
     *          ----------------
     * ($object instanceof Clazz);
     *          ----------------
     *
     *          ------------------------
     * ($object instanceof Clazz::$clazz);
     *          ------------------------
     *
     *          -----------------
     * ($object instanceof $clazz);
     *          -----------------
     *
     *          -----------------------
     * ($object instanceof $clazz->type);
     *          -----------------------
     *
     *          -----------------------------
     * ($object instanceof static|self|parent);
     *          -----------------------------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTInstanceOfExpression
     * @since 0.9.6
     */
    private function parseInstanceOfExpression()
    {
        // Consume the "instanceof" keyword and strip comments
        $token = $this->consumeToken(Tokens::T_INSTANCEOF);

        return $this->parseExpressionTypeReference(
            $this->builder->buildAstInstanceOfExpression($token->image),
            false
        );
    }

    /**
     * Parses an isset-expression node.
     *
     * <code>
     * //  -----------
     * if (isset($foo)) {
     * //  -----------
     * }
     *
     * //  -----------------------
     * if (isset($foo, $bar, $baz)) {
     * //  -----------------------
     * }
     * </code>
     *
     * @return \PDepend\Source\AST\ASTIssetExpression
     * @since 0.9.12
     */
    private function parseIssetExpression()
    {
        $startToken = $this->consumeToken(Tokens::T_ISSET);
        $this->consumeComments();
        $this->consumeToken(Tokens::T_PARENTHESIS_OPEN);

        $expr = $this->builder->buildAstIssetExpression();
        $expr = $this->parseVariableList($expr);

        $stopToken = $this->consumeToken(Tokens::T_PARENTHESIS_CLOSE);

        $expr->configureLinesAndColumns(
            $startToken->startLine,
            $stopToken->endLine,
            $startToken->startColumn,
            $stopToken->endColumn
        );

        return $expr;
    }

    /**
     * This method parses a type identifier as it is used in expression nodes
     * like {@link \PDepend\Source\AST\ASTInstanceOfExpression} or an object
     * allocation node like {@link \PDepend\Source\AST\ASTAllocationExpression}.
     *
     * @param \PDepend\Source\AST\ASTNode $expr
     * @param boolean $classRef
     * @return \PDepend\Source\AST\ASTNode
     */
    protected function parseExpressionTypeReference(ASTNode $expr, $classRef)
    {
        // Peek next token and look for a static type identifier
        $this->consumeComments();
        $tokenType = $this->tokenizer->peek();

        switch ($tokenType) {
            case Tokens::T_DOLLAR:
            case Tokens::T_VARIABLE:
                // TODO: Parse variable or Member Primary Prefix + Property Postfix
                $ref = $this->parseVariableOrFunctionPostfixOrMemberPrimaryPrefix();
                break;
            case Tokens::T_SELF:
                $ref = $this->parseSelfReference($this->consumeToken(Tokens::T_SELF));
                break;
            case Tokens::T_PARENT:
                $ref = $this->parseParentReference($this->consumeToken(Tokens::T_PARENT));
                break;
            case Tokens::T_STATIC:
                $ref = $this->parseStaticReference($this->consumeToken(Tokens::T_STATIC));
                break;
            default:
                $ref = $this->parseClassOrInterfaceReference($classRef);
                break;
        }

        $expr->addChild(
            $this->parseOptionalMemberPrimaryPrefix(
                $this->parseOptionalStaticMemberPrimaryPrefix($ref)
            )
        );

        return $expr;
    }

    /**
     * This method parses a conditional-expression.
     *
     * <code>
     *         --------------
     * $foo = ($bar ? 42 : 23);
     *         --------------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTConditionalExpression
     * @since 0.9.8
     */
    protected function parseConditionalExpression()
    {
        $this->tokenStack->push();
        $this->consumeToken(Tokens::T_QUESTION_MARK);

        $expr = $this->builder->buildAstConditionalExpression();
        if (($child = $this->parseOptionalExpression()) != null) {
            $expr->addChild($child);
        }

        $this->consumeToken(Tokens::T_COLON);

        $expr->addChild($this->parseExpression());

        return $this->setNodePositionsAndReturn($expr);
    }

    /**
     * This method parses a shift left expression node.
     *
     * @return \PDepend\Source\AST\ASTShiftLeftExpression
     * @since 1.0.1
     */
    protected function parseShiftLeftExpression()
    {
        $token = $this->consumeToken(Tokens::T_SL);

        $expr = $this->builder->buildAstShiftLeftExpression();
        $expr->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );
        return $expr;
    }

    /**
     * This method parses a shift right expression node.
     *
     * @return \PDepend\Source\AST\ASTShiftRightExpression
     * @since 1.0.1
     */
    protected function parseShiftRightExpression()
    {
        $token = $this->consumeToken(Tokens::T_SR);

        $expr = $this->builder->buildAstShiftRightExpression();
        $expr->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );
        return $expr;
    }

    /**
     * This method parses a boolean and-expression.
     *
     * @return \PDepend\Source\AST\ASTBooleanAndExpression
     * @since 0.9.8
     */
    protected function parseBooleanAndExpression()
    {
        $token = $this->consumeToken(Tokens::T_BOOLEAN_AND);

        $expr = $this->builder->buildAstBooleanAndExpression();
        $expr->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );
        return $expr;
    }

    /**
     * This method parses a boolean or-expression.
     *
     * @return \PDepend\Source\AST\ASTBooleanOrExpression
     * @since 0.9.8
     */
    protected function parseBooleanOrExpression()
    {
        $token = $this->consumeToken(Tokens::T_BOOLEAN_OR);

        $expr = $this->builder->buildAstBooleanOrExpression();
        $expr->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );
        return $expr;
    }

    /**
     * This method parses a logical <b>and</b>-expression.
     *
     * @return \PDepend\Source\AST\ASTLogicalAndExpression
     * @since 0.9.8
     */
    protected function parseLogicalAndExpression()
    {
        $token = $this->consumeToken(Tokens::T_LOGICAL_AND);

        $expr = $this->builder->buildAstLogicalAndExpression();
        $expr->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );
        return $expr;
    }

    /**
     * This method parses a logical <b>or</b>-expression.
     *
     * @return \PDepend\Source\AST\ASTLogicalOrExpression
     * @since 0.9.8
     */
    protected function parseLogicalOrExpression()
    {
        $token = $this->consumeToken(Tokens::T_LOGICAL_OR);

        $expr = $this->builder->buildAstLogicalOrExpression();
        $expr->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );
        return $expr;
    }

    /**
     * This method parses a logical <b>xor</b>-expression.
     *
     * @return \PDepend\Source\AST\ASTLogicalXorExpression
     * @since 0.9.8
     */
    protected function parseLogicalXorExpression()
    {
        $token = $this->consumeToken(Tokens::T_LOGICAL_XOR);

        $expr = $this->builder->buildAstLogicalXorExpression();
        $expr->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );
        return $expr;
    }

    /**
     * Parses a class or interface reference node.
     *
     * @param boolean $classReference Force a class reference.
     *
     * @return \PDepend\Source\AST\ASTClassOrInterfaceReference
     * @since 0.9.8
     */
    private function parseClassOrInterfaceReference($classReference)
    {
        $this->tokenStack->push();

        if ($classReference === true) {
            return $this->setNodePositionsAndReturn(
                $this->builder->buildAstClassReference(
                    $this->parseQualifiedName()
                )
            );
        }
        return $this->setNodePositionsAndReturn(
            $this->builder->buildAstClassOrInterfaceReference(
                $this->parseQualifiedName()
            )
        );
    }

    /**
     * This method parses a brace expression and adds all parsed node instances
     * to the given {@link \PDepend\Source\AST\ASTNode} object. Finally it returns
     * the prepared input node.
     *
     * A brace expression can be a compound:
     *
     * <code>
     * $this->{$foo ? 'foo' : 'bar'}();
     * </code>
     *
     * or a parameter list:
     *
     * <code>
     * $this->foo($bar, $baz);
     * </code>
     *
     * or an array index:
     *
     * <code>
     * $foo[$bar];
     * </code>
     *
     * @param  \PDepend\Source\AST\ASTNode     $node
     * @param  \PDepend\Source\Tokenizer\Token $start
     * @param  integer                         $closeToken
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\TokenStreamEndException
     * @since 0.9.6
     */
    private function parseBraceExpression(
        ASTNode $node,
        Token $start,
        $closeToken
    ) {
        if (is_object($expr = $this->parseOptionalExpression())) {
            $node->addChild($expr);
        }

        $end = $this->consumeToken($closeToken);

        $node->configureLinesAndColumns(
            $start->startLine,
            $end->endLine,
            $start->startColumn,
            $end->endColumn
        );
        return $node;
    }

    /**
     * Parses the body of the given statement instance and adds all parsed nodes
     * to that statement.
     *
     * @param \PDepend\Source\AST\ASTStatement $stmt The owning statement.
     *
     * @return \PDepend\Source\AST\ASTStatement
     * @since 0.9.12
     */
    private function parseStatementBody(\PDepend\Source\AST\ASTStatement $stmt)
    {
        $this->consumeComments();
        $tokenType = $this->tokenizer->peek();

        if ($tokenType === Tokens::T_CURLY_BRACE_OPEN) {
            $stmt->addChild($this->parseRegularScope());
        } elseif ($tokenType === Tokens::T_COLON) {
            $stmt->addChild($this->parseAlternativeScope());
        } else {
            $stmt->addChild($this->parseStatement());
        }
        return $stmt;
    }

    /**
     * Parse a scope enclosed by curly braces.
     *
     * @return \PDepend\Source\AST\ASTScope
     * @since 0.9.12
     */
    private function parseRegularScope()
    {
        $this->tokenStack->push();

        $this->consumeComments();
        $this->consumeToken(Tokens::T_CURLY_BRACE_OPEN);

        $scope = $this->parseScopeStatements();

        $this->consumeToken(Tokens::T_CURLY_BRACE_CLOSE);
        return $this->setNodePositionsAndReturn($scope);
    }

    /**
     * Parses the scope of a statement that is surrounded with PHP's alternative
     * syntax for statements.
     *
     * @return \PDepend\Source\AST\ASTScopeStatement
     * @since 0.10.0
     */
    private function parseAlternativeScope()
    {
        $this->tokenStack->push();
        $this->consumeToken(Tokens::T_COLON);

        $scope = $this->parseScopeStatements();

        $this->parseOptionalAlternativeScopeTermination();
        return $this->setNodePositionsAndReturn($scope);
    }

    /**
     * Parses all statements that exist in a scope an adds them to a scope
     * instance.
     *
     * @return \PDepend\Source\AST\ASTScopeStatement
     * @since 0.10.0
     */
    private function parseScopeStatements()
    {
        $scope = $this->builder->buildAstScopeStatement();
        while (($child = $this->parseOptionalStatement()) != null) {
            if ($child instanceof \PDepend\Source\AST\ASTNode) {
                $scope->addChild($child);
            }
        }
        return $scope;
    }

    /**
     * Parses the termination of a scope statement that uses PHP's laternative
     * syntax format.
     *
     * @return void
     * @since 0.10.0
     */
    private function parseOptionalAlternativeScopeTermination()
    {
        $tokenType = $this->tokenizer->peek();
        if ($this->isAlternativeScopeTermination($tokenType)) {
            $this->parseAlternativeScopeTermination($tokenType);
        }
    }


    /**
     * This method returns <b>true</b> when the given token identifier represents
     * the end token of a alternative scope termination symbol. Otherwise this
     * method will return <b>false</b>.
     *
     * @param integer $tokenType The token type identifier.
     *
     * @return boolean
     * @since 0.10.0
     */
    private function isAlternativeScopeTermination($tokenType)
    {
        return in_array(
            $tokenType,
            array(
                Tokens::T_ENDDECLARE,
                Tokens::T_ENDFOR,
                Tokens::T_ENDFOREACH,
                Tokens::T_ENDIF,
                Tokens::T_ENDSWITCH,
                Tokens::T_ENDWHILE
            )
        );
    }

    /**
     * Parses a series of tokens that represent an alternative scope termination.
     *
     * @param integer $tokenType The token type identifier.
     *
     * @return void
     * @since 0.10.0
     */
    private function parseAlternativeScopeTermination($tokenType)
    {
        $this->consumeToken($tokenType);
        $this->consumeComments();

        if ($this->tokenizer->peek() === Tokens::T_SEMICOLON) {
            $this->consumeToken(Tokens::T_SEMICOLON);
        } else {
            $this->parseNonePhpCode();
        }
    }

    /**
     * This method parses multiple expressions and adds them as children to the
     * given <b>$exprList</b> node.
     *
     * @param \PDepend\Source\AST\ASTNode
     * @return \PDepend\Source\AST\ASTNode
     * @since 1.0.0
     */
    private function parseExpressionList(ASTNode $exprList)
    {
        $this->consumeComments();
        while ($expr = $this->parseOptionalExpression()) {
            $exprList->addChild($expr);

            $this->consumeComments();
            if (Tokens::T_COMMA === $this->tokenizer->peek()) {
                $this->consumeToken(Tokens::T_COMMA);
                $this->consumeComments();
            } else {
                break;
            }
        }

        return $exprList;
    }

    /**
     * This method parses an expression node and returns it. When no expression
     * was found this method will throw an InvalidStateException.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\ParserException
     * @since 1.0.1
     */
    private function parseExpression()
    {
        if (null === ($expr = $this->parseOptionalExpression())) {
            $token = $this->consumeToken($this->tokenizer->peek());

            throw new InvalidStateException(
                $token->startLine,
                $this->compilationUnit->getFileName(),
                'Mandatory expression expected.'
            );
        }
        return $expr;
    }

    /**
     * This method optionally parses an expression node and returns it. When no
     * expression was found this method will return <b>null</b>.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\ParserException
     * @since 0.9.6
     */
    protected function parseOptionalExpression()
    {
        $expressions = array();

        while (($tokenType = $this->tokenizer->peek()) != Tokenizer::T_EOF) {
            $expr = null;

            switch ($tokenType) {
                case Tokens::T_COMMA:
                case Tokens::T_AS:
                case Tokens::T_BREAK:
                case Tokens::T_CLOSE_TAG:
                case Tokens::T_COLON:
                case Tokens::T_CONTINUE:
                case Tokens::T_CURLY_BRACE_CLOSE:
                case Tokens::T_DECLARE:
                case Tokens::T_DO:
                case Tokens::T_DOUBLE_ARROW:
                case Tokens::T_ECHO:
                case Tokens::T_END_HEREDOC:
                case Tokens::T_ENDFOREACH:
                case Tokens::T_FOR:
                case Tokens::T_FOREACH:
                case Tokens::T_GLOBAL:
                case Tokens::T_GOTO:
                case Tokens::T_IF:
                case Tokens::T_PARENTHESIS_CLOSE:
                case Tokens::T_RETURN:
                case Tokens::T_SEMICOLON:
                case Tokens::T_SQUARED_BRACKET_CLOSE:
                case Tokens::T_SWITCH:
                case Tokens::T_THROW:
                case Tokens::T_TRY:
                case Tokens::T_UNSET:
                case Tokens::T_WHILE:
                    break 2;
                case Tokens::T_SELF:
                case Tokens::T_STRING:
                case Tokens::T_PARENT:
                case Tokens::T_STATIC:
                case Tokens::T_DOLLAR:
                case Tokens::T_VARIABLE:
                case Tokens::T_BACKSLASH:
                case Tokens::T_NAMESPACE:
                    $expressions[] = $this->parseVariableOrConstantOrPrimaryPrefix();
                    break;
                case ($this->isArrayStartDelimiter()):
                    $expressions[] = $this->doParseArray();
                    break;
                case Tokens::T_NULL:
                case Tokens::T_TRUE:
                case Tokens::T_FALSE:
                case Tokens::T_LNUMBER:
                case Tokens::T_DNUMBER:
                case Tokens::T_BACKTICK:
                case Tokens::T_DOUBLE_QUOTE:
                case Tokens::T_CONSTANT_ENCAPSED_STRING:
                    $expressions[] = $this->parseLiteralOrString();
                    break;
                case Tokens::T_NEW:
                    $expressions[] = $this->parseAllocationExpression();
                    break;
                case Tokens::T_EVAL:
                    $expressions[] = $this->parseEvalExpression();
                    break;
                case Tokens::T_CLONE:
                    $expressions[] = $this->parseCloneExpression();
                    break;
                case Tokens::T_INSTANCEOF:
                    $expressions[] = $this->parseInstanceOfExpression();
                    break;
                case Tokens::T_ISSET:
                    $expressions[] = $this->parseIssetExpression();
                    break;
                case Tokens::T_LIST:
                    $expressions[] = $this->parseListExpression();
                    break;
                case Tokens::T_QUESTION_MARK:
                    $expressions[] = $this->parseConditionalExpression();
                    break;
                case Tokens::T_BOOLEAN_AND:
                    $expressions[] = $this->parseBooleanAndExpression();
                    break;
                case Tokens::T_BOOLEAN_OR:
                    $expressions[] = $this->parseBooleanOrExpression();
                    break;
                case Tokens::T_LOGICAL_AND:
                    $expressions[] = $this->parseLogicalAndExpression();
                    break;
                case Tokens::T_LOGICAL_OR:
                    $expressions[] = $this->parseLogicalOrExpression();
                    break;
                case Tokens::T_LOGICAL_XOR:
                    $expressions[] = $this->parseLogicalXorExpression();
                    break;
                case Tokens::T_FUNCTION:
                    $expressions[] = $this->parseClosureDeclaration();
                    break;
                case Tokens::T_PARENTHESIS_OPEN:
                    $expressions[] = $this->parseParenthesisExpressionOrPrimaryPrefix();
                    break;
                case Tokens::T_EXIT:
                    $expressions[] = $this->parseExitExpression();
                    break;
                case Tokens::T_START_HEREDOC:
                    $expressions[] = $this->parseHeredoc();
                    break;
                case Tokens::T_CURLY_BRACE_OPEN:
                    $expressions[] = $this->parseBraceExpression(
                        $this->builder->buildAstExpression(),
                        $this->consumeToken(Tokens::T_CURLY_BRACE_OPEN),
                        Tokens::T_CURLY_BRACE_CLOSE
                    );
                    break;
                case Tokens::T_INCLUDE:
                    $expressions[] = $this->parseIncludeExpression();
                    break;
                case Tokens::T_INCLUDE_ONCE:
                    $expressions[] = $this->parseIncludeOnceExpression();
                    break;
                case Tokens::T_REQUIRE:
                    $expressions[] = $this->parseRequireExpression();
                    break;
                case Tokens::T_REQUIRE_ONCE:
                    $expressions[] = $this->parseRequireOnceExpression();
                    break;
                case Tokens::T_DEC:
                    $expressions[] = $this->parseDecrementExpression($expressions);
                    break;
                case Tokens::T_INC:
                    $expressions[] = $this->parseIncrementExpression($expressions);
                    break;
                case Tokens::T_SL:
                    $expressions[] = $this->parseShiftLeftExpression();
                    break;
                case Tokens::T_SR:
                    $expressions[] = $this->parseShiftRightExpression();
                    break;
                case Tokens::T_DIR:
                case Tokens::T_FILE:
                case Tokens::T_LINE:
                case Tokens::T_NS_C:
                case Tokens::T_FUNC_C:
                case Tokens::T_CLASS_C:
                case Tokens::T_METHOD_C:
                    $expressions[] = $this->parseConstant();
                    break;
                case Tokens::T_INT_CAST:
                case Tokens::T_BOOL_CAST:
                case Tokens::T_ARRAY_CAST:
                case Tokens::T_UNSET_CAST:
                case Tokens::T_OBJECT_CAST:
                case Tokens::T_DOUBLE_CAST:
                case Tokens::T_STRING_CAST:
                    $expressions[] = $this->parseCastExpression();
                    break;
                case Tokens::T_EQUAL:
                case Tokens::T_OR_EQUAL:
                case Tokens::T_SL_EQUAL:
                case Tokens::T_SR_EQUAL:
                case Tokens::T_AND_EQUAL:
                case Tokens::T_DIV_EQUAL:
                case Tokens::T_MOD_EQUAL:
                case Tokens::T_MUL_EQUAL:
                case Tokens::T_XOR_EQUAL:
                case Tokens::T_PLUS_EQUAL:
                case Tokens::T_MINUS_EQUAL:
                case Tokens::T_CONCAT_EQUAL:
                    $expressions[] = $this->parseAssignmentExpression(
                        array_pop($expressions)
                    );
                    break;
                // TODO: Handle comments here
                case Tokens::T_COMMENT:
                case Tokens::T_DOC_COMMENT:
                    $this->consumeToken($tokenType);
                    break;
                case Tokens::T_PRINT: // TODO: Implement print expression
                    $token = $this->consumeToken($tokenType);

                    $expr = $this->builder->buildAstPrintExpression();
                    $expr->configureLinesAndColumns(
                        $token->startLine,
                        $token->endLine,
                        $token->startColumn,
                        $token->endColumn
                    );

                    $expressions[] = $expr;
                    break;
                case Tokens::T_STRING_VARNAME: // TODO: Implement this
                case Tokens::T_PLUS: // TODO: Make this a arithmetic expression
                case Tokens::T_MINUS:
                case Tokens::T_MUL:
                case Tokens::T_DIV:
                case Tokens::T_MOD:
                case Tokens::T_IS_EQUAL: // TODO: Implement compare expressions
                case Tokens::T_IS_NOT_EQUAL:
                case Tokens::T_IS_IDENTICAL:
                case Tokens::T_IS_NOT_IDENTICAL:
                case Tokens::T_IS_GREATER_OR_EQUAL:
                case Tokens::T_IS_SMALLER_OR_EQUAL:
                case Tokens::T_ANGLE_BRACKET_OPEN:
                case Tokens::T_ANGLE_BRACKET_CLOSE:
                case Tokens::T_EMPTY:
                case Tokens::T_CONCAT:
                case Tokens::T_BITWISE_OR:
                case Tokens::T_BITWISE_AND:
                case Tokens::T_BITWISE_NOT:
                case Tokens::T_BITWISE_XOR:
                    $token = $this->consumeToken($tokenType);

                    $expr = $this->builder->buildAstExpression($token->image);
                    $expr->configureLinesAndColumns(
                        $token->startLine,
                        $token->endLine,
                        $token->startColumn,
                        $token->endColumn
                    );

                    $expressions[] = $expr;
                    break;
                case Tokens::T_AT:
                case Tokens::T_EXCLAMATION_MARK:
                    $token = $this->consumeToken($tokenType);

                    $expr = $this->builder->buildAstUnaryExpression($token->image);
                    $expr->configureLinesAndColumns(
                        $token->startLine,
                        $token->endLine,
                        $token->startColumn,
                        $token->endColumn
                    );

                    $expressions[] = $expr;
                    break;
                case Tokens::T_YIELD:
                    $expressions[] = $this->parseYield();
                    break;
                default:
                    $expressions[] = $this->parseOptionalExpressionForVersion();
                    break;
            }
        }

        $expressions = $this->reduce($expressions);

        $count = count($expressions);
        if ($count == 0) {
            return null;
        } elseif ($count == 1) {
            return $expressions[0];
        }

        $expr = $this->builder->buildAstExpression();
        foreach ($expressions as $node) {
            $expr->addChild($node);
        }
        $expr->configureLinesAndColumns(
            $expressions[0]->getStartLine(),
            $expressions[$count - 1]->getEndLine(),
            $expressions[0]->getStartColumn(),
            $expressions[$count - 1]->getEndColumn()
        );

        return $expr;
    }

    /**
     * This method will be called when the base parser cannot handle an expression
     * in the base version. In this method you can implement version specific
     * expressions.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\UnexpectedTokenException
     * @since 2.2
     */
    protected function parseOptionalExpressionForVersion()
    {
        $this->throwUnexpectedTokenException();
    }

    /**
     * Applies all reduce rules against the given expression list.
     *
     * @param \PDepend\Source\AST\ASTExpression[] $expressions Unprepared input
     *        array with parsed expression nodes found in the source tree.
     *
     * @return \PDepend\Source\AST\ASTExpression[]
     * @since 0.10.0
     */
    protected function reduce(array $expressions)
    {
        return $this->reduceUnaryExpression($expressions);
    }

    /**
     * Reduces all unary-expressions in the given expression list.
     *
     * @param \PDepend\Source\AST\ASTExpression[] $expressions Unprepared input
     *        array with parsed expression nodes found in the source tree.
     *
     * @return \PDepend\Source\AST\ASTExpression[]
     * @since 0.10.0
     */
    private function reduceUnaryExpression(array $expressions)
    {
        for ($i = count($expressions) - 2; $i >= 0; --$i) {
            $expr = $expressions[$i];
            if ($expr instanceof \PDepend\Source\AST\ASTUnaryExpression) {
                $child = $expressions[$i + 1];

                $expr->addChild($child);

                $expr->configureLinesAndColumns(
                    $expr->getStartLine(),
                    $child->getEndLine(),
                    $expr->getStartColumn(),
                    $child->getEndColumn()
                );

                unset($expressions[$i + 1]);
            }
        }
        return array_values($expressions);
    }

    /**
     * This method parses a switch statement.
     *
     * @return \PDepend\Source\AST\ASTSwitchStatement
     * @since 0.9.8
     */
    private function parseSwitchStatement()
    {
        $this->tokenStack->push();
        $this->consumeToken(Tokens::T_SWITCH);

        $switch = $this->builder->buildAstSwitchStatement();
        $switch->addChild($this->parseParenthesisExpression());
        $this->parseSwitchStatementBody($switch);

        return $this->setNodePositionsAndReturn($switch);
    }

    /**
     * Parses the body of a switch statement.
     *
     * @param \PDepend\Source\AST\ASTSwitchStatement $switch The parent switch stmt.
     *
     * @return \PDepend\Source\AST\ASTSwitchStatement
     * @since 0.9.8
     */
    private function parseSwitchStatementBody(ASTSwitchStatement $switch)
    {
        $this->consumeComments();
        if ($this->tokenizer->peek() === Tokens::T_CURLY_BRACE_OPEN) {
            $this->consumeToken(Tokens::T_CURLY_BRACE_OPEN);
        } else {
            $this->consumeToken(Tokens::T_COLON);
        }

        while (($tokenType = $this->tokenizer->peek()) !== Tokenizer::T_EOF) {
            switch ($tokenType) {
                case Tokens::T_CLOSE_TAG:
                    $this->parseNonePhpCode();
                    break;
                case Tokens::T_ENDSWITCH:
                    $this->parseAlternativeScopeTermination(Tokens::T_ENDSWITCH);
                    return $switch;
                case Tokens::T_CURLY_BRACE_CLOSE:
                    $this->consumeToken(Tokens::T_CURLY_BRACE_CLOSE);
                    return $switch;
                case Tokens::T_CASE:
                    $switch->addChild($this->parseSwitchLabel());
                    break;
                case Tokens::T_DEFAULT:
                    $switch->addChild($this->parseSwitchLabelDefault());
                    break;
                case Tokens::T_COMMENT:
                case Tokens::T_DOC_COMMENT:
                    $this->consumeToken($tokenType);
                    break;
                default:
                    break 2;
            }
        }

        $this->throwUnexpectedTokenException();
    }

    /**
     * This method parses a case label of a switch statement.
     *
     * @return \PDepend\Source\AST\ASTSwitchLabel
     * @since 0.9.8
     */
    private function parseSwitchLabel()
    {
        $this->tokenStack->push();
        $token = $this->consumeToken(Tokens::T_CASE);

        $label = $this->builder->buildAstSwitchLabel($token->image);
        $label->addChild($this->parseExpression());

        if ($this->tokenizer->peek() === Tokens::T_COLON) {
            $this->consumeToken(Tokens::T_COLON);
        } else {
            $this->consumeToken(Tokens::T_SEMICOLON);
        }

        $this->parseSwitchLabelBody($label);

        return $this->setNodePositionsAndReturn($label);
    }

    /**
     * This method parses the default label of a switch statement.
     *
     * @return \PDepend\Source\AST\ASTSwitchLabel
     * @since 0.9.8
     */
    private function parseSwitchLabelDefault()
    {
        $this->tokenStack->push();
        $token = $this->consumeToken(Tokens::T_DEFAULT);

        $this->consumeComments();
        if ($this->tokenizer->peek() === Tokens::T_COLON) {
            $this->consumeToken(Tokens::T_COLON);
        } else {
            $this->consumeToken(Tokens::T_SEMICOLON);
        }

        $label = $this->builder->buildAstSwitchLabel($token->image);
        $label->setDefault();

        $this->parseSwitchLabelBody($label);

        return $this->setNodePositionsAndReturn($label);
    }

    /**
     * Parses the body of an switch label node.
     *
     * @param  \PDepend\Source\AST\ASTSwitchLabel $label The context switch label.
     * @return \PDepend\Source\AST\ASTSwitchLabel
     */
    private function parseSwitchLabelBody(\PDepend\Source\AST\ASTSwitchLabel $label)
    {
        $curlyBraceCount = 0;

        $tokenType = $this->tokenizer->peek();
        while ($tokenType !== Tokenizer::T_EOF) {
            switch ($tokenType) {
                case Tokens::T_CURLY_BRACE_OPEN:
                    $this->consumeToken(Tokens::T_CURLY_BRACE_OPEN);
                    ++$curlyBraceCount;
                    break;
                case Tokens::T_CURLY_BRACE_CLOSE:
                    if ($curlyBraceCount === 0) {
                        return $label;
                    }
                    $this->consumeToken(Tokens::T_CURLY_BRACE_CLOSE);
                    --$curlyBraceCount;
                    break;
                case Tokens::T_CLOSE_TAG:
                    $this->parseNonePhpCode();
                    break;
                case Tokens::T_CASE:
                case Tokens::T_DEFAULT:
                case Tokens::T_ENDSWITCH:
                    return $label;
                default:
                    $statement = $this->parseOptionalStatement();
                    if ($statement === null) {
                        $this->consumeToken($tokenType);
                    } elseif ($statement instanceof ASTNode) {
                        $label->addChild($statement);
                    }
                    // TODO: Change the <else if> into and <else> when the ast
                    //       implementation is finished.
                    break;
            }
            $tokenType = $this->tokenizer->peek();
        }
        throw new TokenStreamEndException($this->tokenizer);
    }

    /**
     * Parses the termination token for a statement. This termination token can
     * be a semicolon or a closing php tag.
     *
     * @return void
     * @since 0.9.12
     */
    private function parseStatementTermination()
    {
        $this->consumeComments();
        if ($this->tokenizer->peek() === Tokens::T_SEMICOLON) {
            $this->consumeToken(Tokens::T_SEMICOLON);
        } else {
            $this->parseNonePhpCode();
        }
    }

    /**
     * This method parses a try-statement + associated catch-statements.
     *
     * @return \PDepend\Source\AST\ASTTryStatement
     * @since 0.9.12
     */
    private function parseTryStatement()
    {
        $this->tokenStack->push();
        $token = $this->consumeToken(Tokens::T_TRY);

        $stmt = $this->builder->buildAstTryStatement($token->image);
        $stmt->addChild($this->parseRegularScope());

        $this->consumeComments();

        if (false === in_array($this->tokenizer->peek(), array(Tokens::T_CATCH, Tokens::T_FINALLY))) {
            $this->throwUnexpectedTokenException();
        }

        while ($this->tokenizer->peek() === Tokens::T_CATCH) {
            $stmt->addChild($this->parseCatchStatement());
            $this->consumeComments();
        }

        while ($this->tokenizer->peek() === Tokens::T_FINALLY) {
            $stmt->addChild($this->parseFinallyStatement());
            $this->consumeComments();
        }

        return $this->setNodePositionsAndReturn($stmt);
    }

    /**
     * This method parses a throw-statement.
     *
     * @return \PDepend\Source\AST\ASTThrowStatement
     * @since 0.9.12
     */
    private function parseThrowStatement()
    {
        $this->tokenStack->push();
        $token = $this->consumeToken(Tokens::T_THROW);

        $stmt = $this->builder->buildAstThrowStatement($token->image);
        $stmt->addChild($this->parseExpression());

        $this->parseStatementTermination();

        return $this->setNodePositionsAndReturn($stmt);
    }

    /**
     * This method parses a goto-statement.
     *
     * @return \PDepend\Source\AST\ASTGotoStatement
     * @since 0.9.12
     */
    private function parseGotoStatement()
    {
        $this->tokenStack->push();

        $this->consumeToken(Tokens::T_GOTO);
        $this->consumeComments();

        $token = $this->consumeToken(Tokens::T_STRING);

        $this->parseStatementTermination();

        $stmt = $this->builder->buildAstGotoStatement($token->image);
        return $this->setNodePositionsAndReturn($stmt);
    }

    /**
     * This method parses a label-statement.
     *
     * @return \PDepend\Source\AST\ASTLabelStatement
     * @since 0.9.12
     */
    private function parseLabelStatement()
    {
        $this->tokenStack->push();

        $token = $this->consumeToken(Tokens::T_STRING);
        $this->consumeComments();
        $this->consumeToken(Tokens::T_COLON);

        return $this->setNodePositionsAndReturn(
            $this->builder->buildAstLabelStatement($token->image)
        );
    }

    /**
     * This method parses a global-statement.
     *
     * @return \PDepend\Source\AST\ASTGlobalStatement
     * @since 0.9.12
     */
    private function parseGlobalStatement()
    {
        $this->tokenStack->push();
        $this->consumeToken(Tokens::T_GLOBAL);

        $stmt = $this->builder->buildAstGlobalStatement();
        $stmt = $this->parseVariableList($stmt);

        $this->parseStatementTermination();

        return $this->setNodePositionsAndReturn($stmt);
    }

    /**
     * This method parses a unset-statement.
     *
     * @return \PDepend\Source\AST\ASTUnsetStatement
     * @since 0.9.12
     */
    private function parseUnsetStatement()
    {
        $this->tokenStack->push();

        $this->consumeToken(Tokens::T_UNSET);
        $this->consumeComments();
        $this->consumeToken(Tokens::T_PARENTHESIS_OPEN);

        $stmt = $this->builder->buildAstUnsetStatement();
        $stmt = $this->parseVariableList($stmt);

        $this->consumeToken(Tokens::T_PARENTHESIS_CLOSE);

        $this->parseStatementTermination();

        return $this->setNodePositionsAndReturn($stmt);
    }

    /**
     * This method parses a catch-statement.
     *
     * @return \PDepend\Source\AST\ASTCatchStatement
     * @since 0.9.8
     */
    private function parseCatchStatement()
    {
        $this->tokenStack->push();
        $this->consumeComments();

        $token = $this->consumeToken(Tokens::T_CATCH);

        $catch = $this->builder->buildAstCatchStatement($token->image);

        $this->consumeComments();
        $this->consumeToken(Tokens::T_PARENTHESIS_OPEN);

        $catch->addChild(
            $this->builder->buildAstClassOrInterfaceReference(
                $this->parseQualifiedName()
            )
        );

        $this->consumeComments();
        $catch->addChild($this->parseVariable());

        $this->consumeComments();
        $this->consumeToken(Tokens::T_PARENTHESIS_CLOSE);

        $catch->addChild($this->parseRegularScope());

        return $this->setNodePositionsAndReturn($catch);
    }

    /**
     * This method parses a finally-statement.
     *
     * @return \PDepend\Source\AST\ASTFinallyStatement
     * @since 2.0.0
     */
    private function parseFinallyStatement()
    {
        $this->tokenStack->push();
        $this->consumeComments();

        $token = $this->consumeToken(Tokens::T_FINALLY);

        $finally = $this->builder->buildAstFinallyStatement($token->image);
        $finally->addChild($this->parseRegularScope());

        return $this->setNodePositionsAndReturn($finally);
    }

    /**
     * This method parses a single if-statement node.
     *
     * @return \PDepend\Source\AST\ASTIfStatement
     * @since 0.9.8
     */
    private function parseIfStatement()
    {
        $this->tokenStack->push();
        $token = $this->consumeToken(Tokens::T_IF);

        $stmt = $this->builder->buildAstIfStatement($token->image);
        $stmt->addChild($this->parseParenthesisExpression());

        $this->parseStatementBody($stmt);
        $this->parseOptionalElseOrElseIfStatement($stmt);

        return $this->setNodePositionsAndReturn($stmt);
    }

    /**
     * This method parses a single elseif-statement node.
     *
     * @return \PDepend\Source\AST\ASTElseIfStatement
     * @since 0.9.8
     */
    private function parseElseIfStatement()
    {
        $this->tokenStack->push();
        $token = $this->consumeToken(Tokens::T_ELSEIF);

        $stmt = $this->builder->buildAstElseIfStatement($token->image);
        $stmt->addChild($this->parseParenthesisExpression());

        $this->parseStatementBody($stmt);
        $this->parseOptionalElseOrElseIfStatement($stmt);

        return $this->setNodePositionsAndReturn($stmt);
    }

    /**
     * This method parses an optional else-, else+if- or elseif-statement.
     *
     * @param \PDepend\Source\AST\ASTStatement $stmt The owning if/elseif statement.
     *
     * @return \PDepend\Source\AST\ASTStatement
     * @since 0.9.12
     */
    private function parseOptionalElseOrElseIfStatement(ASTStatement $stmt)
    {
        $this->consumeComments();
        switch ($this->tokenizer->peek()) {
            case Tokens::T_ELSE:
                $this->consumeToken(Tokens::T_ELSE);
                $this->consumeComments();
                if ($this->tokenizer->peek() === Tokens::T_IF) {
                    $stmt->addChild($this->parseIfStatement());
                } else {
                    $this->parseStatementBody($stmt);
                }
                break;
            case Tokens::T_ELSEIF:
                $stmt->addChild($this->parseElseIfStatement());
                break;
        }

        return $stmt;
    }

    /**
     * This method parses a single for-statement node.
     *
     * @return \PDepend\Source\AST\ASTForStatement
     * @since 0.9.8
     */
    private function parseForStatement()
    {
        $this->tokenStack->push();
        $token = $this->consumeToken(Tokens::T_FOR);

        $this->consumeComments();
        $this->consumeToken(Tokens::T_PARENTHESIS_OPEN);

        $stmt = $this->builder->buildAstForStatement($token->image);

        if (($init = $this->parseForInit()) !== null) {
            $stmt->addChild($init);
        }
        $this->consumeToken(Tokens::T_SEMICOLON);

        if (($expr = $this->parseForExpression()) !== null) {
            $stmt->addChild($expr);
        }
        $this->consumeToken(Tokens::T_SEMICOLON);

        if (($update = $this->parseForUpdate()) !== null) {
            $stmt->addChild($update);
        }
        $this->consumeToken(Tokens::T_PARENTHESIS_CLOSE);

        return $this->setNodePositionsAndReturn($this->parseStatementBody($stmt));
    }

    /**
     * Parses the init part of a for-statement.
     *
     * <code>
     *      ------------------------
     * for ($x = 0, $y = 23, $z = 42; $x < $y; ++$x) {}
     *      ------------------------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTForInit
     * @since 0.9.8
     */
    private function parseForInit()
    {
        $this->consumeComments();
        if (Tokens::T_SEMICOLON === $this->tokenizer->peek()) {
            return null;
        }

        $this->tokenStack->push();

        $init = $this->builder->buildAstForInit();
        $this->parseExpressionList($init);

        return $this->setNodePositionsAndReturn($init);
    }

    /**
     * Parses the expression part of a for-statement.
     *
     * @return \PDepend\Source\AST\ASTExpression
     * @since 0.9.12
     */
    private function parseForExpression()
    {
        return $this->parseOptionalExpression();
    }

    /**
     * Parses the update part of a for-statement.
     *
     * <code>
     *                                        -------------------------------
     * for ($x = 0, $y = 23, $z = 42; $x < $y; ++$x, $y = $x + 1, $z = $x + 2) {}
     *                                        -------------------------------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTForUpdate
     * @since 0.9.12
     */
    private function parseForUpdate()
    {
        $this->consumeComments();
        if (Tokens::T_PARENTHESIS_CLOSE === $this->tokenizer->peek()) {
            return null;
        }

        $this->tokenStack->push();

        $update = $this->builder->buildAstForUpdate();
        $this->parseExpressionList($update);

        return $this->setNodePositionsAndReturn($update);
    }

    /**
     * This method parses a single foreach-statement node.
     *
     * @return \PDepend\Source\AST\ASTForeachStatement
     * @since 0.9.8
     */
    private function parseForeachStatement()
    {
        $this->tokenStack->push();
        $token = $this->consumeToken(Tokens::T_FOREACH);

        $foreach = $this->builder->buildAstForeachStatement($token->image);

        $this->consumeComments();
        $this->consumeToken(Tokens::T_PARENTHESIS_OPEN);

        $foreach->addChild($this->parseExpression());

        $this->consumeToken(Tokens::T_AS);
        $this->consumeComments();

        if ($this->tokenizer->peek() === Tokens::T_BITWISE_AND) {
            $foreach->addChild($this->parseVariableOrMemberByReference());
        } else {
            if ($this->tokenizer->peek() == Tokens::T_LIST) {
                $foreach->addChild($this->parseListExpression());
            } else {
                $foreach->addChild($this->parseVariableOrConstantOrPrimaryPrefix());

                if ($this->tokenizer->peek() === Tokens::T_DOUBLE_ARROW) {
                    $this->consumeToken(Tokens::T_DOUBLE_ARROW);

                    if ($this->tokenizer->peek() == Tokens::T_LIST) {
                        $foreach->addChild($this->parseListExpression());
                    } else {
                        $foreach->addChild(
                            $this->parseVariableOrMemberOptionalByReference()
                        );
                    }
                }
            }
        }

        $this->consumeComments();
        $this->consumeToken(Tokens::T_PARENTHESIS_CLOSE);

        return $this->setNodePositionsAndReturn(
            $this->parseStatementBody($foreach)
        );
    }

    /**
     * This method parses a single while-statement node.
     *
     * @return \PDepend\Source\AST\ASTWhileStatement
     * @since 0.9.8
     */
    private function parseWhileStatement()
    {
        $this->tokenStack->push();
        $token = $this->consumeToken(Tokens::T_WHILE);

        $stmt = $this->builder->buildAstWhileStatement($token->image);
        $stmt->addChild($this->parseParenthesisExpression());

        return $this->setNodePositionsAndReturn(
            $this->parseStatementBody($stmt)
        );
    }

    /**
     * This method parses a do/while-statement.
     *
     * @return \PDepend\Source\AST\ASTDoWhileStatement
     * @since 0.9.12
     */
    private function parseDoWhileStatement()
    {
        $this->tokenStack->push();
        $token = $this->consumeToken(Tokens::T_DO);

        $stmt = $this->builder->buildAstDoWhileStatement($token->image);
        $stmt = $this->parseStatementBody($stmt);

        $this->consumeComments();
        $this->consumeToken(Tokens::T_WHILE);

        $stmt->addChild($this->parseParenthesisExpression());

        $this->parseStatementTermination();

        return $this->setNodePositionsAndReturn($stmt);
    }

    /**
     * This method parses a declare-statement.
     *
     * <code>
     * -------------------------------
     * declare(encoding='ISO-8859-1');
     * -------------------------------
     *
     * -------------------
     * declare(ticks=42) {
     *     // ...
     * }
     * -
     *
     * ------------------
     * declare(ticks=42):
     *     // ...
     * enddeclare;
     * -----------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTDeclareStatement
     * @since 0.10.0
     */
    private function parseDeclareStatement()
    {
        $this->tokenStack->push();
        $this->consumeToken(Tokens::T_DECLARE);

        $stmt = $this->builder->buildAstDeclareStatement();
        $stmt = $this->parseDeclareList($stmt);
        $stmt = $this->parseStatementBody($stmt);

        return $this->setNodePositionsAndReturn($stmt);
    }

    /**
     * This method parses a list of declare values. A declare list value always
     * consists of a string token and a static scalar.
     *
     * @param \PDepend\Source\AST\ASTDeclareStatement $stmt The declare statement that
     *        is the owner of this list.
     * @return \PDepend\Source\AST\ASTDeclareStatement
     * @since 0.10.0
     */
    private function parseDeclareList(ASTDeclareStatement $stmt)
    {
        $this->consumeComments();
        $this->consumeToken(Tokens::T_PARENTHESIS_OPEN);

        while (true) {
            $this->consumeComments();
            $name = $this->consumeToken(Tokens::T_STRING)->image;

            $this->consumeComments();
            $this->consumeToken(Tokens::T_EQUAL);

            $this->consumeComments();
            $value = $this->parseStaticValue();

            $stmt->addValue($name, $value);

            $this->consumeComments();
            if ($this->tokenizer->peek() === Tokens::T_COMMA) {
                $this->consumeToken(Tokens::T_COMMA);
                continue;
            }
            break;
        }

        $this->consumeToken(Tokens::T_PARENTHESIS_CLOSE);
        return $stmt;
    }

    /**
     * This method parses a single return-statement node.
     *
     * @return \PDepend\Source\AST\ASTReturnStatement
     * @since 0.9.12
     */
    private function parseReturnStatement()
    {
        $this->tokenStack->push();
        $token = $this->consumeToken(Tokens::T_RETURN);

        $stmt = $this->builder->buildAstReturnStatement($token->image);
        if (($expr = $this->parseOptionalExpression()) != null) {
            $stmt->addChild($expr);
        }
        $this->parseStatementTermination();

        return $this->setNodePositionsAndReturn($stmt);
    }

    /**
     * This method parses a break-statement node.
     *
     * @return \PDepend\Source\AST\ASTBreakStatement
     * @since 0.9.12
     */
    private function parseBreakStatement()
    {
        $this->tokenStack->push();
        $token = $this->consumeToken(Tokens::T_BREAK);

        $stmt = $this->builder->buildAstBreakStatement($token->image);
        if (($expr = $this->parseOptionalExpression()) != null) {
            $stmt->addChild($expr);
        }
        $this->parseStatementTermination();

        return $this->setNodePositionsAndReturn($stmt);
    }

    /**
     * This method parses a continue-statement node.
     *
     * @return \PDepend\Source\AST\ASTContinueStatement
     * @since 0.9.12
     */
    private function parseContinueStatement()
    {
        $this->tokenStack->push();
        $token = $this->consumeToken(Tokens::T_CONTINUE);

        $stmt = $this->builder->buildAstContinueStatement($token->image);
        if (($expr = $this->parseOptionalExpression()) != null) {
            $stmt->addChild($expr);
        }
        $this->parseStatementTermination();

        return $this->setNodePositionsAndReturn($stmt);
    }

    /**
     * This method parses a echo-statement node.
     *
     * @return \PDepend\Source\AST\ASTEchoStatement
     * @since 0.9.12
     */
    private function parseEchoStatement()
    {
        $this->tokenStack->push();
        $token = $this->consumeToken(Tokens::T_ECHO);

        $stmt = $this->parseExpressionList(
            $this->builder->buildAstEchoStatement($token->image)
        );

        $this->parseStatementTermination();

        return $this->setNodePositionsAndReturn($stmt);
    }

    /**
     * Parses a simple parenthesis expression or a direct object access, which
     * was introduced with PHP 5.4.0:
     *
     * <code>
     * (new MyClass())->bar();
     * </code>
     *
     * @return \PDepend\Source\AST\ASTNode
     * @since 1.0.0
     */
    protected function parseParenthesisExpressionOrPrimaryPrefix()
    {
        return $this->parseParenthesisExpressionOrPrimaryPrefixForVersion(
            $this->parseParenthesisExpression()
        );
    }

    /**
     * @param \PDepend\Source\AST\ASTExpression $expr
     * @return \PDepend\Source\AST\ASTExpression
     */
    protected function parseParenthesisExpressionOrPrimaryPrefixForVersion(ASTExpression $expr)
    {
        $this->consumeComments();
        if (Tokens::T_OBJECT_OPERATOR === $this->tokenizer->peek()) {
            return $this->parseMemberPrimaryPrefix($expr->getChild(0));
        }
        return $expr;
    }

    /**
     * Parses any expression that is surrounded by an opening and a closing
     * parenthesis
     *
     * @return \PDepend\Source\AST\ASTExpression
     * @since 0.9.8
     */
    private function parseParenthesisExpression()
    {
        $this->tokenStack->push();
        $this->consumeComments();

        $expr = $this->builder->buildAstExpression();
        $expr = $this->parseBraceExpression(
            $expr,
            $this->consumeToken(Tokens::T_PARENTHESIS_OPEN),
            Tokens::T_PARENTHESIS_CLOSE
        );

        return $this->setNodePositionsAndReturn($expr);
    }

    /**
     * This method parses a member primary prefix expression or a function
     * postfix expression node.
     *
     * A member primary prefix can be a method call:
     *
     * <code>
     * $object->foo();
     *
     * clazz::foo();
     * </code>
     *
     * a property access:
     *
     * <code>
     * $object->foo;
     *
     * clazz::$foo;
     * </code>
     *
     * or a class constant access:
     *
     * <code>
     * clazz::FOO;
     * </code>
     *
     * A function postfix represents any kind of function call:
     *
     * <code>
     * $function();
     *
     * func();
     * </code>
     *
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\ParserException
     * @since 0.9.6
     */
    private function parseMemberPrefixOrFunctionPostfix()
    {
        $this->tokenStack->push();
        $this->tokenStack->push();

        $qName = $this->parseQualifiedName();

        // Remove comments
        $this->consumeComments();

        // Get next token type
        $tokenType = $this->tokenizer->peek();

        switch ($tokenType) {
            case Tokens::T_DOUBLE_COLON:
                $node = $this->builder->buildAstClassOrInterfaceReference($qName);
                $node = $this->setNodePositionsAndReturn($node);
                $node = $this->parseStaticMemberPrimaryPrefix($node);
                break;
            case Tokens::T_PARENTHESIS_OPEN:
                $node = $this->builder->buildAstIdentifier($qName);
                $node = $this->setNodePositionsAndReturn($node);
                $node = $this->parseFunctionPostfix($node);
                break;
            default:
                $node = $this->builder->buildAstConstant($qName);
                $node = $this->setNodePositionsAndReturn($node);
                break;
        }

        return $this->setNodePositionsAndReturn($node);
    }

    /**
     * This method will parse an optional function postfix.
     *
     * If the next available token is an opening parenthesis, this method will
     * wrap the given <b>$node</b> with a {@link \PDepend\Source\AST\ASTFunctionPostfix}
     * node.
     *
     * @param \PDepend\Source\AST\ASTNode $node The previously parsed node.
     *
     * @return \PDepend\Source\AST\ASTNode The original input node or this node
     *         wrapped with a function postfix instance.
     * @since 1.0.0
     */
    private function parseOptionalFunctionPostfix(ASTNode $node)
    {
        $this->consumeComments();
        if (Tokens::T_PARENTHESIS_OPEN === $this->tokenizer->peek()) {
            return $this->parseFunctionPostfix($node);
        }
        return $node;
    }

    /**
     * This method parses a function postfix expression. An object of type
     * {@link \PDepend\Source\AST\ASTFunctionPostfix} represents any valid php
     * function call.
     *
     * This method will delegate the call to another method that returns a
     * member primary prefix object when the function postfix expression is
     * followed by an object operator.
     *
     * @param  \PDepend\Source\AST\ASTNode $node This node represents the function
     *        identifier. An identifier can be a static string, a variable, a
     *        compound variable or any other valid php function identifier.
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\ParserException
     * @since 0.9.6
     */
    private function parseFunctionPostfix(ASTNode $node)
    {
        $image = $this->extractPostfixImage($node);

        $function = $this->builder->buildAstFunctionPostfix($image);
        $function->addChild($node);
        $function->addChild($this->parseArguments());

        return $this->parseOptionalMemberPrimaryPrefix(
            $this->parseOptionalIndexExpression($function)
        );
    }

    /**
     * This method parses a PHP version specific identifier for method and
     * property postfix expressions.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @since 1.0.0
     */
    protected function parsePostfixIdentifier()
    {
        switch ($this->tokenizer->peek()) {
            case Tokens::T_STRING:
                $node = $this->parseLiteral();
                break;
            default:
                $node = $this->parseCompoundVariableOrVariableVariableOrVariable();
                break;
        }
        return $this->parseOptionalIndexExpression($node);
    }

    /**
     * This method parses an optional member primary expression. It will parse
     * the primary expression when an object operator can be found at the actual
     * token stream position. Otherwise this method simply returns the input
     * {@link \PDepend\Source\AST\ASTNode} instance.
     *
     * @param  \PDepend\Source\AST\ASTNode $node This node represents primary prefix
     *        left expression. It will be the first child of the parsed member
     *        primary expression.
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\ParserException
     * @since 0.9.6
     */
    protected function parseOptionalMemberPrimaryPrefix(ASTNode $node)
    {
        $this->consumeComments();

        if ($this->tokenizer->peek() === Tokens::T_OBJECT_OPERATOR) {
            return $this->parseMemberPrimaryPrefix($node);
        }
        return $node;
    }

    /**
     * This method parses a dynamic or object bound member primary expression.
     * A member primary prefix can be a method call:
     *
     * <code>
     * $object->foo();
     * </code>
     *
     * or a property access:
     *
     * <code>
     * $object->foo;
     * </code>
     *
     * @param  \PDepend\Source\AST\ASTNode $node The left node in the parsed member
     *        primary expression.
     * @return \PDepend\Source\AST\ASTMemberPrimaryPrefix
     * @throws \PDepend\Source\Parser\ParserException
     * @since 0.9.6
     */
    protected function parseMemberPrimaryPrefix(ASTNode $node)
    {
        // Consume double colon and optional comments
        $token = $this->consumeToken(Tokens::T_OBJECT_OPERATOR);

        $prefix = $this->builder->buildAstMemberPrimaryPrefix($token->image);
        $prefix->addChild($node);

        $this->consumeComments();
        $tokenType = $this->tokenizer->peek();

        switch ($tokenType) {
            case ($this->isMethodName($tokenType)):
                $child = $this->parseIdentifier($tokenType);
                $child = $this->parseOptionalIndexExpression($child);

                // TODO: Move this in a separate method
                if ($child instanceof ASTIndexExpression) {
                    $this->consumeComments();
                    if (Tokens::T_PARENTHESIS_OPEN === $this->tokenizer->peek()) {
                        $prefix->addChild($this->parsePropertyPostfix($child));
                        return $this->parseOptionalFunctionPostfix($prefix);
                    }
                }
                break;
            case Tokens::T_CURLY_BRACE_OPEN:
                $child = $this->parseCompoundExpression();
                break;
            default:
                $child = $this->parseCompoundVariableOrVariableVariableOrVariable();
                break;
        }

        $prefix->addChild(
            $this->parseMethodOrPropertyPostfix(
                $this->parseOptionalIndexExpression($child)
            )
        );

        return $this->parseOptionalMemberPrimaryPrefix(
            $this->parseOptionalIndexExpression($prefix)
        );
    }

    /**
     * This method parses an optional member primary expression. It will parse
     * the primary expression when a double colon operator can be found at the
     * actual token stream position. Otherwise this method simply returns the
     * input {@link \PDepend\Source\AST\ASTNode} instance.
     *
     * @param  \PDepend\Source\AST\ASTNode $node This node represents primary prefix
     *        left expression. It will be the first child of the parsed member
     *        primary expression.
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\ParserException
     * @since 1.0.1
     */
    private function parseOptionalStaticMemberPrimaryPrefix(ASTNode $node)
    {
        $this->consumeComments();

        if ($this->tokenizer->peek() === Tokens::T_DOUBLE_COLON) {
            return $this->parseStaticMemberPrimaryPrefix($node);
        }
        return $node;
    }

    /**
     * This method parses a static member primary expression. The given node
     * contains the used static class or interface identifier. A static member
     * primary prefix can represent the following code expressions:
     *
     * A static method class:
     *
     * <code>
     * Foo::bar();
     * </code>
     *
     * a static property access:
     *
     * <code>
     * Foo::$bar;
     * </code>
     *
     * or a static constant access:
     *
     * <code>
     * Foo::BAR;
     * </code>
     *
     * @param  \PDepend\Source\AST\ASTNode $node The left node in the parsed member
     *        primary expression.
     * @return \PDepend\Source\AST\ASTMemberPrimaryPrefix
     * @throws \PDepend\Source\Parser\ParserException
     * @since 0.9.6
     */
    protected function parseStaticMemberPrimaryPrefix(ASTNode $node)
    {
        $token = $this->consumeToken(Tokens::T_DOUBLE_COLON);

        $prefix = $this->builder->buildAstMemberPrimaryPrefix($token->image);
        $prefix->addChild($node);

        $this->consumeComments();

        switch ($this->tokenizer->peek()) {
            case Tokens::T_STRING:
                $postfix = $this->parseMethodOrConstantPostfix();
                break;
            case Tokens::T_CLASS_FQN:
                $postfix = $this->parseFullQualifiedClassNamePostfix();
                break;
            default:
                $postfix = $this->parseMethodOrPropertyPostfix(
                    $this->parsePostfixIdentifier()
                );
                break;
        }

        $prefix->addChild($postfix);

        return $this->parseOptionalMemberPrimaryPrefix(
            $this->parseOptionalIndexExpression($prefix)
        );
    }

    /**
     * This method parses a method- or constant-postfix expression. This expression
     * will contain an identifier node as nested child.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\ParserException
     * @since 0.9.6
     */
    private function parseMethodOrConstantPostfix()
    {
        $this->tokenStack->push();

        $node = $this->parseIdentifier();

        $this->consumeComments();
        if ($this->tokenizer->peek() === Tokens::T_PARENTHESIS_OPEN) {
            $postfix = $this->parseMethodPostfix($node);
        } else {
            $postfix = $this->builder->buildAstConstantPostfix($node->getImage());
            $postfix->addChild($node);
        }

        return $this->setNodePositionsAndReturn($postfix);
    }

    /**
     * This method parses a method- or property-postfix expression. This expression
     * will contain the given node as method or property identifier.
     *
     * @param \PDepend\Source\AST\ASTNode $node The identifier for the parsed postfix
     *        expression node. This node will be the first child of the returned
     *        postfix node instance.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\ParserException
     * @since 0.9.6
     */
    private function parseMethodOrPropertyPostfix(ASTNode $node)
    {
        // Strip optional comments
        $this->consumeComments();

        switch ($this->tokenizer->peek()) {
            case Tokens::T_PARENTHESIS_OPEN:
                $postfix = $this->parseMethodPostfix($node);
                break;
            default:
                $postfix = $this->parsePropertyPostfix($node);
                break;
        }
        return $this->parseOptionalMemberPrimaryPrefix($postfix);
    }

    /**
     * Parses/Creates a property postfix node instance.
     *
     * @param \PDepend\Source\AST\ASTNode $node Node that represents the image of
     *        the property postfix node.
     *
     * @return \PDepend\Source\AST\ASTPropertyPostfix
     * @since 0.10.2
     */
    private function parsePropertyPostfix(ASTNode $node)
    {
        $image = $this->extractPostfixImage($node);

        $postfix = $this->builder->buildAstPropertyPostfix($image);
        $postfix->addChild($node);

        $postfix->configureLinesAndColumns(
            $node->getStartLine(),
            $node->getEndLine(),
            $node->getStartColumn(),
            $node->getEndColumn()
        );

        return $postfix;
    }

    /**
     * Parses a full qualified class name postfix.
     *
     * @return \PDepend\Source\AST\ASTClassFqnPostfix
     * @since 2.0.0
     */
    private function parseFullQualifiedClassNamePostfix()
    {
        $this->tokenStack->push();

        $this->consumeToken(Tokens::T_CLASS_FQN);

        return $this->setNodePositionsAndReturn(
            $this->builder->buildAstClassFqnPostfix()
        );
    }

    /**
     * This method will extract the image/name of the real property/variable
     * that is wrapped by {@link \PDepend\Source\AST\ASTIndexExpression} nodes. If
     * the given node is now wrapped by index expressions, this method will
     * return the image of the entire <b>$node</b>.
     *
     * @param \PDepend\Source\AST\ASTNode $node The context node that may be wrapped
     *        by multiple array or string index expressions.
     *
     * @return string
     * @since 1.0.0
     */
    private function extractPostfixImage(ASTNode $node)
    {
        while ($node instanceof \PDepend\Source\AST\ASTIndexExpression) {
            $node = $node->getChild(0);
        }
        return $node->getImage();
    }

    /**
     * Parses a method postfix node instance.
     *
     * @param \PDepend\Source\AST\ASTNode $node Node that represents the image of
     *        the method postfix node.
     *
     * @return \PDepend\Source\AST\ASTMethodPostfix
     * @since 1.0.0
     */
    private function parseMethodPostfix(ASTNode $node)
    {
        $args  = $this->parseArguments();
        $image = $this->extractPostfixImage($node);

        $postfix = $this->builder->buildAstMethodPostfix($image);
        $postfix->addChild($node);
        $postfix->addChild($args);

        $postfix->configureLinesAndColumns(
            $node->getStartLine(),
            $args->getEndLine(),
            $node->getStartColumn(),
            $args->getEndColumn()
        );

        return $this->parseOptionalMemberPrimaryPrefix($postfix);
    }

    /**
     * This method parses the arguments passed to a function- or method-call.
     *
     * @return \PDepend\Source\AST\ASTArguments
     * @throws \PDepend\Source\Parser\ParserException
     * @since 0.9.6
     */
    protected function parseArguments()
    {
        $this->consumeComments();

        $this->tokenStack->push();

        $arguments = $this->builder->buildAstArguments();

        $this->consumeToken(Tokens::T_PARENTHESIS_OPEN);
        $this->consumeComments();

        if (Tokens::T_PARENTHESIS_CLOSE !== $this->tokenizer->peek()) {
            $arguments = $this->parseArgumentList($arguments);
        }
        $this->consumeToken(Tokens::T_PARENTHESIS_CLOSE);

        return $this->setNodePositionsAndReturn($arguments);
    }

    /**
     * @param \PDepend\Source\AST\ASTArguments $arguments
     * @return \PDepend\Source\AST\ASTArguments
     */
    protected function parseArgumentList(ASTArguments $arguments)
    {
        return $this->parseExpressionList($arguments);
    }

    /**
     * This method implements the parsing for various expression types like
     * variables, object/static method. All these expressions are valid in
     * several php language constructs like, isset, empty, unset etc.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @since 0.9.12
     */
    protected function parseVariableOrConstantOrPrimaryPrefix()
    {
        $this->consumeComments();
        switch ($this->tokenizer->peek()) {
            case Tokens::T_DOLLAR:
            case Tokens::T_VARIABLE:
                $node = $this->parseVariableOrFunctionPostfixOrMemberPrimaryPrefix();
                break;
            case Tokens::T_SELF:
                $node = $this->parseConstantOrSelfMemberPrimaryPrefix();
                break;
            case Tokens::T_PARENT:
                $node = $this->parseConstantOrParentMemberPrimaryPrefix();
                break;
            case Tokens::T_STATIC:
                $node = $this->parseStaticVariableDeclarationOrMemberPrimaryPrefix();
                break;
            case Tokens::T_STRING:
            case Tokens::T_BACKSLASH:
            case Tokens::T_NAMESPACE:
                $node = $this->parseMemberPrefixOrFunctionPostfix();
                break;
            default:
                $this->throwUnexpectedTokenException();
        }

        return $node;
    }

    /**
     * This method parses any type of variable, function postfix expressions or
     * any kind of member primary prefix.
     *
     * This method expects that the actual token represents any kind of valid
     * php variable: simple variable, compound variable or variable variable.
     *
     * It will parse a function postfix or member primary expression when this
     * variable is followed by an object operator, double colon or opening
     * parenthesis.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\ParserException
     * @since 0.9.6
     */
    private function parseVariableOrFunctionPostfixOrMemberPrimaryPrefix()
    {
        $this->tokenStack->push();

        $variable = $this->parseCompoundVariableOrVariableVariableOrVariable();
        $variable = $this->parseOptionalIndexExpression($variable);

        $this->consumeComments();
        switch ($this->tokenizer->peek()) {
            case Tokens::T_DOUBLE_COLON:
                $result = $this->parseStaticMemberPrimaryPrefix($variable);
                break;
            case Tokens::T_OBJECT_OPERATOR:
                $result = $this->parseMemberPrimaryPrefix($variable);
                break;
            case Tokens::T_PARENTHESIS_OPEN:
                $result = $this->parseFunctionPostfix($variable);
                break;
            default:
                $result = $variable;
                break;
        }
        return $this->setNodePositionsAndReturn($result);
    }

    /**
     * Parses an assingment expression node.
     *
     * @param \PDepend\Source\AST\ASTNode $left The left part of the assignment
     *        expression that will be parsed by this method.
     *
     * @return \PDepend\Source\AST\ASTAssignmentExpression
     * @since 0.9.12
     */
    protected function parseAssignmentExpression(ASTNode $left)
    {
        $token = $this->consumeToken($this->tokenizer->peek());

        $node = $this->builder->buildAstAssignmentExpression($token->image);
        $node->addChild($left);

        // TODO: Change this into a mandatory expression in later versions
        if (($expr = $this->parseOptionalExpression()) != null) {
            $node->addChild($expr);
        } else {
            $expr = $left;
        }

        $node->configureLinesAndColumns(
            $left->getStartLine(),
            $expr->getEndLine(),
            $left->getStartColumn(),
            $expr->getEndColumn()
        );

        return $node;
    }

    /**
     * This method parses a {@link \PDepend\Source\AST\ASTStaticReference} node.
     *
     * @param  \PDepend\Source\Tokenizer\Token $token The "static" keyword token.
     * @return \PDepend\Source\AST\ASTStaticReference
     * @throws \PDepend\Source\Parser\ParserException
     * @throws \PDepend\Source\Parser\InvalidStateException
     * @since 0.9.6
     */
    private function parseStaticReference(Token $token)
    {
        // Strip optional comments
        $this->consumeComments();

        if ($this->classOrInterface === null) {
            throw new InvalidStateException(
                $token->startLine,
                (string) $this->compilationUnit,
                'The keyword "static" was used outside of a class/method scope.'
            );
        }

        $ref = $this->builder->buildAstStaticReference($this->classOrInterface);
        $ref->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );

        return $ref;
    }

    /**
     * This method parses a {@link \PDepend\Source\AST\ASTSelfReference} node.
     *
     * @param  \PDepend\Source\Tokenizer\Token $token The "self" keyword token.
     * @return \PDepend\Source\AST\ASTSelfReference
     * @throws \PDepend\Source\Parser\ParserException
     * @throws \PDepend\Source\Parser\InvalidStateException
     * @since 0.9.6
     */
    protected function parseSelfReference(Token $token)
    {
        if ($this->classOrInterface === null) {
            throw new InvalidStateException(
                $token->startLine,
                (string) $this->compilationUnit,
                'The keyword "self" was used outside of a class/method scope.'
            );
        }

        $ref = $this->builder->buildAstSelfReference($this->classOrInterface);
        $ref->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );

        return $ref;
    }

    /**
     * Parses a simple PHP constant use and returns a corresponding node.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @since 1.0.0
     */
    protected function parseConstant()
    {
        $this->tokenStack->push();
        switch ($type = $this->tokenizer->peek()) {
            case Tokens::T_STRING:
                // TODO: Separate node classes for magic constants
            case Tokens::T_DIR:
            case Tokens::T_FILE:
            case Tokens::T_LINE:
            case Tokens::T_NS_C:
            case Tokens::T_FUNC_C:
            case Tokens::T_CLASS_C:
            case Tokens::T_METHOD_C:
            case Tokens::T_TRAIT_C:
                $token = $this->consumeToken($type);

                return $this->setNodePositionsAndReturn(
                    $this->builder->buildAstConstant($token->image)
                );
                break;
        }
    }

    /**
     * This method parses a {@link \PDepend\Source\AST\ASTConstant} node or
     * an instance of {@link \PDepend\Source\AST\ASTSelfReference} as part of
     * a {@link \PDepend\Source\AST\ASTMemberPrimaryPrefix} that contains the
     * self reference as its first child when the self token is followed by a
     * double colon token.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\ParserException
     * @throws \PDepend\Source\Parser\InvalidStateException
     * @since 0.9.6
     */
    private function parseConstantOrSelfMemberPrimaryPrefix()
    {
        // Read self token and strip optional comments
        $token = $this->consumeToken(Tokens::T_SELF);
        $this->consumeComments();

        if ($this->tokenizer->peek() == Tokens::T_DOUBLE_COLON) {
            return $this->parseStaticMemberPrimaryPrefix(
                $this->parseSelfReference($token)
            );
        }
        return $this->builder->buildAstConstant($token->image);
    }

    /**
     * This method parses a {@link \PDepend\Source\AST\ASTParentReference} node.
     *
     * @param  \PDepend\Source\Tokenizer\Token $token The "self" keyword token.
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\ParserException
     * @throws \PDepend\Source\Parser\InvalidStateException
     * @since 0.9.6
     */
    private function parseParentReference(Token $token)
    {
        if ($this->classOrInterface === null) {
            throw new InvalidStateException(
                $token->startLine,
                (string) $this->compilationUnit,
                'The keyword "parent" was used as type hint but the parameter ' .
                'declaration is not in a class scope.'
            );
        }

        if ($this->classOrInterface instanceof ASTTrait) {
            $classReference = $this->builder->buildAstClassReference('__PDepend_TraitRuntimeReference');
        } else {
            $classReference = $this->classOrInterface->getParentClassReference();
        }

        if ($classReference === null) {
            throw new InvalidStateException(
                $token->startLine,
                (string) $this->compilationUnit,
                sprintf(
                    'The keyword "parent" was used as type hint but the ' .
                    'class "%s" does not declare a parent.',
                    $this->classOrInterface->getName()
                )
            );
        }

        $ref = $this->builder->buildAstParentReference($classReference);
        $ref->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );

        return $ref;
    }

    /**
     * This method parses a {@link \PDepend\Source\AST\ASTConstant} node or
     * an instance of {@link \PDepend\Source\AST\ASTParentReference} as part
     * of a {@link \PDepend\Source\AST\ASTMemberPrimaryPrefix} that contains
     * the parent reference as its first child when the self token is followed
     * by a double colon token.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\ParserException
     * @throws \PDepend\Source\Parser\InvalidStateException
     * @since 0.9.6
     */
    private function parseConstantOrParentMemberPrimaryPrefix()
    {
        // Consume parent token and strip optional comments
        $token = $this->consumeToken(Tokens::T_PARENT);
        $this->consumeComments();

        if ($this->tokenizer->peek() == Tokens::T_DOUBLE_COLON) {
            return $this->parseStaticMemberPrimaryPrefix(
                $this->parseParentReference($token)
            );
        }
        return $this->builder->buildAstConstant($token->image);
    }

    /**
     * Parses a variable or any other valid member expression that is optionally
     * prefixed with PHP's reference operator.
     *
     * <code>
     * //                  -----------
     * foreach ( $array as &$this->foo ) {}
     * //                  -----------
     *
     * //     ----------
     * $foo = &$bar->baz;
     * //     ----------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTUnaryExpression
     * @since 0.9.18
     */
    private function parseVariableOrMemberOptionalByReference()
    {
        $this->consumeComments();
        if ($this->tokenizer->peek() === Tokens::T_BITWISE_AND) {
            return $this->parseVariableOrMemberByReference();
        }
        return $this->parseVariableOrConstantOrPrimaryPrefix();
    }

    /**
     * Parses a variable or any other valid member expression that is prefixed
     * with PHP's reference operator.
     *
     * <code>
     * //                  -----------
     * foreach ( $array as &$this->foo ) {}
     * //                  -----------
     *
     * //     ----------
     * $foo = &$bar->baz;
     * //     ----------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTUnaryExpression
     * @since 0.9.18
     */
    private function parseVariableOrMemberByReference()
    {
        $this->tokenStack->push();

        $token = $this->consumeToken(Tokens::T_BITWISE_AND);
        $this->consumeComments();

        $expr = $this->builder->buildAstUnaryExpression($token->image);
        $expr->addChild($this->parseVariableOrConstantOrPrimaryPrefix());

        return $this->setNodePositionsAndReturn($expr);
    }

    /**
     * This method parses a simple PHP variable.
     *
     * @return \PDepend\Source\AST\ASTVariable
     * @throws UnexpectedTokenException
     * @since 0.9.6
     */
    private function parseVariable()
    {
        $token = $this->consumeToken(Tokens::T_VARIABLE);

        $variable = $this->builder->buildAstVariable($token->image);
        $variable->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );

        return $variable;
    }

    /**
     * This method parses a comma separated list of valid php variables and/or
     * properties and adds them to the given node instance.
     *
     * @param \PDepend\Source\AST\ASTNode $node The context parent node.
     *
     * @return \PDepend\Source\AST\ASTNode The prepared entire node.
     * @since 0.9.12
     */
    private function parseVariableList(ASTNode $node)
    {
        $this->consumeComments();
        while ($this->tokenizer->peek() !== Tokenizer::T_EOF) {
            $node->addChild($this->parseVariableOrConstantOrPrimaryPrefix());

            $this->consumeComments();
            if ($this->tokenizer->peek() === Tokens::T_COMMA) {
                $this->consumeToken(Tokens::T_COMMA);
                $this->consumeComments();
            } else {
                break;
            }
        }

        return $node;
    }

    /**
     * This method is a decision point between the different variable types
     * availanle in PHP. It peeks the next token and then decides whether it is
     * a regular variable or when the next token is of type <b>T_DOLLAR</b> a
     * compound- or variable-variable.
     *
     * <code>
     * ----
     * $foo;
     * ----
     *
     * -----
     * $$foo;
     * -----
     *
     * ------
     * ${FOO};
     * ------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\ParserException
     * @throws UnexpectedTokenException
     * @since 0.9.6
     */
    protected function parseCompoundVariableOrVariableVariableOrVariable()
    {
        if ($this->tokenizer->peek() == Tokens::T_DOLLAR) {
            return $this->parseCompoundVariableOrVariableVariable();
        }
        return $this->parseVariable();
    }

    /**
     * Parses a PHP compound variable or a simple literal node.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @since 0.9.19
     */
    private function parseCompoundVariableOrLiteral()
    {
        $this->tokenStack->push();

        // Read the dollar token
        $token = $this->consumeToken(Tokens::T_DOLLAR);
        $this->consumeComments();

        // Get next token type
        $tokenType = $this->tokenizer->peek();

        switch ($tokenType) {
            case Tokens::T_CURLY_BRACE_OPEN:
                $variable = $this->builder->buildAstCompoundVariable($token->image);
                $variable->addChild($this->parseCompoundExpression());
                break;
            default:
                $variable = $this->builder->buildAstLiteral($token->image);
                break;
        }

        return $this->setNodePositionsAndReturn($variable);
    }

    /**
     * This method implements a decision point between compound-variables and
     * variable-variable. It expects that the next token in the token-stream is
     * of type <b>T_DOLLAR</b> and removes it from the stream. Then this method
     * peeks the next available token when it is of type <b>T_CURLY_BRACE_OPEN</b>
     * this is compound variable, otherwise it can be a variable-variable or a
     * compound-variable.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\ParserException
     * @throws UnexpectedTokenException
     * @since 0.9.6
     */
    private function parseCompoundVariableOrVariableVariable()
    {
        $this->tokenStack->push();

        // Read the dollar token
        $token = $this->consumeToken(Tokens::T_DOLLAR);
        $this->consumeComments();

        // Get next token type
        $tokenType = $this->tokenizer->peek();

        // T_DOLLAR|T_VARIABLE === Variable variable,
        // T_CURLY_BRACE_OPEN === Compound variable
        switch ($tokenType) {
            case Tokens::T_DOLLAR:
            case Tokens::T_VARIABLE:
                $variable = $this->builder->buildAstVariableVariable($token->image);
                $variable->addChild(
                    $this->parseCompoundVariableOrVariableVariableOrVariable()
                );
                break;
            default:
                $variable = $this->parseCompoundVariable($token);
                break;
        }

        return $this->setNodePositionsAndReturn($variable);
    }

    /**
     * This method parses a compound variable like:
     *
     * <code>
     * //     ----------------
     * return ${'Foo' . 'Bar'};
     * //     ----------------
     * </code>
     *
     * @param  \PDepend\Source\Tokenizer\Token $token The dollar token.
     * @return \PDepend\Source\AST\ASTCompoundVariable
     * @since 0.10.0
     */
    private function parseCompoundVariable(Token $token)
    {
        return $this->parseBraceExpression(
            $this->builder->buildAstCompoundVariable($token->image),
            $this->consumeToken(Tokens::T_CURLY_BRACE_OPEN),
            Tokens::T_CURLY_BRACE_CLOSE
        );
    }

    /**
     * This method parses a compound expression like:
     *
     * <code>
     * //      ------  ------
     * $foo = "{$bar}, {$baz}\n";
     * //      ------  ------
     * </code>
     *
     * or a simple literal token:
     *
     * <code>
     * //      -
     * $foo = "{{$bar}, {$baz}\n";
     * //      -
     * </code>
     *
     * @return \PDepend\Source\AST\ASTNode
     * @since 0.9.10
     */
    private function parseCompoundExpressionOrLiteral()
    {
        $token = $this->consumeToken(Tokens::T_CURLY_BRACE_OPEN);
        $this->consumeComments();

        switch ($this->tokenizer->peek()) {
            case Tokens::T_DOLLAR:
            case Tokens::T_VARIABLE:
                return $this->parseBraceExpression(
                    $this->builder->buildAstCompoundExpression(),
                    $token,
                    Tokens::T_CURLY_BRACE_CLOSE
                );
        }

        $literal = $this->builder->buildAstLiteral($token->image);
        $literal->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );

        return $literal;
    }

    /**
     * This method parses a compound expression node.
     *
     * <code>
     * ------------------
     * {'_' . foo . $bar}
     * ------------------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTCompoundExpression
     * @throws \PDepend\Source\Parser\ParserException
     * @throws \PDepend\Source\Parser\ParserException
     * @since 0.9.6
     */
    protected function parseCompoundExpression()
    {
        $this->consumeComments();

        return $this->parseBraceExpression(
            $this->builder->buildAstCompoundExpression(),
            $this->consumeToken(Tokens::T_CURLY_BRACE_OPEN),
            Tokens::T_CURLY_BRACE_CLOSE
        );
    }

    /**
     * Parses a static identifier expression, as it is used for method and
     * function names.
     *
     * @param integer $tokenType
     * @return \PDepend\Source\AST\ASTIdentifier
     * @since 0.9.12
     */
    protected function parseIdentifier($tokenType = Tokens::T_STRING)
    {
        $token = $this->consumeToken($tokenType);

        $node = $this->builder->buildAstIdentifier($token->image);
        $node->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );

        return $node;
    }

    /**
     * This method parses a {@link \PDepend\Source\AST\ASTLiteral} node or an
     * instance of {@link \PDepend\Source\AST\ASTString} that represents a string
     * in double quotes or surrounded by backticks.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @throws UnexpectedTokenException
     */
    protected function parseLiteralOrString()
    {
        $tokenType = $this->tokenizer->peek();

        switch ($tokenType) {
            case Tokens::T_NULL:
            case Tokens::T_TRUE:
            case Tokens::T_FALSE:
            case Tokens::T_DNUMBER:
            case Tokens::T_CONSTANT_ENCAPSED_STRING:
                $token = $this->consumeToken($tokenType);

                $literal = $this->builder->buildAstLiteral($token->image);
                $literal->configureLinesAndColumns(
                    $token->startLine,
                    $token->endLine,
                    $token->startColumn,
                    $token->endColumn
                );
                return $literal;
            case Tokens::T_LNUMBER:
                return $this->parseIntegerNumber();
            default:
                return $this->parseString($tokenType);
        }
    }

    /**
     * Parses an integer value.
     *
     * @return \PDepend\Source\AST\ASTLiteral
     * @since 1.0.0
     */
    protected function parseIntegerNumber()
    {
        $token = $this->consumeToken(Tokens::T_LNUMBER);

        $literal = $this->builder->buildAstLiteral($token->image);
        $literal->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );

        return $literal;
    }

    /**
     * Parses an array structure.
     *
     * @return \PDepend\Source\AST\ASTArray
     * @since 1.0.0
     */
    protected function doParseArray($static = false)
    {
        $this->tokenStack->push();

        return $this->setNodePositionsAndReturn(
            $this->parseArray(
                $this->builder->buildAstArray(),
                $static
            )
        );
    }

    /**
     * Tests if the next token is a valid array start delimiter in the supported
     * PHP version.
     *
     * @return boolean
     * @since 1.0.0
     */
    abstract protected function isArrayStartDelimiter();

    /**
     * Parses a php array declaration.
     *
     * @param \PDepend\Source\AST\ASTArray $array
     * @param boolean                      $static
     *
     * @return \PDepend\Source\AST\ASTArray
     * @since 1.0.0
     */
    abstract protected function parseArray(ASTArray $array, $static = false);

    /**
     * Parses all elements in an array.
     *
     * @param  \PDepend\Source\AST\ASTArray $array
     * @param  integer                      $endDelimiter
     * @param  boolean                      $static
     * @return \PDepend\Source\AST\ASTArray
     * @since 1.0.0
     */
    protected function parseArrayElements(ASTArray $array, $endDelimiter, $static = false)
    {
        $this->consumeComments();
        while ($endDelimiter !== $this->tokenizer->peek()) {
            $array->addChild($this->parseArrayElement($static));

            $this->consumeComments();
            if (Tokens::T_COMMA === $this->tokenizer->peek()) {
                $this->consumeToken(Tokens::T_COMMA);
                $this->consumeComments();
            }
        }
        return $array;
    }

    /**
     * Parses a single array element.
     *
     * An array element can have a simple value, a key/value pair, a value by
     * reference or a key/value pair with a referenced value.
     *
     * @param  boolean $static
     * @return \PDepend\Source\AST\ASTArrayElement
     * @since 1.0.0
     */
    protected function parseArrayElement($static = false)
    {
        $this->consumeComments();

        $this->tokenStack->push();

        $element = $this->builder->buildAstArrayElement();
        if ($this->parseOptionalByReference()) {
            if ($static) {
                $tokens = $this->tokenStack->pop();

                $this->throwUnexpectedTokenException(end($tokens));
            }

            $element->setByReference();
        }

        $this->consumeComments();
        if ($this->isKeyword($this->tokenizer->peek())) {
            $this->throwUnexpectedTokenException();
        }

        $element->addChild($this->parseExpression());

        $this->consumeComments();
        if (Tokens::T_DOUBLE_ARROW === $this->tokenizer->peek()) {
            $this->consumeToken(Tokens::T_DOUBLE_ARROW);
            $this->consumeComments();

            if ($this->parseOptionalByReference()) {
                $element->setByReference();
            }
            $element->addChild($this->parseExpression());
        }

        return $this->setNodePositionsAndReturn($element);
    }

    /**
     * Parses a here- or nowdoc string instance.
     *
     * @return \PDepend\Source\AST\ASTHeredoc
     * @since 0.9.12
     */
    protected function parseHeredoc()
    {
        $this->tokenStack->push();
        $this->consumeToken(Tokens::T_START_HEREDOC);

        $heredoc = $this->builder->buildAstHeredoc();
        $this->parseStringExpressions($heredoc, Tokens::T_END_HEREDOC);

        $token = $this->consumeToken(Tokens::T_END_HEREDOC);
        $heredoc->setDelimiter($token->image);

        return $this->setNodePositionsAndReturn($heredoc);
    }

    /**
     * Parses a simple string sequence between two tokens of the same type.
     *
     * @param integer $tokenType The start/stop token type.
     *
     * @return string
     * @since 0.9.10
     */
    private function parseStringSequence($tokenType)
    {
        $type   = $tokenType;
        $string = '';

        do {
            $string .= $this->consumeToken($type)->image;
            $type    = $this->tokenizer->peek();
        } while ($type != $tokenType && $type != Tokenizer::T_EOF);

        return $string . $this->consumeToken($tokenType)->image;
    }

    /**
     * This method parses a php string with all possible embedded expressions.
     *
     * <code>
     * $string = "Manuel $Pichler <{$email}>";
     *
     * // \PDepend\Source\AST\ASTSTring
     * // |-- ASTLiteral             -  "Manuel ")
     * // |-- ASTVariable            -  $Pichler
     * // |-- ASTLiteral             -  " <"
     * // |-- ASTCompoundExpression  -  {...}
     * // |   |-- ASTVariable        -  $email
     * // |-- ASTLiteral             -  ">"
     * </code>
     *
     * @param integer $delimiterType The start/stop token type.
     *
     * @return \PDepend\Source\AST\ASTString
     * @throws \PDepend\Source\Parser\UnexpectedTokenException
     * @since 0.9.10
     */
    private function parseString($delimiterType)
    {
        $token = $this->consumeToken($delimiterType);

        $string = $this->builder->buildAstString();
        $startLine = $token->startLine;
        $startColumn = $token->startColumn;

        $this->parseStringExpressions($string, $delimiterType);

        $token = $this->consumeToken($delimiterType);
        $endLine = $token->endLine;
        $endColumn = $token->endColumn;

        $string->configureLinesAndColumns(
            $startLine,
            $endLine,
            $startColumn,
            $endColumn
        );

        return $string;
    }

    /**
     * This method parses the contents of a string or here-/now-doc node. It
     * will not consume the given stop token, so it is up to the calling method
     * to consume the stop token. The return value of this method is the prepared
     * input string node.
     *
     * @param  \PDepend\Source\AST\ASTNode $node
     * @param  integer                     $stopToken
     * @return \PDepend\Source\AST\ASTNode
     * @since 0.9.12
     */
    private function parseStringExpressions(ASTNode $node, $stopToken)
    {
        while (($tokenType = $this->tokenizer->peek()) != Tokenizer::T_EOF) {
            switch ($tokenType) {
                case $stopToken:
                    break 2;
                case Tokens::T_BACKSLASH:
                    $node->addChild($this->parseEscapedAstLiteralString());
                    break;
                case Tokens::T_DOLLAR:
                    $node->addChild($this->parseCompoundVariableOrLiteral());
                    break;
                case Tokens::T_VARIABLE:
                    $node->addChild($this->parseVariable());
                    break;
                case Tokens::T_CURLY_BRACE_OPEN:
                    $node->addChild($this->parseCompoundExpressionOrLiteral());
                    break;
                default:
                    $node->addChild($this->parseLiteral());
                    break;
            }
        }
        return $node;
    }

    /**
     * This method parses an escaped sequence of literal tokens.
     *
     * @return \PDepend\Source\AST\ASTLiteral
     * @since 0.9.10
     */
    private function parseEscapedAstLiteralString()
    {
        $this->tokenStack->push();

        $image  = $this->consumeToken(Tokens::T_BACKSLASH)->image;
        $escape = true;

        $tokenType = $this->tokenizer->peek();
        while ($tokenType != Tokenizer::T_EOF) {
            if ($tokenType === Tokens::T_BACKSLASH) {
                $escape != $escape;
                $image  .= $this->consumeToken(Tokens::T_BACKSLASH)->image;

                $tokenType = $this->tokenizer->peek();
                continue;
            }

            if ($escape) {
                $image .= $this->consumeToken($tokenType)->image;
                break;
            }
        }
        return $this->setNodePositionsAndReturn(
            $this->builder->buildAstLiteral($image)
        );
    }

    /**
     * This method parses a simple literal and configures the position
     * properties.
     *
     * @return \PDepend\Source\AST\ASTLiteral
     * @since 0.9.10
     */
    protected function parseLiteral()
    {
        $token = $this->consumeToken($this->tokenizer->peek());

        $node = $this->builder->buildAstLiteral($token->image);
        $node->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );

        return $node;
    }

    /**
     * Extracts all dependencies from a callable signature.
     *
     * @return \PDepend\Source\AST\ASTFormalParameters
     * @since 0.9.5
     */
    private function parseFormalParameters()
    {
        $this->consumeComments();

        $this->tokenStack->push();

        $formalParameters = $this->builder->buildAstFormalParameters();

        $this->consumeToken(Tokens::T_PARENTHESIS_OPEN);
        $this->consumeComments();

        $tokenType = $this->tokenizer->peek();

        // Check for function without parameters
        if ($tokenType === Tokens::T_PARENTHESIS_CLOSE) {
            $this->consumeToken(Tokens::T_PARENTHESIS_CLOSE);
            return $this->setNodePositionsAndReturn($formalParameters);
        }

        while ($tokenType !== Tokenizer::T_EOF) {
            $formalParameters->addChild(
                $this->parseFormalParameterOrTypeHintOrByReference()
            );

            $this->consumeComments();
            $tokenType = $this->tokenizer->peek();

            // Check for following parameter
            if ($tokenType !== Tokens::T_COMMA) {
                break;
            }
            $this->consumeToken(Tokens::T_COMMA);
        }
        $this->consumeToken(Tokens::T_PARENTHESIS_CLOSE);

        return $this->setNodePositionsAndReturn($formalParameters);
    }

    /**
     * This method parses a formal parameter in all it's variations.
     *
     * <code>
     * //                ------------
     * function traverse(Iterator $it) {}
     * //                ------------
     *
     * //                ---------
     * function traverse(array $ar) {}
     * //                ---------
     *
     * //                ---
     * function traverse(&$x) {}
     * //                ---
     * </code>
     *
     * @return \PDepend\Source\AST\ASTFormalParameter
     * @since 0.9.6
     */
    protected function parseFormalParameterOrTypeHintOrByReference()
    {
        $this->consumeComments();
        $tokenType = $this->tokenizer->peek();

        $this->tokenStack->push();

        switch ($tokenType) {
            case Tokens::T_ARRAY:
                $parameter = $this->parseFormalParameterAndArrayTypeHint();
                break;
            case ($this->isTypeHint($tokenType)):
                $parameter = $this->parseFormalParameterAndTypeHint();
                break;
            case Tokens::T_SELF:
                $parameter = $this->parseFormalParameterAndSelfTypeHint();
                break;
            case Tokens::T_PARENT:
                $parameter = $this->parseFormalParameterAndParentTypeHint();
                break;
            case Tokens::T_BITWISE_AND:
                $parameter = $this->parseFormalParameterAndByReference();
                break;
            default:
                $parameter = $this->parseFormalParameter();
                break;
        }
        return $this->setNodePositionsAndReturn($parameter);
    }

    /**
     * This method parses a formal parameter that has an array type hint.
     *
     * <code>
     * //                ---------
     * function traverse(array $ar) {}
     * //                ---------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTFormalParameter
     * @since 0.9.6
     */
    private function parseFormalParameterAndArrayTypeHint()
    {
        $node = $this->parseArrayType();

        $parameter = $this->parseFormalParameterOrByReference();
        $parameter->prependChild($node);

        return $parameter;
    }

    /**
     * @return \PDepend\Source\AST\ASTTypeArray
     */
    protected function parseArrayType()
    {
        $token = $this->consumeToken(Tokens::T_ARRAY);

        $type = $this->builder->buildAstTypeArray();
        $type->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );

        return $type;
    }

    /**
     * This method parses a formal parameter that has a regular class type hint.
     *
     * <code>
     * //                ------------
     * function traverse(Iterator $it) {}
     * //                ------------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTFormalParameter
     * @since 0.9.6
     */
    private function parseFormalParameterAndTypeHint()
    {
        $this->tokenStack->push();

        $classReference = $this->setNodePositionsAndReturn(
            $this->parseTypeHint()
        );

        $parameter = $this->parseFormalParameterOrByReference();
        $parameter->prependChild($classReference);

        return $parameter;
    }

    /**
     * This method will parse a formal parameter that has the keyword parent as
     * parameter type hint.
     *
     * <code>
     * class Foo extends Bar
     * {
     *     //                   ---------
     *     public function test(parent $o) {}
     *     //                   ---------
     * }
     * </code>
     *
     * @return \PDepend\Source\AST\ASTFormalParameter
     * @throws \PDepend\Source\Parser\InvalidStateException
     * @since 0.9.6
     */
    private function parseFormalParameterAndParentTypeHint()
    {
        $reference = $this->parseParentType();
        $parameter = $this->parseFormalParameterOrByReference();
        $parameter->prependChild($reference);

        return $parameter;
    }

    /**
     * @return \PDepend\Source\AST\ASTParentReference
     */
    protected function parseParentType()
    {
        return $this->parseParentReference($this->consumeToken(Tokens::T_PARENT));
    }

    /**
     * This method will parse a formal parameter that has the keyword self as
     * parameter type hint.
     *
     * <code>
     * class Foo
     * {
     *     //                   -------
     *     public function test(self $o) {}
     *     //                   -------
     * }
     * </code>
     *
     * @return \PDepend\Source\AST\ASTFormalParameter
     * @since 0.9.6
     */
    private function parseFormalParameterAndSelfTypeHint()
    {
        $self = $this->parseSelfType();

        $parameter = $this->parseFormalParameterOrByReference();
        $parameter->addChild($self);

        return $parameter;
    }

    /**
     * @return \PDepend\Source\AST\ASTSelfReference
     */
    protected function parseSelfType()
    {
        return $this->parseSelfReference($this->consumeToken(Tokens::T_SELF));
    }

    /**
     * This method will parse a formal parameter that can optionally be passed
     * by reference.
     *
     * <code>
     * //                 ---  -------
     * function foo(array &$x, $y = 42) {}
     * //                 ---  -------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTFormalParameter
     * @since 0.9.6
     */
    protected function parseFormalParameterOrByReference()
    {
        $this->consumeComments();
        if ($this->tokenizer->peek() === Tokens::T_BITWISE_AND) {
            return $this->parseFormalParameterAndByReference();
        }
        return $this->parseFormalParameter();
    }

    /**
     * This method will parse a formal parameter that is passed by reference.
     *
     * <code>
     * //                 ---  --------
     * function foo(array &$x, &$y = 42) {}
     * //                 ---  --------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTFormalParameter
     * @since 0.9.6
     */
    private function parseFormalParameterAndByReference()
    {
        $this->consumeToken(Tokens::T_BITWISE_AND);
        $this->consumeComments();

        $parameter = $this->parseFormalParameter();
        $parameter->setPassedByReference();

        return $parameter;
    }

    /**
     * This method will parse a formal parameter. A formal parameter is at least
     * a variable name, but can also contain a default parameter value.
     *
     * <code>
     * //               --  -------
     * function foo(Bar $x, $y = 42) {}
     * //               --  -------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTFormalParameter
     * @since 0.9.6
     */
    protected function parseFormalParameter()
    {
        $parameter = $this->builder->buildAstFormalParameter();
        $parameter->addChild($this->parseVariableDeclarator());

        return $parameter;
    }

    /**
     * Tests if the given token type is a valid formal parameter in the supported
     * PHP version.
     *
     * @param integer $tokenType
     * @return boolean
     * @since 1.0.0
     */
    protected function isTypeHint($tokenType)
    {
        switch ($tokenType) {
            case Tokens::T_STRING:
            case Tokens::T_BACKSLASH:
            case Tokens::T_NAMESPACE:
                return true;
        }
        return false;
    }

    /**
     * Parses a type hint that is valid in the supported PHP version.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @since 1.0.0
     */
    protected function parseTypeHint()
    {
        switch ($this->tokenizer->peek()) {
            case Tokens::T_STRING:
            case Tokens::T_BACKSLASH:
            case Tokens::T_NAMESPACE:
                $type = $this->builder->buildAstClassOrInterfaceReference(
                    $this->parseQualifiedName()
                );
                break;
        }
        return $type;
    }

    /**
     * Extracts all dependencies from a callable body.
     *
     * @return \PDepend\Source\AST\ASTScope
     * @since 0.9.12
     */
    private function parseScope()
    {
        $scope = $this->builder->buildAstScope();

        $this->tokenStack->push();

        $this->consumeComments();
        $this->consumeToken(Tokens::T_CURLY_BRACE_OPEN);

        while (($stmt = $this->parseOptionalStatement()) !== null) {
            // TODO: Remove if-statement once, we have translated functions and
            //       closures into ast-nodes
            if ($stmt instanceof \PDepend\Source\AST\ASTNode) {
                $scope->addChild($stmt);
            }
        }

        $this->consumeComments();
        $this->consumeToken(Tokens::T_CURLY_BRACE_CLOSE);

        return $this->setNodePositionsAndReturn($scope);
    }

    /**
     * Parse a statement.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\UnexpectedTokenException
     * @throws \PDepend\Source\Parser\TokenStreamEndException
     * @since 1.0.0
     */
    private function parseStatement()
    {
        if (is_object($stmt = $this->parseOptionalStatement())) {
            return $stmt;
        }
        if (is_object($token = $this->tokenizer->next())) {
            $this->throwUnexpectedTokenException($token);
        }
        throw new TokenStreamEndException($this->compilationUnit->getFileName());
    }

    /**
     * Parses an optional statement or returns <b>null</b>.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @since 0.9.8
     */
    private function parseOptionalStatement()
    {
        $tokenType = $this->tokenizer->peek();

        switch ($tokenType) {
            case Tokens::T_ECHO:
                return $this->parseEchoStatement();
            case Tokens::T_SWITCH:
                return $this->parseSwitchStatement();
            case Tokens::T_TRY:
                return $this->parseTryStatement();
            case Tokens::T_THROW:
                return $this->parseThrowStatement();
            case Tokens::T_IF:
                return $this->parseIfStatement();
            case Tokens::T_FOR:
                return $this->parseForStatement();
            case Tokens::T_FOREACH:
                return $this->parseForeachStatement();
            case Tokens::T_DO:
                return $this->parseDoWhileStatement();
            case Tokens::T_WHILE:
                return $this->parseWhileStatement();
            case Tokens::T_RETURN:
                return $this->parseReturnStatement();
            case Tokens::T_BREAK:
                return $this->parseBreakStatement();
            case Tokens::T_CONTINUE:
                return $this->parseContinueStatement();
            case Tokens::T_GOTO:
                return $this->parseGotoStatement();
            case Tokens::T_GLOBAL:
                return $this->parseGlobalStatement();
            case Tokens::T_UNSET:
                return $this->parseUnsetStatement();
            case Tokens::T_STRING:
                if ($this->tokenizer->peekNext() === Tokens::T_COLON) {
                    return $this->parseLabelStatement();
                }
                break;
            case Tokens::T_CONST:
                return $this->parseConstantDefinition();
            case Tokens::T_FUNCTION:
                return $this->parseFunctionOrClosureDeclaration();
            case Tokens::T_COMMENT:
                return $this->parseCommentWithOptionalInlineClassOrInterfaceReference();
            case Tokens::T_DOC_COMMENT:
                return $this->builder->buildAstComment(
                    $this->consumeToken(Tokens::T_DOC_COMMENT)->image
                );
            case Tokens::T_CURLY_BRACE_OPEN:
                return $this->parseRegularScope();
            case Tokens::T_DECLARE:
                return $this->parseDeclareStatement();
            case Tokens::T_ELSE:
            case Tokens::T_ENDIF:
            case Tokens::T_ELSEIF:
            case Tokens::T_ENDFOR:
            case Tokens::T_ENDWHILE:
            case Tokens::T_ENDSWITCH:
            case Tokens::T_ENDDECLARE:
            case Tokens::T_ENDFOREACH:
            case Tokens::T_CURLY_BRACE_CLOSE:
                return null;
            case Tokens::T_DECLARE:
                return $this->parseDeclareStatement();
            case Tokens::T_CLOSE_TAG:
                if (($tokenType = $this->parseNonePhpCode()) === Tokenizer::T_EOF) {
                    return null;
                }

                return $this->parseOptionalStatement();
            case Tokens::T_TRAIT:
                $package = $this->getNamespaceOrPackage();
                $package->addType($trait = $this->parseTraitDeclaration());

                $this->builder->restoreTrait($trait);
                $this->compilationUnit->addChild($trait);

                return $trait;
            case Tokens::T_INTERFACE:
                $package = $this->getNamespaceOrPackage();
                $package->addType($interface = $this->parseInterfaceDeclaration());

                $this->builder->restoreInterface($interface);
                $this->compilationUnit->addChild($interface);

                return $interface;
            case Tokens::T_CLASS:
            case Tokens::T_FINAL:
            case Tokens::T_ABSTRACT:
                $package = $this->getNamespaceOrPackage();
                $package->addType($class = $this->parseClassDeclaration());

                $this->builder->restoreClass($class);
                $this->compilationUnit->addChild($class);

                return $class;
            case Tokens::T_YIELD:
                return $this->parseYield();
        }

        $this->tokenStack->push();
        $stmt = $this->builder->buildAstStatement();

        if (($expr = $this->parseOptionalExpression()) != null) {
            $stmt->addChild($expr);
        }
        $this->parseStatementTermination();

        return $this->setNodePositionsAndReturn($stmt);
    }

    /**
     * Parses a sequence of none php code tokens and returns the token type of
     * the next token.
     *
     * @return integer
     * @since 0.9.12
     */
    private function parseNonePhpCode()
    {
        $this->consumeToken(Tokens::T_CLOSE_TAG);

        $this->tokenStack->push();
        while (($tokenType = $this->tokenizer->peek()) !== Tokenizer::T_EOF) {
            switch ($tokenType) {
                case Tokens::T_OPEN_TAG:
                case Tokens::T_OPEN_TAG_WITH_ECHO:
                    $this->consumeToken($tokenType);
                    $tokenType = $this->tokenizer->peek();
                    break 2;
                default:
                    $this->consumeToken($tokenType);
                    break;
            }
        }
        $this->tokenStack->pop();

        return $tokenType;
    }

    /**
     * Parses a comment and optionally an embedded class or interface type
     * annotation.
     *
     * @return \PDepend\Source\AST\ASTComment
     * @since 0.9.8
     */
    private function parseCommentWithOptionalInlineClassOrInterfaceReference()
    {
        $token = $this->consumeToken(Tokens::T_COMMENT);

        $comment = $this->builder->buildAstComment($token->image);
        if (preg_match(self::REGEXP_INLINE_TYPE, $token->image, $match)) {
            $image = $this->useSymbolTable->lookup($match[1]) ?: $match[1];

            $comment->addChild(
                $this->builder->buildAstClassOrInterfaceReference($image)
            );
        }

        $comment->configureLinesAndColumns(
            $token->startLine,
            $token->endLine,
            $token->startColumn,
            $token->endColumn
        );
        return $comment;
    }

    /**
     * Parses an optional set of bound closure variables.
     *
     * @param \PDepend\Source\AST\ASTClosure $closure The context closure instance.
     *
     * @return \PDepend\Source\AST\ASTClosure
     * @since 1.0.0
     */
    private function parseOptionalBoundVariables(
        \PDepend\Source\AST\ASTClosure $closure
    ) {
        $this->consumeComments();
        if (Tokens::T_USE === $this->tokenizer->peek()) {
            return $this->parseBoundVariables($closure);
        }
        return $closure;
    }

    /**
     * Parses a list of bound closure variables.
     *
     * @param \PDepend\Source\AST\ASTClosure $closure The parent closure instance.
     *
     * @return \PDepend\Source\AST\ASTClosure
     * @since 0.9.5
     */
    private function parseBoundVariables(\PDepend\Source\AST\ASTClosure $closure)
    {
        $this->consumeToken(Tokens::T_USE);

        $this->consumeComments();
        $this->consumeToken(Tokens::T_PARENTHESIS_OPEN);

        while ($this->tokenizer->peek() !== Tokenizer::T_EOF) {
            $this->consumeComments();

            if ($this->tokenizer->peek() === Tokens::T_BITWISE_AND) {
                $this->consumeToken(Tokens::T_BITWISE_AND);
                $this->consumeComments();
            }

            $this->consumeToken(Tokens::T_VARIABLE);
            $this->consumeComments();

            if ($this->tokenizer->peek() === Tokens::T_COMMA) {
                $this->consumeToken(Tokens::T_COMMA);
                continue;
            }
            break;
        }

        $this->consumeComments();
        $this->consumeToken(Tokens::T_PARENTHESIS_CLOSE);

        return $closure;
    }

    /**
     * Parses a php class/method name chain.
     *
     * <code>
     * PDepend\Source\Parser::parse();
     * </code>
     *
     * @throws NoActiveScopeException
     *
     * @return string
     * @link   http://php.net/manual/en/language.namespaces.importing.php
     */
    protected function parseQualifiedName()
    {
        $fragments = $this->parseQualifiedNameRaw();

        // Check for fully qualified name
        if ($fragments[0] === '\\') {
            return join('', $fragments);
        } else {
            switch (strtolower($fragments[0])) {
                case 'int':
                case 'bool':
                case 'float':
                case 'string':
                case 'callable':
                    return $fragments[0];
            }
        }

        // Search for an use alias
        $mapsTo = $this->useSymbolTable->lookup($fragments[0]);
        if ($mapsTo !== null) {
            // Remove alias and add real namespace
            array_shift($fragments);
            array_unshift($fragments, $mapsTo);
        } elseif ($this->namespaceName !== null
            && $this->namespacePrefixReplaced === false
        ) {
            // Prepend current namespace
            array_unshift($fragments, $this->namespaceName, '\\');
        }
        return join('', $fragments);
    }

    /**
     * This method parses a qualified PHP 5.3 class, interface and namespace
     * identifier and returns the collected tokens as a string array.
     *
     * @return array(string)
     * @since 0.9.5
     */
    protected function parseQualifiedNameRaw()
    {
        // Reset namespace prefix flag
        $this->namespacePrefixReplaced = false;

        // Consume comments and fetch first token type
        $this->consumeComments();
        $tokenType = $this->tokenizer->peek();

        $qualifiedName = array();

        if ($tokenType === Tokens::T_NAMESPACE) {
            // Consume namespace keyword
            $this->consumeToken(Tokens::T_NAMESPACE);
            $this->consumeComments();

            // Add current namespace as first token
            $qualifiedName = array((string) $this->namespaceName);

            // Set prefixed flag to true
            $this->namespacePrefixReplaced = true;
        } elseif ($this->isClassName($tokenType)) {
            $qualifiedName[] = $this->parseClassName();

            $this->consumeComments();
            $tokenType = $this->tokenizer->peek();

            // Stop here for simple identifier
            if ($tokenType !== Tokens::T_BACKSLASH) {
                return $qualifiedName;
            }
        }

        do {
            // Next token must be a namespace separator
            $this->consumeToken(Tokens::T_BACKSLASH);
            $this->consumeComments();

            // Append to qualified name
            $qualifiedName[] = '\\';

            if ($nextElement = $this->parseQualifiedNameElement($qualifiedName)) {
                $qualifiedName[] = $nextElement;
            }

            $this->consumeComments();

            // Get next token type
            $tokenType = $this->tokenizer->peek();
        } while ($tokenType === Tokens::T_BACKSLASH);

        return $qualifiedName;
    }

    /**
     * @param array $previousElements
     * @return string
     */
    protected function parseQualifiedNameElement(array $previousElements)
    {
        return $this->parseClassName();
    }

    /**
     * This method parses a PHP 5.3 namespace declaration.
     *
     * @throws NoActiveScopeException
     *
     * @return void
     * @since 0.9.5
     */
    private function parseNamespaceDeclaration()
    {
        // Consume namespace keyword and strip optional comments
        $this->consumeToken(Tokens::T_NAMESPACE);
        $this->consumeComments();

        $tokenType = $this->tokenizer->peek();

        // Search for a namespace identifier
        if ($this->isClassName($tokenType)) {
            // Reset namespace property
            $this->namespaceName = null;

            $qualifiedName = $this->parseQualifiedName();

            $this->consumeComments();
            if ($this->tokenizer->peek() === Tokens::T_CURLY_BRACE_OPEN) {
                $this->consumeToken(Tokens::T_CURLY_BRACE_OPEN);
            } else {
                $this->consumeToken(Tokens::T_SEMICOLON);
            }

            // Create a package for this namespace
            $this->namespaceName = $qualifiedName;

            $this->useSymbolTable->resetScope();

        } elseif ($tokenType === Tokens::T_BACKSLASH) {
            // Same namespace reference, something like:
            //   new namespace\Foo();
            // or:
            //   $x = namespace\foo::bar();

            // Now parse a qualified name
            $this->parseQualifiedNameRaw();
        } else {
            // Consume opening curly brace
            $this->consumeToken(Tokens::T_CURLY_BRACE_OPEN);

            // Create a package for this namespace
            $this->namespaceName = '';

            $this->useSymbolTable->resetScope();
        }

        $this->reset();
    }

    /**
     * This method parses a list of PHP 5.3 use declarations and adds a mapping
     * between short name and full qualified name to the use symbol table.
     *
     * <code>
     * use \foo\bar as fb,
     *     \foobar\Bar;
     * </code>
     *
     * @return void
     * @since 0.9.5
     */
    protected function parseUseDeclarations()
    {
        // Consume use keyword
        $this->consumeToken(Tokens::T_USE);
        $this->consumeComments();

        // Parse all use declarations
        $this->parseUseDeclaration();
        $this->consumeComments();

        // Consume closing semicolon
        $this->consumeToken(Tokens::T_SEMICOLON);

        // Reset any previous state
        $this->reset();
    }

    /**
     * This method parses a single use declaration and adds a mapping between
     * short name and full qualified name to the use symbol table.
     *
     * @throws NoActiveScopeException
     *
     * @return void
     * @since 0.9.5
     */
    protected function parseUseDeclaration()
    {
        $fragments = $this->parseQualifiedNameRaw();
        $this->consumeComments();

        // Add leading backslash, because aliases must be full qualified
        // http://php.net/manual/en/language.namespaces.importing.php
        if ($fragments[0] !== '\\') {
            array_unshift($fragments, '\\');
        }

        $this->parseUseDeclarationForVersion($fragments);

        // Check for a following use declaration
        if ($this->tokenizer->peek() === Tokens::T_COMMA) {
            // Consume comma token and comments
            $this->consumeToken(Tokens::T_COMMA);
            $this->consumeComments();

            $this->parseUseDeclaration();
        }
    }

    /**
     * @param array $fragments
     * @return void
     */
    protected function parseUseDeclarationForVersion(array $fragments)
    {
        $image = $this->parseNamespaceImage($fragments);

        // Add mapping between image and qualified name to symbol table
        $this->useSymbolTable->add($image, join('', $fragments));
    }

    /**
     * @param array $fragments
     * @return string
     */
    protected function parseNamespaceImage(array $fragments)
    {
        if ($this->tokenizer->peek() === Tokens::T_AS) {
            $this->consumeToken(Tokens::T_AS);
            $this->consumeComments();

            $image = $this->consumeToken(Tokens::T_STRING)->image;
            $this->consumeComments();
        } else {
            $image = end($fragments);
        }
        return $image;
    }

    /**
     * Parses a single constant definition with one or more constant declarators.
     *
     * <code>
     * class Foo
     * {
     * //  ------------------------
     *     const FOO = 42, BAR = 23;
     * //  ------------------------
     * }
     * </code>
     *
     * @return \PDepend\Source\AST\ASTConstantDefinition
     * @since 0.9.6
     */
    private function parseConstantDefinition()
    {
        $this->tokenStack->push();

        $token = $this->consumeToken(Tokens::T_CONST);

        $definition = $this->builder->buildAstConstantDefinition($token->image);
        $definition->setComment($this->docComment);

        do {
            $definition->addChild($this->parseConstantDeclarator());

            $this->consumeComments();
            $tokenType = $this->tokenizer->peek();

            if ($tokenType === Tokens::T_SEMICOLON) {
                break;
            }
            $this->consumeToken(Tokens::T_COMMA);
        } while ($tokenType !== Tokenizer::T_EOF);


        $definition = $this->setNodePositionsAndReturn($definition);

        $this->consumeToken(Tokens::T_SEMICOLON);

        return $definition;
    }

    /**
     * Parses a single constant declarator.
     *
     * <code>
     * class Foo
     * {
     *     //    --------
     *     const BAR = 42;
     *     //    --------
     * }
     * </code>
     *
     * Or in a comma separated constant defintion:
     *
     * <code>
     * class Foo
     * {
     *     //    --------
     *     const BAR = 42,
     *     //    --------
     *
     *     //    --------------
     *     const BAZ = 'Foobar',
     *     //    --------------
     *
     *     //    ----------
     *     const FOO = 3.14;
     *     //    ----------
     * }
     * </code>
     *
     * @return \PDepend\Source\AST\ASTConstantDeclarator
     * @since 0.9.6
     */
    protected function parseConstantDeclarator()
    {
        // Remove leading comments and create a new token stack
        $this->consumeComments();
        $this->tokenStack->push();

        $tokenType = $this->tokenizer->peek();
        if (false === $this->isConstantName($tokenType)) {
            $this->throwUnexpectedTokenException();
        }

        $token = $this->consumeToken($tokenType);

        $this->consumeComments();
        $this->consumeToken(Tokens::T_EQUAL);

        $declarator = $this->builder->buildAstConstantDeclarator($token->image);
        $declarator->setValue($this->parseConstantDeclaratorValue());

        return $this->setNodePositionsAndReturn($declarator);
    }

    /**
     * Parses the value of a php constant. By default this can be only static
     * values that were allowed in the oldest supported PHP version.
     *
     * @return \PDepend\Source\AST\ASTValue
     * @since 2.2.x
     */
    protected function parseConstantDeclaratorValue()
    {
        return $this->parseStaticValue();
    }

    /**
     * This method parses a static variable declaration list, a member primary
     * prefix invoked in the static context of a class or it parses a static
     * closure declaration.
     *
     * Static variable:
     * <code>
     * function foo() {
     * //  ------------------------------
     *     static $foo, $bar, $baz = null;
     * //  ------------------------------
     * }
     * </code>
     *
     * Static method invocation:
     * <code>
     * class Foo {
     *     public function baz() {
     * //      ----------------
     *         static::foobar();
     * //      ----------------
     *     }
     *     public function foobar() {}
     * }
     *
     * class Bar extends Foo {
     *     public function foobar() {}
     * }
     * </code>
     *
     * Static closure declaration:
     * <code>
     * $closure = static function($x, $y) {
     *     return ($x * $y);
     * };
     * </code>
     *
     * @return \PDepend\Source\AST\ASTConstant
     * @throws \PDepend\Source\Parser\ParserException
     * @throws \PDepend\Source\Parser\UnexpectedTokenException
     * @since 0.9.6
     */
    private function parseStaticVariableDeclarationOrMemberPrimaryPrefix()
    {
        $this->tokenStack->push();

        // Consume static token and strip optional comments
        $token = $this->consumeToken(Tokens::T_STATIC);
        $this->consumeComments();

        // Fetch next token type
        $tokenType = $this->tokenizer->peek();

        if ($tokenType === Tokens::T_PARENTHESIS_OPEN
            || $tokenType === Tokens::T_DOUBLE_COLON
        ) {
            $static = $this->parseStaticReference($token);

            $prefix = $this->parseStaticMemberPrimaryPrefix($static);
            return $this->setNodePositionsAndReturn($prefix);
        } elseif ($tokenType === Tokens::T_FUNCTION) {
            $closure = $this->parseClosureDeclaration();
            $closure->setStatic(true);

            return $this->setNodePositionsAndReturn($closure);
        }

        $declaration = $this->parseStaticVariableDeclaration($token);
        return $this->setNodePositionsAndReturn($declaration);

    }

    /**
     * This method will parse a static variable declaration.
     *
     * <code>
     * function foo()
     * {
     *     // First declaration
     *     static $foo;
     *     // Second declaration
     *     static $bar = array();
     *     // Third declaration
     *     static $baz    = array(),
     *            $foobar = null,
     *            $barbaz;
     * }
     * </code>
     *
     * @param  \PDepend\Source\Tokenizer\Token $token Token with the "static" keyword.
     * @return \PDepend\Source\AST\ASTStaticVariableDeclaration
     * @since 0.9.6
     */
    private function parseStaticVariableDeclaration(Token $token)
    {
        $staticDeclaration = $this->builder->buildAstStaticVariableDeclaration(
            $token->image
        );

        // Strip optional comments
        $this->consumeComments();

        // Fetch next token type
        $tokenType = $this->tokenizer->peek();

        while ($tokenType !== Tokenizer::T_EOF) {
            $staticDeclaration->addChild($this->parseVariableDeclarator());

            $this->consumeComments();

            // Semicolon terminates static declaration
            $tokenType = $this->tokenizer->peek();
            if ($tokenType === Tokens::T_SEMICOLON) {
                break;
            }
            // We are here, so there must be a next declarator
            $this->consumeToken(Tokens::T_COMMA);
        }

        return $staticDeclaration;
    }

    /**
     * This method will parse a variable declarator.
     *
     * <code>
     * // Parameter declarator
     * function foo($x = 23) {
     * }
     * // Property declarator
     * class Foo{
     *     protected $bar = 42;
     * }
     * // Static declarator
     * function baz() {
     *     static $foo;
     * }
     * </code>
     *
     * @return \PDepend\Source\AST\ASTVariableDeclarator
     * @since 0.9.6
     */
    protected function parseVariableDeclarator()
    {
        $this->tokenStack->push();

        $name = $this->consumeToken(Tokens::T_VARIABLE)->image;
        $this->consumeComments();

        $declarator = $this->builder->buildAstVariableDeclarator($name);

        if ($this->tokenizer->peek() === Tokens::T_EQUAL) {
            $this->consumeToken(Tokens::T_EQUAL);
            $declarator->setValue($this->parseStaticValueOrStaticArray());
        }
        return $this->setNodePositionsAndReturn($declarator);
    }

    /**
     * This method will parse a static value or a static array as it is
     * used as default value for a parameter or property declaration.
     *
     * @return \PDepend\Source\AST\ASTValue
     * @since 0.9.6
     */
    protected function parseStaticValueOrStaticArray()
    {
        $this->consumeComments();
        if ($this->isArrayStartDelimiter()) {
            // TODO: Use default value as value!
            $defaultValue = $this->doParseArray(true);

            $value = new ASTValue();
            $value->setValue(array());

            return $value;
        }
        return $this->parseStaticValue();
    }

    /**
     * This method will parse a static default value as it is used for a
     * parameter, property or constant declaration.
     *
     * @return \PDepend\Source\AST\ASTValue
     * @since 0.9.5
     */
    protected function parseStaticValue()
    {
        $defaultValue = new ASTValue();

        $this->consumeComments();

        // By default all parameters positive signed
        $signed = 1;

        $tokenType = $this->tokenizer->peek();
        while ($tokenType !== Tokenizer::T_EOF) {
            switch ($tokenType) {
                case Tokens::T_COMMA:
                case Tokens::T_SEMICOLON:
                case Tokens::T_PARENTHESIS_CLOSE:
                    if ($defaultValue->isValueAvailable() === true) {
                        return $defaultValue;
                    }
                    throw new MissingValueException($this->tokenizer);
                case Tokens::T_NULL:
                    $this->consumeToken(Tokens::T_NULL);
                    $defaultValue->setValue(null);
                    break;
                case Tokens::T_TRUE:
                    $this->consumeToken(Tokens::T_TRUE);
                    $defaultValue->setValue(true);
                    break;
                case Tokens::T_FALSE:
                    $this->consumeToken(Tokens::T_FALSE);
                    $defaultValue->setValue(false);
                    break;
                case Tokens::T_LNUMBER:
                    $token = $this->consumeToken(Tokens::T_LNUMBER);
                    $defaultValue->setValue($signed * (int) $token->image);
                    break;
                case Tokens::T_DNUMBER:
                    $token = $this->consumeToken(Tokens::T_DNUMBER);
                    $defaultValue->setValue($signed * (double) $token->image);
                    break;
                case Tokens::T_CONSTANT_ENCAPSED_STRING:
                    $token = $this->consumeToken(Tokens::T_CONSTANT_ENCAPSED_STRING);
                    $defaultValue->setValue(substr($token->image, 1, -1));
                    break;
                case Tokens::T_DOUBLE_COLON:
                    $this->consumeToken(Tokens::T_DOUBLE_COLON);
                    break;
                case Tokens::T_CLASS_FQN:
                    $this->consumeToken(Tokens::T_CLASS_FQN);
                    break;
                case Tokens::T_PLUS:
                    $this->consumeToken(Tokens::T_PLUS);
                    break;
                case Tokens::T_MINUS:
                    $this->consumeToken(Tokens::T_MINUS);
                    $signed *= -1;
                    break;
                case Tokens::T_DOUBLE_QUOTE:
                    $defaultValue->setValue($this->parseStringSequence($tokenType));
                    break;
                case Tokens::T_DIR:
                case Tokens::T_FILE:
                case Tokens::T_LINE:
                case Tokens::T_SELF:
                case Tokens::T_NS_C:
                case Tokens::T_FUNC_C:
                case Tokens::T_PARENT:
                case Tokens::T_STRING:
                case Tokens::T_STATIC:
                case Tokens::T_CLASS_C:
                case Tokens::T_METHOD_C:
                case Tokens::T_BACKSLASH:
                case Tokens::T_SQUARED_BRACKET_OPEN:
                case Tokens::T_SQUARED_BRACKET_CLOSE:
                    // There is a default value but we don't handle it at the moment.
                    $defaultValue->setValue(null);
                    $this->consumeToken($tokenType);
                    break;
                case Tokens::T_START_HEREDOC:
                    $defaultValue->setValue(
                        $this->parseHeredoc()->getChild(0)->getImage()
                    );
                    break;
                default:
                    return $this->parseStaticValueVersionSpecific($defaultValue);
            }

            $this->consumeComments();

            $tokenType = $this->tokenizer->peek();
        }

        // We should never reach this, so throw an exception
        throw new TokenStreamEndException($this->tokenizer);
    }

    /**
     * Parses additional static values that are valid in the supported php version.
     *
     * @param  \PDepend\Source\AST\ASTValue $value
     * @return \PDepend\Source\AST\ASTValue
     * @throws \PDepend\Source\Parser\UnexpectedTokenException
     */
    protected function parseStaticValueVersionSpecific(ASTValue $value)
    {
        $this->throwUnexpectedTokenException();
    }

    /**
     * Checks if the given expression is a read/write variable as defined in
     * the PHP zend_language_parser.y definition.
     *
     * @param \PDepend\Source\AST\ASTNode $expr The context node instance.
     *
     * @return boolean
     * @since 0.10.0
     */
    private function isReadWriteVariable($expr)
    {
        return ($expr instanceof \PDepend\Source\AST\ASTVariable
            || $expr instanceof \PDepend\Source\AST\ASTFunctionPostfix
            || $expr instanceof \PDepend\Source\AST\ASTVariableVariable
            || $expr instanceof \PDepend\Source\AST\ASTCompoundVariable
            || $expr instanceof \PDepend\Source\AST\ASTMemberPrimaryPrefix);
    }

    /**
     * This method creates a qualified class or interface name based on the
     * current parser state. By default method uses the current namespace scope
     * as prefix for the given local name. And it will fallback to a previously
     * parsed package annotation, when no namespace declaration was parsed.
     *
     * @param string $localName The local class or interface name.
     *
     * @return string
     */
    private function createQualifiedTypeName($localName)
    {
        return ltrim($this->getNamespaceOrPackageName() . '\\' . $localName, '\\');
    }

    /**
     * Returns the name of a declared names. When the parsed code is not namespaced
     * this method will return the name from the @package annotation.
     *
     * @return string
     * @since 0.9.8
     */
    private function getNamespaceOrPackageName()
    {
        if ($this->namespaceName === null) {
            return $this->packageName;
        }
        return $this->namespaceName;
    }

    /**
     * Returns the currently active package or namespace.
     *
     * @return \PDepend\Source\AST\ASTNamespace
     * @since 1.0.0
     */
    private function getNamespaceOrPackage()
    {
        $namespace = $this->builder->buildNamespace($this->getNamespaceOrPackageName());
        $namespace->setPackageAnnotation(null === $this->namespaceName);

        return $namespace;
    }

    /**
     * Extracts the @package information from the given comment.
     *
     * @param string $comment
     * @return string
     */
    private function parsePackageAnnotation($comment)
    {
        if (getenv('DISMISS_PACKAGES')) {
            $this->packageName = null;
            $this->globalPackageName = null;

            return;
        }

        $package = Builder::DEFAULT_NAMESPACE;
        if (preg_match('#\*\s*@package\s+(\S+)#', $comment, $match)) {
            $package = trim($match[1]);
            if (preg_match('#\*\s*@subpackage\s+(\S+)#', $comment, $match)) {
                $package .= '\\' . trim($match[1]);
            }
        }

        // Check for doc level comment
        if ($this->globalPackageName === Builder::DEFAULT_NAMESPACE
            && $this->isFileComment() === true
        ) {
            $this->globalPackageName = $package;

            $this->compilationUnit->setComment($comment);
        }
        return $package;
    }

    /**
     * Checks that the current token could be used as file comment.
     *
     * This method checks that the previous token is an open tag and the following
     * token is not a class, a interface, final, abstract or a function.
     *
     * @return boolean
     */
    protected function isFileComment()
    {
        if ($this->tokenizer->prev() !== Tokens::T_OPEN_TAG) {
            return false;
        }

        $notExpectedTags = array(
            Tokens::T_CLASS,
            Tokens::T_FINAL,
            Tokens::T_TRAIT,
            Tokens::T_ABSTRACT,
            Tokens::T_FUNCTION,
            Tokens::T_INTERFACE
        );

        return !in_array($this->tokenizer->peek(), $notExpectedTags, true);
    }

    /**
     * Returns the class names of all <b>throws</b> annotations with in the
     * given comment block.
     *
     * @param string $comment The context doc comment block.
     *
     * @return array
     */
    private function parseThrowsAnnotations($comment)
    {
        $throws = array();
        if (preg_match_all(self::REGEXP_THROWS_TYPE, $comment, $matches) > 0) {
            foreach ($matches[1] as $match) {
                $throws[] = $this->useSymbolTable->lookup($match) ?: $match;
            }
        }
        return $throws;
    }

    /**
     * This method parses the given doc comment text for a return annotation and
     * it returns the found return type.
     *
     * @param string $comment A doc comment text.
     *
     * @return string
     */
    private function parseReturnAnnotation($comment)
    {
        if (0 === preg_match(self::REGEXP_RETURN_TYPE, $comment, $match)) {
            return null;
        }

        foreach (explode('|', end($match)) as $image) {
            $image = $this->useSymbolTable->lookup($image) ?: $image;

            if (Type::isScalarType($image)) {
                continue;
            }

            return $image;
        }
        return null;
    }

    /**
     * This method parses the given doc comment text for a var annotation and
     * it returns the found property types.
     *
     * @param  string $comment A doc comment text.
     * @return array(string)
     */
    private function parseVarAnnotation($comment)
    {
        if (preg_match(self::REGEXP_VAR_TYPE, $comment, $match) > 0) {
            $useSymbolTable = $this->useSymbolTable;

            return array_map(
                function ($image) use ($useSymbolTable) {
                    return $useSymbolTable->lookup($image) ?: $image;
                },
                array_map('trim', explode('|', end($match)))
            );
        }
        return array();
    }

    /**
     * This method will extract the type information of a property from it's
     * doc comment information. The returned value will be <b>null</b> when no
     * type information exists.
     *
     * @return \PDepend\Source\AST\ASTType
     * @since 0.9.6
     */
    private function parseFieldDeclarationType()
    {
        // Skip, if ignore annotations is set
        if ($this->ignoreAnnotations === true) {
            return null;
        }

        $reference = $this->parseFieldDeclarationClassOrInterfaceReference();
        if ($reference !== null) {
            return $reference;
        }

        $annotations = $this->parseVarAnnotation($this->docComment);
        foreach ($annotations as $annotation) {
            if (Type::isPrimitiveType($annotation) === true) {
                return $this->builder->buildAstScalarType(
                    Type::getPrimitiveType($annotation)
                );
            } elseif (Type::isArrayType($annotation) === true) {
                return $this->builder->buildAstTypeArray();
            }
        }
        return null;
    }

    /**
     * Extracts non scalar types from a field doc comment and creates a
     * matching type instance.
     *
     * @return \PDepend\Source\AST\ASTClassOrInterfaceReference
     * @since 0.9.6
     */
    private function parseFieldDeclarationClassOrInterfaceReference()
    {
        $annotations = $this->parseVarAnnotation($this->docComment);
        foreach ($annotations as $annotation) {
            if (Type::isScalarType($annotation) === false) {
                return $this->builder->buildAstClassOrInterfaceReference(
                    $annotation
                );
            }
        }
        return null;
    }

    /**
     * This method parses a yield-statement node.
     *
     * @return \PDepend\Source\AST\ASTYieldStatmenet
     */
    private function parseYield()
    {
        $this->tokenStack->push();

        $token = $this->consumeToken(Tokens::T_YIELD);
        $this->consumeComments();

        $yield = $this->builder->buildAstYieldStatement($token->image);

        $node = $this->parseOptionalExpression();
        if ($node) {
            $yield->addChild($node);

            if ($this->tokenizer->peek() === Tokens::T_DOUBLE_ARROW) {
                $this->consumeToken(Tokens::T_DOUBLE_ARROW);

                $yield->addChild($this->parseOptionalExpression());
            }
        }

        $this->consumeComments();
        if (Tokens::T_PARENTHESIS_CLOSE === $this->tokenizer->peek()) {
            return $this->setNodePositionsAndReturn($yield);
        }

        $this->parseStatementTermination();
        return $this->setNodePositionsAndReturn($yield);
    }

    /**
     * Extracts documented <b>throws</b> and <b>return</b> types and sets them
     * to the given <b>$callable</b> instance.
     *
     * @param  \PDepend\Source\AST\AbstractASTCallable $callable
     * @return void
     */
    private function prepareCallable(AbstractASTCallable $callable)
    {
        // Skip, if ignore annotations is set
        if ($this->ignoreAnnotations === true) {
            return;
        }

        // Get all @throws Types
        $throws = $this->parseThrowsAnnotations($callable->getComment());
        foreach ($throws as $qualifiedName) {
            $callable->addExceptionClassReference(
                $this->builder->buildAstClassOrInterfaceReference($qualifiedName)
            );
        }

        // Stop here if return class already exists.
        if ($callable->hasReturnClass()) {
            return;
        }

        // Get return annotation
        $qualifiedName = $this->parseReturnAnnotation($callable->getComment());
        if ($qualifiedName !== null) {
            $callable->setReturnClassReference(
                $this->builder->buildAstClassOrInterfaceReference($qualifiedName)
            );
        }
    }

    /**
     * This method will consume the next token in the token stream. It will
     * throw an exception if the type of this token is not identical with
     * <b>$tokenType</b>.
     *
     * @param  integer $tokenType The next expected token type.
     * @return \PDepend\Source\Tokenizer\Token
     * @throws \PDepend\Source\Parser\TokenStreamEndException
     * @throws \PDepend\Source\Parser\UnexpectedTokenException
     */
    protected function consumeToken($tokenType)
    {
        switch ($this->tokenizer->peek()) {
            case $tokenType:
                return $this->tokenStack->add($this->tokenizer->next());
            case Tokenizer::T_EOF:
                throw new TokenStreamEndException($this->tokenizer);
        }
        $this->throwUnexpectedTokenException();
    }

    /**
     * This method will consume all comment tokens from the token stream.
     *
     * @return void
     */
    protected function consumeComments()
    {
        $type = $this->tokenizer->peek();
        while ($type == Tokens::T_COMMENT || $type == Tokens::T_DOC_COMMENT) {
            $token = $this->consumeToken($type);
            $type  = $this->tokenizer->peek();

            if (Tokens::T_COMMENT === $token->type) {
                continue;
            }

            $this->docComment = $token->image;
            if (preg_match('(\s+@package\s+[^\s]+\s+)', $token->image)) {
                $this->packageName = $this->parsePackageAnnotation($token->image);
            }
        }
    }

    /**
     * Throws an UnexpectedTokenException
     *
     * @param \PDepend\Source\Tokenizer\Token $token
     * @return void
     * @throws \PDepend\Source\Parser\UnexpectedTokenException
     * @since 2.2.5
     */
    protected function throwUnexpectedTokenException(Token $token = null)
    {
        throw new UnexpectedTokenException(
            (null === $token) ? $this->tokenizer->next() : $token,
            $this->tokenizer->getSourceFile()
        );
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.3
 */

namespace PDepend\Source\Language\PHP;

use PDepend\Source\Tokenizer\Tokens;

/**
 * Concrete parser implementation that supports features up to PHP version 7.1.
 *
 * TODO:
 * - void
 *   http://php.net/manual/en/migration71.new-features.php#migration71.new-features.void-functions
 * - Symmetric array destructuring
 *   http://php.net/manual/en/migration71.new-features.php#migration71.new-features.symmetric-array-destructuring
 * - Class constant visibility
 *   http://php.net/manual/en/migration71.new-features.php#migration71.new-features.class-constant-visibility
 * - Multi catch exception handling
 *   http://php.net/manual/en/migration71.new-features.php#migration71.new-features.mulit-catch-exception-handling
 * - see full list
 *   http://php.net/manual/en/migration71.php
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.4
 */
abstract class PHPParserVersion71 extends PHPParserVersion70
{
    /**
     * @return \PDepend\Source\AST\ASTType
     */
    protected function parseReturnTypeHint()
    {
        $this->consumeComments();

        $tokenType = $this->tokenizer->peek();
        if (Tokens::T_QUESTION_MARK === $tokenType) {
            $this->consumeToken(Tokens::T_QUESTION_MARK);
        }

        return parent::parseReturnTypeHint();
    }

    /**
     * This method parses a formal parameter in all it's variations.
     *
     * <code>
     * //                ------------
     * function traverse(Iterator $it) {}
     * //                ------------
     *
     * //                ---------
     * function traverse(array $ar) {}
     * //                ---------
     *
     * //                ---
     * function traverse(&$x) {}
     * //                ---
     * </code>
     *
     * @return \PDepend\Source\AST\ASTFormalParameter
     */
    protected function parseFormalParameterOrTypeHintOrByReference()
    {
        $this->consumeComments();
        $tokenType = $this->tokenizer->peek();
        if ($tokenType === Tokens::T_QUESTION_MARK) {
            $this->consumeToken(Tokens::T_QUESTION_MARK);
        }

        return parent::parseFormalParameterOrTypeHintOrByReference();
    }

    /**
     * Parses a type hint that is valid in the supported PHP version.
     *
     * @return \PDepend\Source\AST\ASTNode
     */
    protected function parseTypeHint()
    {
        $tokenType = $this->tokenizer->peek();
        if (Tokens::T_QUESTION_MARK === $tokenType) {
            $this->consumeToken(Tokens::T_QUESTION_MARK);
        }

        return parent::parseTypeHint();
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.3
 */

namespace PDepend\Source\Language\PHP;

use PDepend\Source\AST\ASTAllocationExpression;
use PDepend\Source\AST\ASTExpression;
use PDepend\Source\AST\ASTNode;
use PDepend\Source\Tokenizer\Tokens;

/**
 * Concrete parser implementation that supports features up to PHP version 7.0.
 *
 * TODO:
 * - Tokens: trait, callable, insteadof
 *   - allowed as
 *     - method
 *     - constant
 *   - not allowed as
 *     - class
 *     - interface
 *     - trait
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.3
 */
abstract class PHPParserVersion70 extends PHPParserVersion56
{
    /**
     * @param integer $tokenType
     * @return boolean
     */
    protected function isConstantName($tokenType)
    {
        switch ($tokenType) {
            case Tokens::T_CALLABLE:
            case Tokens::T_TRAIT:
            case Tokens::T_EXTENDS:
            case Tokens::T_IMPLEMENTS:
            case Tokens::T_STATIC:
            case Tokens::T_ABSTRACT:
            case Tokens::T_FINAL:
            case Tokens::T_PUBLIC:
            case Tokens::T_PROTECTED:
            case Tokens::T_PRIVATE:
            case Tokens::T_CONST:
            case Tokens::T_ENDDECLARE:
            case Tokens::T_ENDFOR:
            case Tokens::T_ENDFOREACH:
            case Tokens::T_ENDIF:
            case Tokens::T_ENDWHILE:
            case Tokens::T_LOGICAL_AND:
            case Tokens::T_GLOBAL:
            case Tokens::T_GOTO:
            case Tokens::T_INSTANCEOF:
            case Tokens::T_INSTEADOF:
            case Tokens::T_INTERFACE:
            case Tokens::T_NAMESPACE:
            case Tokens::T_NEW:
            case Tokens::T_LOGICAL_OR:
            case Tokens::T_LOGICAL_XOR:
            case Tokens::T_TRY:
            case Tokens::T_USE:
            case Tokens::T_VAR:
            case Tokens::T_EXIT:
            case Tokens::T_LIST:
            case Tokens::T_CLONE:
            case Tokens::T_INCLUDE:
            case Tokens::T_INCLUDE_ONCE:
            case Tokens::T_THROW:
            case Tokens::T_ARRAY:
            case Tokens::T_PRINT:
            case Tokens::T_ECHO:
            case Tokens::T_REQUIRE:
            case Tokens::T_REQUIRE_ONCE:
            case Tokens::T_RETURN:
            case Tokens::T_ELSE:
            case Tokens::T_ELSEIF:
            case Tokens::T_DEFAULT:
            case Tokens::T_BREAK:
            case Tokens::T_CONTINUE:
            case Tokens::T_SWITCH:
            case Tokens::T_YIELD:
            case Tokens::T_FUNCTION:
            case Tokens::T_IF:
            case Tokens::T_ENDSWITCH:
            case Tokens::T_FINALLY:
            case Tokens::T_FOR:
            case Tokens::T_FOREACH:
            case Tokens::T_DECLARE:
            case Tokens::T_CASE:
            case Tokens::T_DO:
            case Tokens::T_WHILE:
            case Tokens::T_AS:
            case Tokens::T_CATCH:
            //case Tokens::T_DIE:
            case Tokens::T_SELF:
            case Tokens::T_PARENT:
                return true;
        }
        return parent::isConstantName($tokenType);
    }

    /**
     * @param integer $tokenType
     * @return bool
     */
    protected function isMethodName($tokenType)
    {
        switch ($tokenType) {
            case Tokens::T_CLASS:
                return true;
        }
        return $this->isConstantName($tokenType);
    }

    /**
     * @return \PDepend\Source\AST\ASTNode
     */
    protected function parsePostfixIdentifier()
    {
        $tokenType = $this->tokenizer->peek();
        switch (true) {
            case ($this->isConstantName($tokenType)):
                $node = $this->parseLiteral();
                break;
            default:
                $node = parent::parsePostfixIdentifier();
                break;
        }
        return $this->parseOptionalIndexExpression($node);
    }

    /**
     * @param \PDepend\Source\AST\AbstractASTCallable $callable
     * @return \PDepend\Source\AST\AbstractASTCallable
     */
    protected function parseCallableDeclarationAddition($callable)
    {
        $this->consumeComments();
        if (Tokens::T_COLON != $this->tokenizer->peek()) {
            return $callable;
        }

        $this->consumeToken(Tokens::T_COLON);

        $type = $this->parseReturnTypeHint();
        $callable->addChild($type);

        return $callable;
    }

    /**
     * @return \PDepend\Source\AST\ASTType
     */
    protected function parseReturnTypeHint()
    {
        $this->consumeComments();

        switch ($tokenType = $this->tokenizer->peek()) {
            case Tokens::T_ARRAY:
                $type = $this->parseArrayType();
                break;
            case Tokens::T_SELF:
                $type = $this->parseSelfType();
                break;
            case Tokens::T_PARENT:
                $type = $this->parseParentType();
                break;
            default:
                $type = $this->parseTypeHint();
                break;
        }
        return $type;
    }

    /**
     * Parses a type hint that is valid in the supported PHP version.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @since 2.3
     */
    protected function parseTypeHint()
    {
        switch ($this->tokenizer->peek()) {
            case Tokens::T_STRING:
            case Tokens::T_BACKSLASH:
            case Tokens::T_NAMESPACE:
                $name = $this->parseQualifiedName();

                if ($this->isScalarOrCallableTypeHint($name)) {
                    $type = $this->parseScalarOrCallableTypeHint($name);
                } else {
                    $type = $this->builder->buildAstClassOrInterfaceReference($name);
                }
                break;
            default:
                $type = parent::parseTypeHint();
                break;
        }
        return $type;
    }

    /**
     * Tests if the given image is a PHP 7 type hint.
     *
     * @param string $image
     * @return boolean
     */
    private function isScalarOrCallableTypeHint($image)
    {
        switch (strtolower($image)) {
            case 'int':
            case 'bool':
            case 'float':
            case 'string':
            case 'callable':
                return true;
        }

        return false;
    }

    /**
     * Parses a scalar type hint or a callable type hint.
     *
     * @param string $image
     * @return \PDepend\Source\AST\ASTType
     */
    private function parseScalarOrCallableTypeHint($image)
    {
        switch (strtolower($image)) {
            case 'int':
            case 'bool':
            case 'float':
            case 'string':
                return $this->builder->buildAstScalarType($image);
            case 'callable':
                return $this->builder->buildAstTypeCallable();
        }

        return false;
    }

    /**
     * Parse the type reference used in an allocation expression.
     *
     * @param \PDepend\Source\AST\ASTAllocationExpression $allocation
     * @return \PDepend\Source\AST\ASTNode
     * @since 2.3
     */
    protected function parseAllocationExpressionTypeReference(ASTAllocationExpression $allocation)
    {
        if ($newAllocation = $this->parseAnonymousClassDeclaration($allocation)) {
            return $newAllocation;
        }
        return parent::parseAllocationExpressionTypeReference($allocation);
    }

    /**
     * Attempts to the next sequence of tokens as an anonymous class and adds it to the allocation expression
     *
     * @param \PDepend\Source\AST\ASTAllocationExpression $allocation
     *
     * @return null|\PDepend\Source\AST\ASTAnonymousClass
     */
    protected function parseAnonymousClassDeclaration(ASTAllocationExpression $allocation)
    {
        $this->consumeComments();
        if (Tokens::T_CLASS !== $this->tokenizer->peek()) {
            return null;
        }

        $classOrInterface = $this->classOrInterface;

        $this->tokenStack->push();

        $this->consumeToken(Tokens::T_CLASS);
        $this->consumeComments();

        $class = $this->builder->buildAnonymousClass();
        $class->setName(
            sprintf(
                'class@anonymous%s0x%s',
                $this->compilationUnit->getFileName(),
                uniqid('')
            )
        );
        $class->setCompilationUnit($this->compilationUnit);
        $class->setUserDefined();

        if ($this->isNextTokenArguments()) {
            $class->addChild($this->parseArguments());
        }

        $this->consumeComments();
        $tokenType = $this->tokenizer->peek();

        if ($tokenType === Tokens::T_EXTENDS) {
            $class = $this->parseClassExtends($class);

            $this->consumeComments();
            $tokenType = $this->tokenizer->peek();
        }

        if ($tokenType === Tokens::T_IMPLEMENTS) {
            $this->consumeToken(Tokens::T_IMPLEMENTS);
            $this->parseInterfaceList($class);
        }

        $allocation->addChild(
            $this->setNodePositionsAndReturn(
                $this->parseTypeBody($class),
                $tokens
            )
        );
        $class->setTokens($tokens);

        $this->classOrInterface = $classOrInterface;

        return $allocation;
    }

    /**
     * @param \PDepend\Source\AST\ASTNode $node
     * @return \PDepend\Source\AST\ASTNode
     */
    protected function parseOptionalMemberPrimaryPrefix(ASTNode $node)
    {
        $this->consumeComments();
        if (Tokens::T_DOUBLE_COLON === $this->tokenizer->peek()) {
            return $this->parseStaticMemberPrimaryPrefix($node);
        }
        if ($this->tokenizer->peek() === Tokens::T_OBJECT_OPERATOR) {
            return $this->parseMemberPrimaryPrefix($node);
        }
        return $node;
    }

    /**
     * @param \PDepend\Source\AST\ASTExpression $expr
     * @return \PDepend\Source\AST\ASTExpression
     */
    protected function parseParenthesisExpressionOrPrimaryPrefixForVersion(ASTExpression $expr)
    {
        $this->consumeComments();
        if (Tokens::T_DOUBLE_COLON === $this->tokenizer->peek()) {
            return $this->parseStaticMemberPrimaryPrefix($expr->getChild(0));
        }
        if ($this->tokenizer->peek() === Tokens::T_OBJECT_OPERATOR) {
            return $this->parseMemberPrimaryPrefix($expr->getChild(0));
        }
        return $expr;
    }

    /**
     * This method will be called when the base parser cannot handle an expression
     * in the base version. In this method you can implement version specific
     * expressions.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\UnexpectedTokenException
     * @since 2.3
     */
    protected function parseOptionalExpressionForVersion()
    {
        if ($expression = $this->parseExpressionVersion70()) {
            return $expression;
        }
        return parent::parseOptionalExpressionForVersion();
    }

    /**
     * In this method we implement parsing of PHP 7.0 specific expressions.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @since 2.3
     */
    protected function parseExpressionVersion70()
    {
        $this->consumeComments();
        $nextTokenType = $this->tokenizer->peek();

        switch ($nextTokenType) {
            case Tokens::T_SPACESHIP:
            case Tokens::T_COALESCE:
                $token = $this->consumeToken($nextTokenType);

                $expr = $this->builder->buildAstExpression($token->image);
                $expr->configureLinesAndColumns(
                    $token->startLine,
                    $token->endLine,
                    $token->startColumn,
                    $token->endColumn
                );

                return $expr;
        }
    }

    /**
     * This method will parse a formal parameter. A formal parameter is at least
     * a variable name, but can also contain a default parameter value.
     *
     * <code>
     * //               --  -------
     * function foo(Bar $x, $y = 42) {}
     * //               --  -------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTFormalParameter
     * @since 2.0.7
     */
    protected function parseFormalParameter()
    {
        $parameter = $this->builder->buildAstFormalParameter();

        if (Tokens::T_ELLIPSIS === $this->tokenizer->peek()) {
            $this->consumeToken(Tokens::T_ELLIPSIS);
            $this->consumeComments();

            $parameter->setVariableArgList();
        }

        $parameter->addChild($this->parseVariableDeclarator());

        return $parameter;
    }

    /**
     * @param array $fragments
     * @return void
     */
    protected function parseUseDeclarationForVersion(array $fragments)
    {
        if (Tokens::T_CURLY_BRACE_OPEN === $this->tokenizer->peek()) {
            return $this->parseUseDeclarationVersion70($fragments);
        }
        return parent::parseUseDeclarationForVersion($fragments);
    }

    /**
     * @param array $fragments
     * @return void
     */
    protected function parseUseDeclarationVersion70(array $fragments)
    {
        $namespacePrefixReplaced = $this->namespacePrefixReplaced;

        $this->consumeToken(Tokens::T_CURLY_BRACE_OPEN);
        $this->consumeComments();

        do {
            $nextToken = $this->tokenizer->peek();
            switch ($nextToken) {
                case Tokens::T_CONST:
                case Tokens::T_FUNCTION:
                    $this->consumeToken($nextToken);
            }

            $subFragments = $this->parseQualifiedNameRaw();
            $this->consumeComments();

            $image = $this->parseNamespaceImage($subFragments);

            if (Tokens::T_COMMA != $this->tokenizer->peek()) {
                break;
            }

            $this->consumeToken(Tokens::T_COMMA);
            $this->consumeComments();

            // Add mapping between image and qualified name to symbol table
            $this->useSymbolTable->add($image, join('', array_merge($fragments, $subFragments)));
        } while (true);

        $this->useSymbolTable->add($image, join('', array_merge($fragments, $subFragments)));

        $this->consumeToken(Tokens::T_CURLY_BRACE_CLOSE);
        $this->consumeComments();

        $this->namespacePrefixReplaced = $namespacePrefixReplaced;
    }

    /**
     * @param array $previousElements
     * @return string
     */
    protected function parseQualifiedNameElement(array $previousElements)
    {
        if (Tokens::T_CURLY_BRACE_OPEN !== $this->tokenizer->peek()) {
            return parent::parseQualifiedNameElement($previousElements);
        }
        if (count($previousElements) >= 2 && '\\' === end($previousElements)) {
            return null;
        }
        $this->throwUnexpectedTokenException($this->tokenizer->next());
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\Language\PHP;

use PDepend\Source\AST\ASTCompilationUnit;
use PDepend\Source\Tokenizer\Token;
use PDepend\Source\Tokenizer\Tokenizer;
use PDepend\Source\Tokenizer\Tokens;

/**
 * Define PHP 5.4 __TRAIT__ token constant.
 */
if (!defined('T_TRAIT_C')) {
    define('T_TRAIT_C', 42000);
}

/**
 * Define PHP 5.4 'trait' token constant.
 */
if (!defined('T_TRAIT')) {
    define('T_TRAIT', 42001);
}

/**
 * Define PHP 5.4 'insteadof' token constant.
 */
if (!defined('T_INSTEADOF')) {
    define('T_INSTEADOF', 42002);
}

/**
 * Define PHP 5.3 __NAMESPACE__ token constant.
 */
if (!defined('T_NS_C')) {
    define('T_NS_C', 42003);
}

/**
 * Define PHP 5.3 'use' token constant
 */
if (!defined('T_USE')) {
    define('T_USE', 42004);
}

/**
 * Define PHP 5.3 'namespace' token constant.
 */
if (!defined('T_NAMESPACE')) {
    define('T_NAMESPACE', 42005);
}

/**
 * Define PHP 5.6 '...' token constant
 */
if (!defined('T_ELLIPSIS')) {
    define('T_ELLIPSIS', 42006);
}

/**
 * Define PHP 5.3's '__DIR__' token constant.
 */
if (!defined('T_DIR')) {
    define('T_DIR', 42006);
}

/**
 * Define PHP 5.3's 'T_GOTO' token constant.
 */
if (!defined('T_GOTO')) {
    define('T_GOTO', 42007);
}

/**
 * Define PHP 5.4's 'T_CALLABLE' token constant
 */
if (!defined('T_CALLABLE')) {
    define('T_CALLABLE', 42008);
}

/**
 * Define PHP 5.5's 'T_YIELD' token constant
 */
if (!defined('T_YIELD')) {
    define('T_YIELD', 42009);
}

/**
 * Define PHP 5,5's 'T_FINALLY' token constant
 */
if (!defined('T_FINALLY')) {
    define('T_FINALLY', 42010);
}

/**
 * Define character token that was removed in PHP 7
 */
if (!defined('T_CHARACTER')) {
    define('T_CHARACTER', 42011);
}

/**
 * Define bad character token that was removed in PHP 7
 */
if (!defined('T_BAD_CHARACTER')) {
    define('T_BAD_CHARACTER', 42012);
}

/**
 * Define PHP 7's '<=>' token constant
 */
if (!defined('T_SPACESHIP')) {
    define('T_SPACESHIP', 42013);
}

/**
 * Define PHP 7's '??' token constant
 */
if (!defined('T_COALESCE')) {
    define('T_COALESCE', 42014);
}

/**
 * Define PHP 7's '**' token constant
 */
if (!defined('T_POW')) {
    define('T_POW', 42015);
}

/**
 * This tokenizer uses the internal {@link token_get_all()} function as token stream
 * generator.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class PHPTokenizerInternal implements Tokenizer
{
    /**
     * Mapping between php internal tokens and php depend tokens.
     *
     * @var array(integer=>integer)
     */
    protected static $tokenMap = array(
        T_AS                        =>  Tokens::T_AS,
        T_DO                        =>  Tokens::T_DO,
        T_IF                        =>  Tokens::T_IF,
        T_SL                        =>  Tokens::T_SL,
        T_SR                        =>  Tokens::T_SR,
        T_DEC                       =>  Tokens::T_DEC,
        T_FOR                       =>  Tokens::T_FOR,
        T_INC                       =>  Tokens::T_INC,
        T_NEW                       =>  Tokens::T_NEW,
        T_POW                       =>  Tokens::T_POW,
        T_TRY                       =>  Tokens::T_TRY,
        T_USE                       =>  Tokens::T_USE,
        T_VAR                       =>  Tokens::T_VAR,
        T_CASE                      =>  Tokens::T_CASE,
        T_ECHO                      =>  Tokens::T_ECHO,
        T_ELSE                      =>  Tokens::T_ELSE,
        T_EVAL                      =>  Tokens::T_EVAL,
        T_EXIT                      =>  Tokens::T_EXIT,
        T_FILE                      =>  Tokens::T_FILE,
        T_GOTO                      =>  Tokens::T_GOTO,
        T_LINE                      =>  Tokens::T_LINE,
        T_LIST                      =>  Tokens::T_LIST,
        T_NS_C                      =>  Tokens::T_NS_C,
        T_ARRAY                     =>  Tokens::T_ARRAY,
        T_BREAK                     =>  Tokens::T_BREAK,
        T_CLASS                     =>  Tokens::T_CLASS,
        T_CATCH                     =>  Tokens::T_CATCH,
        T_CLONE                     =>  Tokens::T_CLONE,
        T_CONST                     =>  Tokens::T_CONST,
        T_EMPTY                     =>  Tokens::T_EMPTY,
        T_ENDIF                     =>  Tokens::T_ENDIF,
        T_FINAL                     =>  Tokens::T_FINAL,
        T_ISSET                     =>  Tokens::T_ISSET,
        T_PRINT                     =>  Tokens::T_PRINT,
        T_THROW                     =>  Tokens::T_THROW,
        T_TRAIT                     =>  Tokens::T_TRAIT,
        T_UNSET                     =>  Tokens::T_UNSET,
        T_WHILE                     =>  Tokens::T_WHILE,
        T_ENDFOR                    =>  Tokens::T_ENDFOR,
        T_ELSEIF                    =>  Tokens::T_ELSEIF,
        T_FUNC_C                    =>  Tokens::T_FUNC_C,
        T_GLOBAL                    =>  Tokens::T_GLOBAL,
        T_PUBLIC                    =>  Tokens::T_PUBLIC,
        T_RETURN                    =>  Tokens::T_RETURN,
        T_STATIC                    =>  Tokens::T_STATIC,
        T_STRING                    =>  Tokens::T_STRING,
        T_SWITCH                    =>  Tokens::T_SWITCH,
        T_CLASS_C                   =>  Tokens::T_CLASS_C,
        T_COMMENT                   =>  Tokens::T_COMMENT,
        T_DECLARE                   =>  Tokens::T_DECLARE,
        T_DEFAULT                   =>  Tokens::T_DEFAULT,
        T_DNUMBER                   =>  Tokens::T_DNUMBER,
        T_EXTENDS                   =>  Tokens::T_EXTENDS,
        T_FOREACH                   =>  Tokens::T_FOREACH,
        T_INCLUDE                   =>  Tokens::T_INCLUDE,
        T_LNUMBER                   =>  Tokens::T_LNUMBER,
        T_PRIVATE                   =>  Tokens::T_PRIVATE,
        T_REQUIRE                   =>  Tokens::T_REQUIRE,
        T_TRAIT_C                   =>  Tokens::T_TRAIT_C,
        T_ABSTRACT                  =>  Tokens::T_ABSTRACT,
        T_CALLABLE                  =>  Tokens::T_CALLABLE,
        T_ENDWHILE                  =>  Tokens::T_ENDWHILE,
        T_FUNCTION                  =>  Tokens::T_FUNCTION,
        T_INT_CAST                  =>  Tokens::T_INT_CAST,
        T_IS_EQUAL                  =>  Tokens::T_IS_EQUAL,
        T_OR_EQUAL                  =>  Tokens::T_OR_EQUAL,
        T_CONTINUE                  =>  Tokens::T_CONTINUE,
        T_METHOD_C                  =>  Tokens::T_METHOD_C,
        T_ELLIPSIS                  =>  Tokens::T_ELLIPSIS,
        T_OPEN_TAG                  =>  Tokens::T_OPEN_TAG,
        T_SL_EQUAL                  =>  Tokens::T_SL_EQUAL,
        T_SR_EQUAL                  =>  Tokens::T_SR_EQUAL,
        T_VARIABLE                  =>  Tokens::T_VARIABLE,
        T_ENDSWITCH                 =>  Tokens::T_ENDSWITCH,
        T_DIV_EQUAL                 =>  Tokens::T_DIV_EQUAL,
        T_AND_EQUAL                 =>  Tokens::T_AND_EQUAL,
        T_MOD_EQUAL                 =>  Tokens::T_MOD_EQUAL,
        T_MUL_EQUAL                 =>  Tokens::T_MUL_EQUAL,
        T_NAMESPACE                 =>  Tokens::T_NAMESPACE,
        T_XOR_EQUAL                 =>  Tokens::T_XOR_EQUAL,
        T_INTERFACE                 =>  Tokens::T_INTERFACE,
        T_BOOL_CAST                 =>  Tokens::T_BOOL_CAST,
        T_CHARACTER                 =>  Tokens::T_CHARACTER,
        T_CLOSE_TAG                 =>  Tokens::T_CLOSE_TAG,
        T_INSTEADOF                 =>  Tokens::T_INSTEADOF,
        T_PROTECTED                 =>  Tokens::T_PROTECTED,
        T_SPACESHIP                 =>  Tokens::T_SPACESHIP,
        T_CURLY_OPEN                =>  Tokens::T_CURLY_BRACE_OPEN,
        T_ENDFOREACH                =>  Tokens::T_ENDFOREACH,
        T_ENDDECLARE                =>  Tokens::T_ENDDECLARE,
        T_IMPLEMENTS                =>  Tokens::T_IMPLEMENTS,
        T_NUM_STRING                =>  Tokens::T_NUM_STRING,
        T_PLUS_EQUAL                =>  Tokens::T_PLUS_EQUAL,
        T_ARRAY_CAST                =>  Tokens::T_ARRAY_CAST,
        T_BOOLEAN_OR                =>  Tokens::T_BOOLEAN_OR,
        T_INSTANCEOF                =>  Tokens::T_INSTANCEOF,
        T_LOGICAL_OR                =>  Tokens::T_LOGICAL_OR,
        T_UNSET_CAST                =>  Tokens::T_UNSET_CAST,
        T_DOC_COMMENT               =>  Tokens::T_DOC_COMMENT,
        T_END_HEREDOC               =>  Tokens::T_END_HEREDOC,
        T_MINUS_EQUAL               =>  Tokens::T_MINUS_EQUAL,
        T_BOOLEAN_AND               =>  Tokens::T_BOOLEAN_AND,
        T_DOUBLE_CAST               =>  Tokens::T_DOUBLE_CAST,
        T_INLINE_HTML               =>  Tokens::T_INLINE_HTML,
        T_LOGICAL_AND               =>  Tokens::T_LOGICAL_AND,
        T_LOGICAL_XOR               =>  Tokens::T_LOGICAL_XOR,
        T_OBJECT_CAST               =>  Tokens::T_OBJECT_CAST,
        T_STRING_CAST               =>  Tokens::T_STRING_CAST,
        T_DOUBLE_ARROW              =>  Tokens::T_DOUBLE_ARROW,
        T_INCLUDE_ONCE              =>  Tokens::T_INCLUDE_ONCE,
        T_IS_IDENTICAL              =>  Tokens::T_IS_IDENTICAL,
        T_DOUBLE_COLON              =>  Tokens::T_DOUBLE_COLON,
        T_CONCAT_EQUAL              =>  Tokens::T_CONCAT_EQUAL,
        T_IS_NOT_EQUAL              =>  Tokens::T_IS_NOT_EQUAL,
        T_REQUIRE_ONCE              =>  Tokens::T_REQUIRE_ONCE,
        T_BAD_CHARACTER             =>  Tokens::T_BAD_CHARACTER,
        T_HALT_COMPILER             =>  Tokens::T_HALT_COMPILER,
        T_START_HEREDOC             =>  Tokens::T_START_HEREDOC,
        T_STRING_VARNAME            =>  Tokens::T_STRING_VARNAME,
        T_OBJECT_OPERATOR           =>  Tokens::T_OBJECT_OPERATOR,
        T_IS_NOT_IDENTICAL          =>  Tokens::T_IS_NOT_IDENTICAL,
        T_OPEN_TAG_WITH_ECHO        =>  Tokens::T_OPEN_TAG_WITH_ECHO,
        T_IS_GREATER_OR_EQUAL       =>  Tokens::T_IS_GREATER_OR_EQUAL,
        T_IS_SMALLER_OR_EQUAL       =>  Tokens::T_IS_SMALLER_OR_EQUAL,
        T_PAAMAYIM_NEKUDOTAYIM      =>  Tokens::T_DOUBLE_COLON,
        T_ENCAPSED_AND_WHITESPACE   =>  Tokens::T_ENCAPSED_AND_WHITESPACE,
        T_CONSTANT_ENCAPSED_STRING  =>  Tokens::T_CONSTANT_ENCAPSED_STRING,
        T_YIELD                     =>  Tokens::T_YIELD,
        T_FINALLY                   =>  Tokens::T_FINALLY,
        T_COALESCE                  =>  Tokens::T_COALESCE,
        //T_DOLLAR_OPEN_CURLY_BRACES  =>  Tokens::T_CURLY_BRACE_OPEN,
    );

    /**
     * Internally used transition token.
     */
    const T_ELLIPSIS = 23006;

    /**
     * Mapping between php internal text tokens an php depend numeric tokens.
     *
     * @var array(string=>integer)
     */
    protected static $literalMap = array(
        '@'              =>  Tokens::T_AT,
        '/'              =>  Tokens::T_DIV,
        '%'              =>  Tokens::T_MOD,
        '*'              =>  Tokens::T_MUL,
        '+'              =>  Tokens::T_PLUS,
        ':'              =>  Tokens::T_COLON,
        ','              =>  Tokens::T_COMMA,
        '='              =>  Tokens::T_EQUAL,
        '-'              =>  Tokens::T_MINUS,
        '.'              =>  Tokens::T_CONCAT,
        '$'              =>  Tokens::T_DOLLAR,
        '`'              =>  Tokens::T_BACKTICK,
        '\\'             =>  Tokens::T_BACKSLASH,
        ';'              =>  Tokens::T_SEMICOLON,
        '|'              =>  Tokens::T_BITWISE_OR,
        '&'              =>  Tokens::T_BITWISE_AND,
        '~'              =>  Tokens::T_BITWISE_NOT,
        '^'              =>  Tokens::T_BITWISE_XOR,
        '"'              =>  Tokens::T_DOUBLE_QUOTE,
        '?'              =>  Tokens::T_QUESTION_MARK,
        '!'              =>  Tokens::T_EXCLAMATION_MARK,
        '{'              =>  Tokens::T_CURLY_BRACE_OPEN,
        '}'              =>  Tokens::T_CURLY_BRACE_CLOSE,
        '('              =>  Tokens::T_PARENTHESIS_OPEN,
        ')'              =>  Tokens::T_PARENTHESIS_CLOSE,
        '<'              =>  Tokens::T_ANGLE_BRACKET_OPEN,
        '>'              =>  Tokens::T_ANGLE_BRACKET_CLOSE,
        '['              =>  Tokens::T_SQUARED_BRACKET_OPEN,
        ']'              =>  Tokens::T_SQUARED_BRACKET_CLOSE,
        'use'            =>  Tokens::T_USE,
        'goto'           =>  Tokens::T_GOTO,
        'null'           =>  Tokens::T_NULL,
        'self'           =>  Tokens::T_SELF,
        'true'           =>  Tokens::T_TRUE,
        'array'          =>  Tokens::T_ARRAY,
        'false'          =>  Tokens::T_FALSE,
        'trait'          =>  Tokens::T_TRAIT,
        'yield'          =>  Tokens::T_YIELD,
        'parent'         =>  Tokens::T_PARENT,
        'finally'        =>  Tokens::T_FINALLY,
        'callable'       =>  Tokens::T_CALLABLE,
        'insteadof'      =>  Tokens::T_INSTEADOF,
        'namespace'      =>  Tokens::T_NAMESPACE,
        '__dir__'        =>  Tokens::T_DIR,
        '__trait__'      =>  Tokens::T_TRAIT_C,
        '__namespace__'  =>  Tokens::T_NS_C,
    );

    /**
     *
     * @var array(mixed=>array)
     */
    protected static $substituteTokens = array(
        T_DOLLAR_OPEN_CURLY_BRACES  =>  array('$', '{'),
    );

    /**
     * BuilderContext sensitive alternative mappings.
     *
     * @var array(integer=>array)
     */
    protected static $alternativeMap = array(
        Tokens::T_USE => array(
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
            Tokens::T_CONST            =>  Tokens::T_STRING,
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
        ),

        Tokens::T_GOTO => array(
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
            Tokens::T_CONST            =>  Tokens::T_STRING,
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
        ),

        Tokens::T_NULL => array(
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
            Tokens::T_CONST            =>  Tokens::T_STRING,
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
        ),

        Tokens::T_SELF => array(
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
            Tokens::T_CONST            =>  Tokens::T_STRING,
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
        ),

        Tokens::T_TRUE => array(
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
            Tokens::T_NAMESPACE        =>  Tokens::T_STRING,
            Tokens::T_CONST            =>  Tokens::T_STRING,
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
        ),

        Tokens::T_ARRAY => array(
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
        ),

        Tokens::T_FALSE => array(
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
            Tokens::T_NAMESPACE        =>  Tokens::T_STRING,
            Tokens::T_CONST            =>  Tokens::T_STRING,
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
        ),

        Tokens::T_PARENT => array(
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
            Tokens::T_CONST            =>  Tokens::T_STRING,
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
        ),

        Tokens::T_NAMESPACE => array(
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
            Tokens::T_CONST            =>  Tokens::T_STRING,
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
        ),

        Tokens::T_DIR => array(
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
            Tokens::T_CONST            =>  Tokens::T_STRING,
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
        ),

        Tokens::T_NS_C => array(
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
            Tokens::T_CONST            =>  Tokens::T_STRING,
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
        ),

        Tokens::T_PARENT => array(
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
            Tokens::T_CONST            =>  Tokens::T_STRING,
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
        ),

        Tokens::T_FINALLY => array(
            Tokens::T_OBJECT_OPERATOR  =>  Tokens::T_STRING,
            Tokens::T_DOUBLE_COLON     =>  Tokens::T_STRING,
            Tokens::T_CONST            =>  Tokens::T_STRING,
            Tokens::T_FUNCTION         =>  Tokens::T_STRING,
        ),

        Tokens::T_CALLABLE => array(
            Tokens::T_OBJECT_OPERATOR  => Tokens::T_STRING,
            Tokens::T_DOUBLE_COLON     => Tokens::T_STRING,
        ),

        Tokens::T_LIST => array(
            Tokens::T_OBJECT_OPERATOR  => Tokens::T_STRING,
            Tokens::T_DOUBLE_COLON     => Tokens::T_STRING,
        ),

        Tokens::T_EMPTY => array(
            Tokens::T_OBJECT_OPERATOR  => Tokens::T_STRING,
            Tokens::T_DOUBLE_COLON     => Tokens::T_STRING,
        ),

        Tokens::T_CLASS => array(
            Tokens::T_DOUBLE_COLON     => Tokens::T_CLASS_FQN,
        ),
    );

    protected static $reductionMap = array(
        Tokens::T_CONCAT => array(
            Tokens::T_CONCAT => array(
                'type'  => self::T_ELLIPSIS,
                'image' => '..',
            ),
            self::T_ELLIPSIS  =>  array(
                'type'  => Tokens::T_ELLIPSIS,
                'image' => '...',
            )
        ),

        Tokens::T_ANGLE_BRACKET_CLOSE => array(
            Tokens::T_IS_SMALLER_OR_EQUAL => array(
                'type'  => Tokens::T_SPACESHIP,
                'image' => '<=>',
            )
        ),

        Tokens::T_QUESTION_MARK => array(
            Tokens::T_QUESTION_MARK => array(
                'type'  => Tokens::T_COALESCE,
                'image' => '??',
            )
        ),

        Tokens::T_MUL => array(
            Tokens::T_MUL => array(
                'type'  => Tokens::T_POW,
                'image' => '**',
            )
        ),
    );

    /**
     * The source file instance.
     *
     * @var \PDepend\Source\AST\ASTCompilationUnit
     */
    protected $sourceFile = '';

    /**
     * Count of all tokens.
     *
     * @var integer
     */
    protected $count = 0;

    /**
     * Internal stream pointer index.
     *
     * @var integer
     */
    protected $index = 0;

    /**
     * Prepared token list.
     *
     * @var Token[]
     */
    protected $tokens = null;

    /**
     * The next free identifier for unknown string tokens.
     *
     * @var integer
     */
    private $unknownTokenID = 1000;

    /**
     * Returns the name of the source file.
     *
     * @return \PDepend\Source\AST\ASTCompilationUnit
     */
    public function getSourceFile()
    {
        return $this->sourceFile;
    }

    /**
     * Sets a new php source file.
     *
     * @param string $sourceFile A php source file.
     *
     * @return void
     */
    public function setSourceFile($sourceFile)
    {
        $this->tokens = null;
        $this->sourceFile = new ASTCompilationUnit($sourceFile);
    }

    /**
     * Returns the next token or {@link \PDepend\Source\Tokenizer\Tokenizer::T_EOF} if
     * there is no next token.
     *
     * @return Token|integer
     */
    public function next()
    {
        $this->tokenize();

        if ($this->index < $this->count) {
            return $this->tokens[$this->index++];
        }
        return self::T_EOF;
    }

    /**
     * Returns the next token type or {@link \PDepend\Source\Tokenizer\Tokenizer::T_EOF} if
     * there is no next token.
     *
     * @return integer
     */
    public function peek()
    {
        $this->tokenize();

        if (isset($this->tokens[$this->index])) {
            return $this->tokens[$this->index]->type;
        }
        return self::T_EOF;
    }

    /**
     * Returns the type of next token, after the current token. This method
     * ignores all comments between the current and the next token.
     *
     * @return integer
     * @since  0.9.12
     */
    public function peekNext()
    {
        $this->tokenize();
        
        $offset = 0;
        do {
            $type = $this->tokens[$this->index + ++$offset]->type;
        } while ($type == Tokens::T_COMMENT || $type == Tokens::T_DOC_COMMENT);
        return $type;
    }

    /**
     * Returns the previous token type or {@link \PDepend\Source\Tokenizer\Tokenizer::T_BOF}
     * if there is no previous token.
     *
     * @return integer
     */
    public function prev()
    {
        $this->tokenize();

        if ($this->index > 1) {
            return $this->tokens[$this->index - 2]->type;
        }
        return self::T_BOF;
    }

    /**
     * This method takes an array of tokens returned by <b>token_get_all()</b>
     * and substitutes some of the tokens with those required by PDepend's
     * parser implementation.
     *
     * @param array(array) $tokens Unprepared array of php tokens.
     *
     * @return array(array)
     */
    private function substituteTokens(array $tokens)
    {
        $result = array();
        foreach ($tokens as $token) {
            $temp = (array) $token;
            $temp = $temp[0];
            if (isset(self::$substituteTokens[$temp])) {
                foreach (self::$substituteTokens[$temp] as $token) {
                    $result[] = $token;
                }
            } else {
                $result[] = $token;
            }
        }
        return $result;
    }

    /**
     * Tokenizes the content of the source file with {@link token_get_all()} and
     * filters this token stream.
     *
     * @return void
     */
    private function tokenize()
    {
        if ($this->tokens) {
            return;
        }

        $this->tokens = array();
        $this->index  = 0;
        $this->count  = 0;

        // Replace short open tags, short open tags will produce invalid results
        // in all environments with disabled short open tags.
        $source = $this->sourceFile->getSource();
        $source = preg_replace(
            array('(<\?=)', '(<\?(\s))'),
            array('<?php echo ', '<?php\1'),
            $source
        );

        if (version_compare(phpversion(), '5.3.0alpha3') < 0) {
            $tokens = PHPTokenizerHelperVersion52::tokenize($source);
        } else {
            $tokens = token_get_all($source);
        }

        $tokens = $this->substituteTokens($tokens);

        // Is the current token between an opening and a closing php tag?
        $inTag = false;

        // The current line number
        $startLine = 1;

        $startColumn = 1;
        $endColumn   = 1;

        $literalMap = self::$literalMap;
        $tokenMap   = self::$tokenMap;

        // Previous found type
        $previousType = null;
        $previousStartColumn = 0;

        while ($token = current($tokens)) {
            $type  = null;
            $image = null;

            if (is_string($token)) {
                $token = array(null, $token);
            }

            if ($token[0] === T_OPEN_TAG) {
                $type  = $tokenMap[$token[0]];
                $image = $token[1];
                $inTag = true;
            } elseif ($token[0] === T_CLOSE_TAG) {
                $type  = $tokenMap[$token[0]];
                $image = $token[1];
                $inTag = false;
            } elseif ($inTag === false) {
                $type  = Tokens::T_NO_PHP;
                $image = $this->consumeNonePhpTokens($tokens);
            } elseif ($token[0] === T_WHITESPACE) {
                // Count newlines in token
                $lines = substr_count($token[1], "\n");
                if ($lines === 0) {
                    $startColumn += strlen($token[1]);
                } else {
                    $startColumn = strlen(
                        substr($token[1], strrpos($token[1], "\n") + 1)
                    ) + 1;
                }

                $startLine += $lines;
            } else {
                $value = strtolower($token[1]);
                if (isset($literalMap[$value])) {
                    // Fetch literal type
                    $type = $literalMap[$value];
                    $image = $token[1];

                    // Check for a context sensitive alternative
                    if (isset(self::$alternativeMap[$type][$previousType])) {
                        $type = self::$alternativeMap[$type][$previousType];
                    }

                    if (isset(self::$reductionMap[$type][$previousType])) {
                        $image = self::$reductionMap[$type][$previousType]['image'];
                        $type = self::$reductionMap[$type][$previousType]['type'];

                        $startColumn = $previousStartColumn;

                        array_pop($this->tokens);
                    }

                } elseif (isset($tokenMap[$token[0]])) {
                    $type = $tokenMap[$token[0]];
                    // Check for a context sensitive alternative
                    if (isset(self::$alternativeMap[$type][$previousType])) {
                        $type = self::$alternativeMap[$type][$previousType];
                    }

                    $image = $token[1];
                } else {
                    // This should never happen
                    // @codeCoverageIgnoreStart
                    list($type, $image) = $this->generateUnknownToken($token[1]);
                    // @codeCoverageIgnoreEnd
                }
            }

            if ($type) {
                $rtrim = rtrim($image);
                $lines = substr_count($rtrim, "\n");
                if ($lines === 0) {
                    $endColumn = $startColumn + strlen($rtrim) - 1;
                } else {
                    $endColumn = strlen(
                        substr($rtrim, strrpos($rtrim, "\n") + 1)
                    );
                }

                $endLine = $startLine + $lines;

                $token = new Token($type, $rtrim, $startLine, $endLine, $startColumn, $endColumn);

                // Store token in internal list
                $this->tokens[] = $token;

                // Store previous start column
                $previousStartColumn = $startColumn;

                // Count newlines in token
                $lines = substr_count($image, "\n");
                if ($lines === 0) {
                    $startColumn += strlen($image);
                } else {
                    $startColumn = strlen(
                        substr($image, strrpos($image, "\n") + 1)
                    ) + 1;
                }

                $startLine += $lines;
                
                // Store current type
                if ($type !== Tokens::T_COMMENT && $type !== Tokens::T_DOC_COMMENT) {
                    $previousType = $type;
                }
            }

            next($tokens);
        }

        $this->count = count($this->tokens);
    }

    /**
     * This method fetches all tokens until an opening php tag was found and it
     * returns the collected content. The returned value will be null if there
     * was no none php token.
     *
     * @param array &$tokens Reference to the current token stream.
     *
     * @return string
     */
    private function consumeNonePhpTokens(array &$tokens)
    {
        // The collected token content
        $content = null;

        // Fetch current token
        $token = (array) current($tokens);

        // Skipp all non open tags
        while ($token[0] !== T_OPEN_TAG_WITH_ECHO &&
               $token[0] !== T_OPEN_TAG &&
               $token[0] !== false) {
            $content .= (isset($token[1]) ? $token[1] : $token[0]);

            $token = (array) next($tokens);
        }

        // Set internal pointer one back when there was at least one none php token
        if ($token[0] !== false) {
            prev($tokens);
        }

        return $content;
    }

    /**
     * Generates a dummy/temp token for unknown string literals.
     *
     * @param string $token The unknown string token.
     *
     * @return array(integer => mixed)
     */
    private function generateUnknownToken($token)
    {
        return array($this->unknownTokenID++, $token);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\Language\PHP;

use PDepend\Source\Parser\TokenException;

/**
 * Utility class that can be used to handle PHP's namespace separator in all
 * PHP environments lower than 5.3alpha3
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
final class PHPTokenizerHelperVersion52
{
    /**
     * This method implements a workaround for all PHP versions lower 5.3alpha3
     * that do not handle the namespace separator char.
     *
     * @param string $source The raw source code.
     *
     * @return array The tokens.
     */
    public static function tokenize($source)
    {
        // Replace backslash with valid token
        $source = preg_replace(
            array(
                '#\\\\([^"\'`\\\\])#i',
                '(<<<(\s*)([\w\d]+)(.*[\r\n])\2;(\r\n|\n|\r))sU',
                '(<<<(\s*)([\w\d]+)(.*[\r\n])\2(\r\n|\n|\r))sU',
                '(<<<(\s*)(["\'])([\w\d]+)\2(.*[\r\n])\3;(\r\n|\n|\r))sU',
                '(<<<(\s*)(["\'])([\w\d]+)\2(.*[\r\n])\3(\s*),(\s*))sU',
                '(<<<(\s*)(["\'])([\w\d]+)\2(.*[\r\n])\3(\s*)\)(\s*))sU'
            ),
            array(
                ':::\\1',
                "<<<\\1\\2\\3\\2;\\4/*\"*/;",
                "<<<\\1\\2\\3\\2;\\4/*\"*/",
                "<<<\\1\\3\\4\\3;\\5/*\\2*/;",
                "<<<\\1\\3\\4\\3;\\5/*\\2*/,\\6",
                "<<<\\1\\3\\4\\3;\\5/*\\2*/)\\6"
            ),
            $source
        );

        $tokens = self::doTokenize($source);

        $result = array();
        for ($i = 0, $c = count($tokens); $i < $c; ++$i) {
            if (is_string($tokens[$i])) {
                $result[] = str_replace(':::', '\\', $tokens[$i]);
            } elseif ($tokens[$i][0] !== T_DOUBLE_COLON) {
                $tokens[$i][1] = str_replace(':::', '\\', $tokens[$i][1]);
                $result[]      = $tokens[$i];
            } elseif (!isset($tokens[$i + 1]) || $tokens[$i + 1] !== ':') {
                $tokens[$i][1] = str_replace(':::', '\\', $tokens[$i][1]);
                $result[]      = $tokens[$i];
            } else {
                $result[] = '\\';
                ++$i;
            }
        }
        return $result;
    }

    /**
     * Executes the internal tokenizer function and decorates it with some
     * exception handling.
     *
     * @param  string $source The raw php source code.
     * @return array
     * @throws \PDepend\Source\Parser\TokenException
     * @todo   Exception should be moved into a general namespace.
     */
    private static function doTokenize($source)
    {
        ini_set('track_errors', 'on');
        $php_errormsg = null;

        $tokens = @token_get_all($source);

        if ($php_errormsg === null) {
            return $tokens;
        }
        throw new TokenException($php_errormsg);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.3
 */

namespace PDepend\Source\Language\PHP;

use PDepend\Source\AST\ASTArguments;
use PDepend\Source\AST\ASTValue;
use PDepend\Source\Parser\UnexpectedTokenException;
use PDepend\Source\Tokenizer\Tokenizer;
use PDepend\Source\Tokenizer\Tokens;

/**
 * Concrete parser implementation that supports features up to PHP version 5.6.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.3
 */
abstract class PHPParserVersion56 extends PHPParserVersion55
{
    /**
     * Parses additional static values that are valid in the supported php version.
     *
     * @param  \PDepend\Source\AST\ASTValue $value
     * @return \PDepend\Source\AST\ASTValue
     * @throws \PDepend\Source\Parser\UnexpectedTokenException
     */
    protected function parseStaticValueVersionSpecific(ASTValue $value)
    {
        $expressions = array();

        while (($tokenType = $this->tokenizer->peek()) != Tokenizer::T_EOF) {
            $expr = null;

            switch ($tokenType) {
                case Tokens::T_COMMA:
                case Tokens::T_CLOSE_TAG:
                case Tokens::T_COLON:
                case Tokens::T_DOUBLE_ARROW:
                case Tokens::T_END_HEREDOC:
                case Tokens::T_PARENTHESIS_CLOSE:
                case Tokens::T_SEMICOLON:
                case Tokens::T_SQUARED_BRACKET_CLOSE:
                    break 2;
                case Tokens::T_SELF:
                case Tokens::T_STRING:
                case Tokens::T_PARENT:
                case Tokens::T_STATIC:
                case Tokens::T_DOLLAR:
                case Tokens::T_VARIABLE:
                case Tokens::T_BACKSLASH:
                case Tokens::T_NAMESPACE:
                    $expressions[] = $this->parseVariableOrConstantOrPrimaryPrefix();
                    break;
                case ($this->isArrayStartDelimiter()):
                    $expressions[] = $this->doParseArray(true);
                    break;
                case Tokens::T_NULL:
                case Tokens::T_TRUE:
                case Tokens::T_FALSE:
                case Tokens::T_LNUMBER:
                case Tokens::T_DNUMBER:
                case Tokens::T_BACKTICK:
                case Tokens::T_DOUBLE_QUOTE:
                case Tokens::T_CONSTANT_ENCAPSED_STRING:
                    $expressions[] = $this->parseLiteralOrString();
                    break;
                case Tokens::T_QUESTION_MARK:
                    $expressions[] = $this->parseConditionalExpression();
                    break;
                case Tokens::T_BOOLEAN_AND:
                    $expressions[] = $this->parseBooleanAndExpression();
                    break;
                case Tokens::T_BOOLEAN_OR:
                    $expressions[] = $this->parseBooleanOrExpression();
                    break;
                case Tokens::T_LOGICAL_AND:
                    $expressions[] = $this->parseLogicalAndExpression();
                    break;
                case Tokens::T_LOGICAL_OR:
                    $expressions[] = $this->parseLogicalOrExpression();
                    break;
                case Tokens::T_LOGICAL_XOR:
                    $expressions[] = $this->parseLogicalXorExpression();
                    break;
                case Tokens::T_PARENTHESIS_OPEN:
                    $expressions[] = $this->parseParenthesisExpressionOrPrimaryPrefix();
                    break;
                case Tokens::T_START_HEREDOC:
                    $expressions[] = $this->parseHeredoc();
                    break;
                case Tokens::T_SL:
                    $expressions[] = $this->parseShiftLeftExpression();
                    break;
                case Tokens::T_SR:
                    $expressions[] = $this->parseShiftRightExpression();
                    break;
                case Tokens::T_STRING_VARNAME: // TODO: Implement this
                case Tokens::T_PLUS: // TODO: Make this a arithmetic expression
                case Tokens::T_MINUS:
                case Tokens::T_MUL:
                case Tokens::T_DIV:
                case Tokens::T_MOD:
                case Tokens::T_POW:
                case Tokens::T_IS_EQUAL: // TODO: Implement compare expressions
                case Tokens::T_IS_NOT_EQUAL:
                case Tokens::T_IS_IDENTICAL:
                case Tokens::T_IS_NOT_IDENTICAL:
                case Tokens::T_BITWISE_OR:
                case Tokens::T_BITWISE_AND:
                case Tokens::T_BITWISE_NOT:
                case Tokens::T_BITWISE_XOR:
                case Tokens::T_IS_GREATER_OR_EQUAL:
                case Tokens::T_IS_SMALLER_OR_EQUAL:
                case Tokens::T_ANGLE_BRACKET_OPEN:
                case Tokens::T_ANGLE_BRACKET_CLOSE:
                case Tokens::T_EMPTY:
                case Tokens::T_CONCAT:
                    $token = $this->consumeToken($tokenType);

                    $expr = $this->builder->buildAstExpression($token->image);
                    $expr->configureLinesAndColumns(
                        $token->startLine,
                        $token->endLine,
                        $token->startColumn,
                        $token->endColumn
                    );

                    $expressions[] = $expr;
                    break;
                case Tokens::T_EQUAL:
                case Tokens::T_OR_EQUAL:
                case Tokens::T_SL_EQUAL:
                case Tokens::T_SR_EQUAL:
                case Tokens::T_AND_EQUAL:
                case Tokens::T_DIV_EQUAL:
                case Tokens::T_MOD_EQUAL:
                case Tokens::T_MUL_EQUAL:
                case Tokens::T_XOR_EQUAL:
                case Tokens::T_PLUS_EQUAL:
                case Tokens::T_MINUS_EQUAL:
                case Tokens::T_CONCAT_EQUAL:
                    $expressions[] = $this->parseAssignmentExpression(
                        array_pop($expressions)
                    );
                    break;
                case Tokens::T_DIR:
                case Tokens::T_FILE:
                case Tokens::T_LINE:
                case Tokens::T_NS_C:
                case Tokens::T_FUNC_C:
                case Tokens::T_CLASS_C:
                case Tokens::T_METHOD_C:
                    $expressions[] = $this->parseConstant();
                    break;
                // TODO: Handle comments here
                case Tokens::T_COMMENT:
                case Tokens::T_DOC_COMMENT:
                    $this->consumeToken($tokenType);
                    break;
                case Tokens::T_AT:
                case Tokens::T_EXCLAMATION_MARK:
                    $token = $this->consumeToken($tokenType);

                    $expr = $this->builder->buildAstUnaryExpression($token->image);
                    $expr->configureLinesAndColumns(
                        $token->startLine,
                        $token->endLine,
                        $token->startColumn,
                        $token->endColumn
                    );

                    $expressions[] = $expr;
                    break;
                default:
                    throw new UnexpectedTokenException(
                        $this->tokenizer->next(),
                        $this->tokenizer->getSourceFile()
                    );
            }
        }

        $expressions = $this->reduce($expressions);

        $count = count($expressions);
        if ($count == 0) {
            return null;
        } elseif ($count == 1) {
            // @todo ASTValue must be a valid node.
            $value->setValue($expressions[0]);

            return $value;
        }

        $expr = $this->builder->buildAstExpression();
        foreach ($expressions as $node) {
            $expr->addChild($node);
        }
        $expr->configureLinesAndColumns(
            $expressions[0]->getStartLine(),
            $expressions[$count - 1]->getEndLine(),
            $expressions[0]->getStartColumn(),
            $expressions[$count - 1]->getEndColumn()
        );

        // @todo ASTValue must be a valid node.
        $value->setValue($expr);

        return $value;
    }

    /**
     * Parses use declarations that are valid in the supported php version.
     *
     * @return void
     */
    protected function parseUseDeclarations()
    {
        // Consume use keyword
        $this->consumeToken(Tokens::T_USE);
        $this->consumeComments();

        // Consume const and function tokens
        $nextToken = $this->tokenizer->peek();
        switch ($nextToken) {
            case Tokens::T_CONST:
            case Tokens::T_FUNCTION:
                $this->consumeToken($nextToken);
        }

        // Parse all use declarations
        $this->parseUseDeclaration();
        $this->consumeComments();

        // Consume closing semicolon
        $this->consumeToken(Tokens::T_SEMICOLON);

        // Reset any previous state
        $this->reset();
    }

    /**
     * This method will be called when the base parser cannot handle an expression
     * in the base version. In this method you can implement version specific
     * expressions.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @throws \PDepend\Source\Parser\UnexpectedTokenException
     * @since 2.2
     */
    protected function parseOptionalExpressionForVersion()
    {
        if ($expression = $this->parseExpressionVersion56()) {
            return $expression;
        }
        return parent::parseOptionalExpressionForVersion();
    }

    /**
     * In this method we implement parsing of PHP 5.6 specific expressions.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @since 2.3
     */
    protected function parseExpressionVersion56()
    {
        $this->consumeComments();
        $nextTokenType = $this->tokenizer->peek();

        switch ($nextTokenType) {
            case Tokens::T_POW:
                $token = $this->consumeToken($nextTokenType);

                $expr = $this->builder->buildAstExpression($token->image);
                $expr->configureLinesAndColumns(
                    $token->startLine,
                    $token->endLine,
                    $token->startColumn,
                    $token->endColumn
                );

                return $expr;
        }
    }

    /**
     * @param \PDepend\Source\AST\ASTArguments $arguments
     * @return \PDepend\Source\AST\ASTArguments
     */
    protected function parseArgumentList(ASTArguments $arguments)
    {
        while (true) {
            $this->consumeComments();
            if (Tokens::T_ELLIPSIS === $this->tokenizer->peek()) {
                $this->consumeToken(Tokens::T_ELLIPSIS);
            }

            $this->consumeComments();
            if (null === ($expr = $this->parseOptionalExpression())) {
                break;
            }

            $arguments->addChild($expr);

            $this->consumeComments();
            if (Tokens::T_COMMA === $this->tokenizer->peek()) {
                $this->consumeToken(Tokens::T_COMMA);
                $this->consumeComments();

                continue;
            }
        }

        return $arguments;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.3
 */

namespace PDepend\Source\Language\PHP;

/**
 * Concrete parser implementation that supports features up to PHP version 5.5.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.3
 */
abstract class PHPParserVersion55 extends PHPParserVersion54
{

}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.3
 */

namespace PDepend\Source\Language\PHP;

use PDepend\Source\AST\ASTArray;
use PDepend\Source\Parser\UnexpectedTokenException;
use PDepend\Source\Tokenizer\Tokens;

/**
 * Concrete parser implementation that supports features up to PHP version 5.5.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.3
 */
abstract class PHPParserVersion53 extends AbstractPHPParser
{

    /**
     * Tests if the next token is a valid array start delimiter in the supported
     * PHP version.
     *
     * @return boolean
     * @since 1.0.0
     */
    protected function isArrayStartDelimiter()
    {
        switch ($this->tokenizer->peek()) {
            case Tokens::T_ARRAY:
                return true;
        }
        return false;
    }

    /**
     * Parses a php array declaration.
     *
     * @param \PDepend\Source\AST\ASTArray $array
     * @param boolean $static
     * @return \PDepend\Source\AST\ASTArray
     * @since 1.0.0
     */
    protected function parseArray(ASTArray $array, $static = false)
    {
        switch ($this->tokenizer->peek()) {
            case Tokens::T_ARRAY:
                $this->consumeToken(Tokens::T_ARRAY);
                $this->consumeComments();
                $this->consumeToken(Tokens::T_PARENTHESIS_OPEN);
                $this->parseArrayElements($array, Tokens::T_PARENTHESIS_CLOSE, $static);
                $this->consumeToken(Tokens::T_PARENTHESIS_CLOSE);
                break;
            default:
                throw new UnexpectedTokenException(
                    $this->tokenizer->next(),
                    $this->tokenizer->getSourceFile()
                );
        }
        return $array;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\Parser;

/**
 * This class provides a simple hashmap for name mappings done by the parser.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class SymbolTable
{
    /**
     * Stack with all active scopes.
     *
     * @var array(array)
     */
    private $scopeStack = array();

    /**
     * The currently active scope.
     *
     * @var array(string=>string)
     */
    private $scope = array();

    /**
     * This method creates a new scope.
     *
     * @return void
     */
    public function createScope()
    {
        // Add copy of last scope as new scope
        array_push($this->scopeStack, $this->scope);
    }

    /**
     * This method destroys the top most scope.
     *
     * @throws NoActiveScopeException
     *
     * @return void
     */
    public function destroyScope()
    {
        $this->ensureActiveScopeExists();

        // Destroy current active scope
        $this->scope = null;

        // Try to restore previously active scope
        if (count($this->scopeStack) > 0) {
            $this->scope = array_pop($this->scopeStack);
        }
    }

    /**
     * Adds a new value to the top most scope.
     *
     * @param  string $key   The key of this scope value.
     * @param  mixed  $value A new scope value.
     *
     * @throws NoActiveScopeException
     *
     * @return void
     */
    public function add($key, $value)
    {
        $this->ensureActiveScopeExists();
        $this->scope[$this->normalizeKey($key)] = $value;
    }

    /**
     * Resets the current scope
     *
     * @throws NoActiveScopeException
     *
     * @return void
     */
    public function resetScope()
    {
        $this->ensureActiveScopeExists();
        $this->scope = array();
    }

    /**
     * This method will return the registered value for the given key, when it
     * exists in the current scope. The returned value will <b>null</b> if no
     * value exists for the given key.
     *
     * @param string $key The key for a searched scope value.
     *
     * @throws NoActiveScopeException
     *
     * @return mixed
     */
    public function lookup($key)
    {
        $this->ensureActiveScopeExists();

        $normalizedKey = $this->normalizeKey($key);

        return isset($this->scope[$normalizedKey])
            ? $this->scope[$normalizedKey]
            : null;
    }

    /**
     * Checks if there is an active scope.
     *
     * @throws NoActiveScopeException if no active scope exists.
     *
     * @return void
     */
    private function ensureActiveScopeExists()
    {
        if (null === $this->scope) {
            throw new NoActiveScopeException();
        }
    }

    /**
     * Normalizes the <code>$key</code>, so it's the same for
     * <code>add()</code> and <code>lookup()</code> operations.
     *
     * @param string $key
     *
     * @return string normalized key
     */
    private function normalizeKey($key)
    {
        return strtolower($key);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\Parser;

use PDepend\Source\Tokenizer\Token;
use PDepend\Source\Tokenizer\Tokenizer;

/**
 * This type of exception is thrown when a parameter or property declaration
 * should contain a default value, but this value was not defined.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class MissingValueException extends ParserException
{
    /**
     * Constructs a new missing value exception.
     *
     * @param \PDepend\Source\Tokenizer\Tokenizer $tokenizer
     */
    public function __construct(Tokenizer $tokenizer)
    {
        // Get wrong token
        $token = $tokenizer->next();
        // The parser must take care for this
        assert($token instanceof Token);

        $message = sprintf(
            'Missing default value on line: %d, col: %d, file: %s.',
            $token->startLine,
            $token->startColumn,
            $tokenizer->getSourceFile()
        );

        parent::__construct($message);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\Parser;

/**
 * This type of exception is thrown when the parser reaches an invalid state
 * and the parsed source does not fill the expected structure.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class InvalidStateException extends ParserException
{
    /**
     * Constructs a new invalid state exception.
     *
     * @param integer $lineNumber Line number where the parser has stopped.
     * @param string  $fileName   The source file where this exception occurred.
     * @param string  $reason     Short description what has happened.
     */
    public function __construct($lineNumber, $fileName, $reason)
    {
        parent::__construct(
            sprintf(
                'The parser has reached an invalid state near line "%d" in file ' .
                '"%s". Please check the following conditions: %s',
                $lineNumber,
                $fileName,
                $reason
            )
        );
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\Parser;

use PDepend\Source\Tokenizer\Token;

/**
 * This class provides a scoped collection for {@link \PDepend\Source\Tokenizer\Token}
 * objects.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class TokenStack
{
    /**
     * The actual token scope.
     *
     * @var \PDepend\Source\Tokenizer\Token[]
     */
    private $tokens = array();

    /**
     * Stack with token scopes.
     *
     * @var \PDepend\Source\Tokenizer\Token[][]
     */
    private $stack = array();

    /**
     * The current stack offset.
     *
     * @var integer
     */
    private $offset = 0;

    /**
     * This method will push a new token scope onto the stack,
     *
     * @return void
     */
    public function push()
    {
        $this->stack[$this->offset++] = $this->tokens;
        $this->tokens                  = array();
    }

    /**
     * This method will pop the top token scope from the stack and return an
     * array with all collected tokens. Additionally this method will add all
     * tokens of the removed scope onto the next token scope.
     *
     * @return \PDepend\Source\Tokenizer\Token[]
     */
    public function pop()
    {
        $tokens        = $this->tokens;
        $this->tokens = $this->stack[--$this->offset];

        unset($this->stack[$this->offset]);

        foreach ($tokens as $token) {
            $this->tokens[] = $token;
        }
        return $tokens;
    }

    /**
     * This method will add a new token to the currently active token scope.
     *
     * @param  \PDepend\Source\Tokenizer\Token $token The token to add.
     * @return \PDepend\Source\Tokenizer\Token
     */
    public function add(Token $token)
    {
        return ($this->tokens[] = $token);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\Parser;

/**
 * This type of exception is thrown when an operation is performed
 * on a symbol table and there is no active scope.
 */
class NoActiveScopeException extends ParserException
{
    /**
     * Constructs a new no active scope exception.
     */
    public function __construct()
    {
        parent::__construct('No active scope in symbol table.');
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\Parser;

/**
 * Base class for exceptions that can occurred during the parsing process.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ParserException extends \RuntimeException
{
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\Parser;

use PDepend\Source\Tokenizer\Token;

/**
 * This type of exception is thrown when the parser detects an unexpected token.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class UnexpectedTokenException extends TokenException
{
    /**
     * Constructs a new unexpected token exception.
     *
     * @param Token  $token    The last parsed token instance.
     * @param string $fileName The file where the exception occurred.
     */
    public function __construct(Token $token, $fileName)
    {
        $message = sprintf(
            'Unexpected token: %s, line: %d, col: %d, file: %s.',
            $token->image,
            $token->startLine,
            $token->startColumn,
            $fileName
        );

        parent::__construct($message);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\Parser;

use PDepend\Source\Tokenizer\Tokenizer;

/**
 * This type of exception is thrown when the parser reaches the end of the token
 * stream, but expects further tokens.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class TokenStreamEndException extends TokenException
{
    /**
     * Constructs a new end of token stream exception.
     *
     * @param \PDepend\Source\Tokenizer\Tokenizer $tokenizer
     */
    public function __construct(Tokenizer $tokenizer)
    {
        parent::__construct(
            sprintf(
                'Unexpected end of token stream in file: %s.',
                $tokenizer->getSourceFile()
            )
        );
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.10
 */

namespace PDepend\Source\Parser;

/**
 * Base class for token/token stream related exceptions.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.10
 */
class TokenException extends ParserException
{
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  */

namespace PDepend\Source\Builder;

use PDepend\Source\AST\AbstractASTClassOrInterface;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTClassOrInterfaceReference;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTTrait;
use PDepend\Util\Cache\CacheDriver;

/**
 * Base interface for all code node builders.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface Builder extends \IteratorAggregate
{
    /**
     * The default package name.
     */
    const DEFAULT_NAMESPACE = '+global';

    /**
     * Setter method for the currently used token cache.
     *
     * @param  \PDepend\Util\Cache\CacheDriver $cache
     * @return \PDepend\Source\Builder\Builder
     * @since  0.10.0
     */
    public function setCache(CacheDriver $cache);

    /**
     * Restores a function within the internal type scope.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     * @since  0.10.0
     */
    public function restoreFunction(ASTFunction $function);

    /**
     * This method will try to find an already existing instance for the given
     * qualified name. It will create a new {@link \PDepend\Source\AST\ASTClass}
     * instance when no matching type exists.
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\AbstractASTClassOrInterface
     * @since  0.9.5
     */
    public function getClassOrInterface($qualifiedName);

    /**
     * Builds a new code type reference instance.
     *
     * @param string $qualifiedName The qualified name of the referenced type.
     *
     * @return \PDepend\Source\AST\ASTClassOrInterfaceReference
     * @since  0.9.5
     */
    public function buildAstClassOrInterfaceReference($qualifiedName);

    /**
     * Builds a new php trait instance.
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\ASTTrait
     * @since  1.0.0
     */
    public function buildTrait($qualifiedName);

    /**
     * Restores an existing trait instance within the context of this builder.
     *
     * @param  \PDepend\Source\AST\ASTTrait $trait
     * @return void
     * @since  1.0.0
     */
    public function restoreTrait(ASTTrait $trait);

    /**
     * This method will try to find an already existing instance for the given
     * qualified name. It will create a new {@link \PDepend\Source\AST\ASTTrait}
     * instance when no matching type exists.
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\ASTTrait
     * @since  1.0.0
     */
    public function getTrait($qualifiedName);

    /**
     * Builds a new code class instance.
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\ASTClass
     */
    public function buildClass($qualifiedName);

    /**
     * Builds an anonymous class instance.
     *
     * @return \PDepend\Source\AST\ASTAnonymousClass
     */
    public function buildAnonymousClass();

    /**
     * This method will try to find an already existing instance for the given
     * qualified name. It will create a new {@link \PDepend\Source\AST\ASTClass}
     * instance when no matching type exists.
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\ASTClass
     * @since  0.9.5
     */
    public function getClass($qualifiedName);

    /**
     * Restores an existing class instance within the context of this builder.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     * @since  0.10.0
     */
    public function restoreClass(ASTClass $class);

    /**
     * Builds a new code type reference instance.
     *
     * @param  string $qualifiedName The qualified name of the referenced type.
     * @return \PDepend\Source\AST\ASTClassReference
     * @since  0.9.5
     */
    public function buildAstClassReference($qualifiedName);

    /**
     * Builds a new new interface instance.
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\ASTInterface
     */
    public function buildInterface($qualifiedName);

    /**
     * Restores an existing interface instance within the context of this builder.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     * @since  0.10.0
     */
    public function restoreInterface(ASTInterface $interface);

    /**
     * This method will try to find an already existing instance for the given
     * qualified name. It will create a new {@link \PDepend\Source\AST\ASTInterface}
     * instance when no matching type exists.
     *
     * @param  string $qualifiedName The full qualified type identifier.
     * @return \PDepend\Source\AST\ASTInterface
     * @since  0.9.5
     */
    public function getInterface($qualifiedName);

    /**
     * Builds a new namespace instance.
     *
     * @param  string $name
     * @return \PDepend\Source\AST\ASTNamespace
     */
    public function buildNamespace($name);

    /**
     * Builds a new method instance.
     *
     * @param  string $name
     * @return \PDepend\Source\AST\ASTMethod
     */
    public function buildMethod($name);

    /**
     * Builds a new function instance.
     *
     * @param  string $name
     * @return \PDepend\Source\AST\ASTFunction
     */
    public function buildFunction($name);

    /**
     * Builds a new self reference instance.
     *
     * @param  \PDepend\Source\AST\AbstractASTClassOrInterface $type
     * @return \PDepend\Source\AST\ASTSelfReference
     * @since  0.9.6
     */
    public function buildAstSelfReference(AbstractASTClassOrInterface $type);

    /**
     * Builds a new parent reference instance.
     *
     * @param  \PDepend\Source\AST\ASTClassOrInterfaceReference $reference The type
     *        instance that reference the concrete target of parent.
     * @return \PDepend\Source\AST\ASTParentReference
     * @since  0.9.6
     */
    public function buildAstParentReference(ASTClassOrInterfaceReference $reference);

    /**
     * Builds a new static reference instance.
     *
     * @param  \PDepend\Source\AST\AbstractASTClassOrInterface $owner
     * @return \PDepend\Source\AST\ASTStaticReference
     * @since  0.9.6
     */
    public function buildAstStaticReference(AbstractASTClassOrInterface $owner);

    /**
     * Builds a new field declaration node.
     *
     * @return \PDepend\Source\AST\ASTFieldDeclaration
     * @since  0.9.6
     */
    public function buildAstFieldDeclaration();

    /**
     * Builds a new variable declarator node.
     *
     * @param string $image The source image for the variable declarator.
     *
     * @return \PDepend\Source\AST\ASTVariableDeclarator
     * @since  0.9.6
     */
    public function buildAstVariableDeclarator($image);

    /**
     * Builds a new constant node.
     *
     * @param string $image The source image for the constant.
     *
     * @return \PDepend\Source\AST\ASTConstant
     * @since  0.9.6
     */
    public function buildAstConstant($image);

    /**
     * Builds a new variable node.
     *
     * @param string $image The source image for the variable.
     *
     * @return \PDepend\Source\AST\ASTVariable
     * @since  0.9.6
     */
    public function buildAstVariable($image);

    /**
     * Builds a new variable variable node.
     *
     * @param string $image The source image for the variable variable.
     *
     * @return \PDepend\Source\AST\ASTVariableVariable
     * @since  0.9.6
     */
    public function buildAstVariableVariable($image);

    /**
     * Builds a new compound variable node.
     *
     * @param string $image The source image for the compound variable.
     *
     * @return \PDepend\Source\AST\ASTCompoundVariable
     * @since  0.9.6
     */
    public function buildAstCompoundVariable($image);

    /**
     * Builds a new compound expression node.
     *
     * @return \PDepend\Source\AST\ASTCompoundExpression
     * @since  0.9.6
     */
    public function buildAstCompoundExpression();

    /**
     * Builds a new static variable declaration node.
     *
     * @param string $image The source image for the static declaration.
     *
     * @return \PDepend\Source\AST\ASTStaticVariableDeclaration
     * @since  0.9.6
     */
    public function buildAstStaticVariableDeclaration($image);

    /**
     * Builds a new closure node.
     *
     * @return \PDepend\Source\AST\ASTClosure
     * @since  0.9.12
     */
    public function buildAstClosure();

    /**
     * Builds a new formal parameters node.
     *
     * @return \PDepend\Source\AST\ASTFormalParameters
     * @since  0.9.6
     */
    public function buildAstFormalParameters();

    /**
     * Builds a new formal parameter node.
     *
     * @return \PDepend\Source\AST\ASTFormalParameter
     * @since  0.9.6
     */
    public function buildAstFormalParameter();

    /**
     * Builds a new expression node.
     *
     * @param string $image
     * @return \PDepend\Source\AST\ASTExpression
     * @since 0.9.8
     */
    public function buildAstExpression($image = null);

    /**
     * Builds a new assignment expression node.
     *
     * @param string $image The assignment operator.
     *
     * @return \PDepend\Source\AST\ASTAssignmentExpression
     * @since  0.9.8
     */
    public function buildAstAssignmentExpression($image);

    /**
     * Builds a new allocation expression node.
     *
     * @param string $image The source image of this expression.
     *
     * @return \PDepend\Source\AST\ASTAllocationExpression
     * @since  0.9.6
     */
    public function buildAstAllocationExpression($image);

    /**
     * Builds a new eval-expression node.
     *
     * @param string $image The source image of this expression.
     *
     * @return \PDepend\Source\AST\ASTEvalExpression
     * @since  0.9.12
     */
    public function buildAstEvalExpression($image);

    /**
     * Builds a new exit-expression instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTExitExpression
     * @since  0.9.12
     */
    public function buildAstExitExpression($image);

    /**
     * Builds a new clone-expression node.
     *
     * @param string $image The source image of this expression.
     *
     * @return \PDepend\Source\AST\ASTCloneExpression
     * @since  0.9.12
     */
    public function buildAstCloneExpression($image);

    /**
     * Builds a new list-expression node.
     *
     * @param string $image The source image of this expression.
     *
     * @return \PDepend\Source\AST\ASTListExpression
     * @since  0.9.12
     */
    public function buildAstListExpression($image);

    /**
     * Builds a new include- or include_once-expression.
     *
     * @return \PDepend\Source\AST\ASTIncludeExpression
     * @since  0.9.12
     */
    public function buildAstIncludeExpression();

    /**
     * Builds a new require- or require_once-expression.
     *
     * @return \PDepend\Source\AST\ASTRequireExpression
     * @since  0.9.12
     */
    public function buildAstRequireExpression();

    /**
     * Builds a new array-expression node.
     *
     * @return \PDepend\Source\AST\ASTArrayIndexExpression
     * @since  0.9.12
     */
    public function buildAstArrayIndexExpression();

    /**
     * Builds a new string-expression node.
     *
     * <code>
     * //     --------
     * $string{$index}
     * //     --------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTStringIndexExpression
     * @since  0.9.12
     */
    public function buildAstStringIndexExpression();

    /**
     * Builds a new instanceof-expression node.
     *
     * @param string $image The source image of this expression.
     *
     * @return \PDepend\Source\AST\ASTInstanceOfExpression
     * @since  0.9.6
     */
    public function buildAstInstanceOfExpression($image);

    /**
     * Builds a new isset-expression node.
     *
     * <code>
     * //  -----------
     * if (isset($foo)) {
     * //  -----------
     * }
     *
     * //  -----------------------
     * if (isset($foo, $bar, $baz)) {
     * //  -----------------------
     * }
     * </code>
     *
     * @return \PDepend\Source\AST\ASTIssetExpression
     * @since  0.9.12
     */
    public function buildAstIssetExpression();

    /**
     * Builds a new boolean conditional-expression.
     *
     * <code>
     *         --------------
     * $bar = ($foo ? 42 : 23);
     *         --------------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTConditionalExpression
     * @since  0.9.8
     */
    public function buildAstConditionalExpression();

    /**
     * Builds a new print-expression.
     *
     * <code>
     * -------------
     * print "qafoo";
     * -------------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTPrintExpression
     * @since 2.3
     */
    public function buildAstPrintExpression();

    /**
     * Build a new shift left expression.
     *
     * @return \PDepend\Source\AST\ASTShiftLeftExpression
     * @since  1.0.1
     */
    public function buildAstShiftLeftExpression();

    /**
     * Build a new shift right expression.
     *
     * @return \PDepend\Source\AST\ASTShiftRightExpression
     * @since  1.0.1
     */
    public function buildAstShiftRightExpression();

    /**
     * Builds a new boolean and-expression.
     *
     * @return \PDepend\Source\AST\ASTBooleanAndExpression
     * @since  0.9.8
     */
    public function buildAstBooleanAndExpression();

    /**
     * Builds a new boolean or-expression.
     *
     * @return \PDepend\Source\AST\ASTBooleanOrExpression
     * @since  0.9.8
     */
    public function buildAstBooleanOrExpression();

    /**
     * Builds a new logical <b>and</b>-expression.
     *
     * @return \PDepend\Source\AST\ASTLogicalAndExpression
     * @since  0.9.8
     */
    public function buildAstLogicalAndExpression();

    /**
     * Builds a new logical <b>or</b>-expression.
     *
     * @return \PDepend\Source\AST\ASTLogicalOrExpression
     * @since  0.9.8
     */
    public function buildAstLogicalOrExpression();

    /**
     * Builds a new logical <b>xor</b>-expression.
     *
     * @return \PDepend\Source\AST\ASTLogicalXorExpression
     * @since  0.9.8
     */
    public function buildAstLogicalXorExpression();

    /**
     * Builds a new trait use-statement node.
     *
     * @return \PDepend\Source\AST\ASTTraitUseStatement
     * @since  1.0.0
     */
    public function buildAstTraitUseStatement();

    /**
     * Builds a new trait adaptation scope.
     *
     * @return \PDepend\Source\AST\ASTTraitAdaptation
     * @since  1.0.0
     */
    public function buildAstTraitAdaptation();

    /**
     * Builds a new trait adaptation alias statement.
     *
     * @param string $image The trait method name.
     *
     * @return \PDepend\Source\AST\ASTTraitAdaptationAlias
     * @since  1.0.0
     */
    public function buildAstTraitAdaptationAlias($image);

    /**
     * Builds a new trait adaptation precedence statement.
     *
     * @param string $image The trait method name.
     *
     * @return \PDepend\Source\AST\ASTTraitAdaptationPrecedence
     * @since  1.0.0
     */
    public function buildAstTraitAdaptationPrecedence($image);

    /**
     * Builds a new trait reference node.
     *
     * @param string $qualifiedName The full qualified trait name.
     *
     * @return \PDepend\Source\AST\ASTTraitReference
     * @since  1.0.0
     */
    public function buildAstTraitReference($qualifiedName);

    /**
     * Builds a new switch-statement-node.
     *
     * @return \PDepend\Source\AST\ASTSwitchStatement
     * @since  0.9.8
     */
    public function buildAstSwitchStatement();

    /**
     * Builds a new switch-label node.
     *
     * @param string $image The source image of this label.
     *
     * @return \PDepend\Source\AST\ASTSwitchLabel
     * @since  0.9.8
     */
    public function buildAstSwitchLabel($image);

    /**
     * Builds a new catch-statement node.
     *
     * @param string $image The source image of this statement.
     *
     * @return \PDepend\Source\AST\ASTCatchStatement
     * @since  0.9.8
     */
    public function buildAstCatchStatement($image);

    /**
     * Builds a new finally-statement node.
     *
     * @return \PDepend\Source\AST\ASTFinallyStatement
     * @since  2.0.0
     */
    public function buildAstFinallyStatement();

    /**
     * Builds a new if statement node.
     *
     * @param string $image The source image of this statement.
     *
     * @return \PDepend\Source\AST\ASTIfStatement
     * @since  0.9.8
     */
    public function buildAstIfStatement($image);

    /**
     * Builds a new elseif-statement node.
     *
     * @param string $image The source image of this statement.
     *
     * @return \PDepend\Source\AST\ASTElseIfStatement
     * @since  0.9.8
     */
    public function buildAstElseIfStatement($image);

    /**
     * Builds a new for-statement node.
     *
     * @param string $image The source image of this statement.
     *
     * @return \PDepend\Source\AST\ASTForStatement
     * @since  0.9.8
     */
    public function buildAstForStatement($image);

    /**
     * Builds a new for-init node.
     *
     * <code>
     *      ------------------------
     * for ($x = 0, $y = 23, $z = 42; $x < $y; ++$x) {}
     *      ------------------------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTForInit
     * @since  0.9.8
     */
    public function buildAstForInit();

    /**
     * Builds a new for-update node.
     *
     * <code>
     *                                        -------------------------------
     * for ($x = 0, $y = 23, $z = 42; $x < $y; ++$x, $y = $x + 1, $z = $x + 2) {}
     *                                        -------------------------------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTForUpdate
     * @since  0.9.12
     */
    public function buildAstForUpdate();

    /**
     * Builds a new foreach-statement node.
     *
     * @param string $image The source image of this statement.
     *
     * @return \PDepend\Source\AST\ASTForeachStatement
     * @since  0.9.8
     */
    public function buildAstForeachStatement($image);

    /**
     * Builds a new while-statement node.
     *
     * @param string $image The source image of this statement.
     *
     * @return \PDepend\Source\AST\ASTWhileStatement
     * @since  0.9.8
     */
    public function buildAstWhileStatement($image);

    /**
     * Builds a new do/while-statement node.
     *
     * @param string $image The source image of this statement.
     *
     * @return \PDepend\Source\AST\ASTDoWhileStatement
     * @since  0.9.12
     */
    public function buildAstDoWhileStatement($image);

    /**
     * Builds a new declare-statement node.
     *
     * <code>
     * -------------------------------
     * declare(encoding='ISO-8859-1');
     * -------------------------------
     *
     * -------------------
     * declare(ticks=42) {
     *     // ...
     * }
     * -
     *
     * ------------------
     * declare(ticks=42):
     *     // ...
     * enddeclare;
     * -----------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTDeclareStatement
     * @since  0.10.0
     */
    public function buildAstDeclareStatement();

    /**
     * Builds a new member primary expression node.
     *
     * <code>
     * //--------
     * Foo::bar();
     * //--------
     *
     * //---------
     * Foo::$bar();
     * //---------
     *
     * //---------
     * $obj->bar();
     * //---------
     *
     * //----------
     * $obj->$bar();
     * //----------
     * </code>
     *
     * @param string $image The source image of this expression.
     *
     * @return \PDepend\Source\AST\ASTMemberPrimaryPrefix
     * @since  0.9.6
     */
    public function buildAstMemberPrimaryPrefix($image);

    /**
     * Builds a new identifier node.
     *
     * @param string $image The image of this identifier.
     *
     * @return \PDepend\Source\AST\ASTIdentifier
     * @since  0.9.6
     */
    public function buildAstIdentifier($image);

    /**
     * Builds a new function postfix expression.
     *
     * <code>
     * //-------
     * foo($bar);
     * //-------
     *
     * //--------
     * $foo($bar);
     * //--------
     * </code>
     *
     * @param string $image The image of this node.
     *
     * @return \PDepend\Source\AST\ASTFunctionPostfix
     * @since  0.9.6
     */
    public function buildAstFunctionPostfix($image);

    /**
     * Builds a new method postfix expression.
     *
     * <code>
     * //   ---------
     * Foo::bar($baz);
     * //   ---------
     *
     * //   ----------
     * Foo::$bar($baz);
     * //   ----------
     * </code>
     *
     * @param string $image The image of this node.
     *
     * @return \PDepend\Source\AST\ASTMethodPostfix
     * @since  0.9.6
     */
    public function buildAstMethodPostfix($image);

    /**
     * Builds a new constant postfix expression.
     *
     * <code>
     * //   ---
     * Foo::BAR;
     * //   ---
     * </code>
     *
     * @param string $image The image of this node.
     *
     * @return \PDepend\Source\AST\ASTConstantPostfix
     * @since  0.9.6
     */
    public function buildAstConstantPostfix($image);

    /**
     * Builds a new property postfix expression.
     *
     * <code>
     * //   ----
     * Foo::$bar;
     * //   ----
     *
     * //       ---
     * $object->bar;
     * //       ---
     * </code>
     *
     * @param string $image The image of this node.
     *
     * @return \PDepend\Source\AST\ASTPropertyPostfix
     * @since  0.9.6
     */
    public function buildAstPropertyPostfix($image);

    /**
     * Builds a new full qualified class name postfix expression.
     *
     * <code>
     * //   -----
     * Foo::class;
     * //   -----
     *
     * //       -----
     * $object::class;
     * //       -----
     * </code>
     *
     * @return \PDepend\Source\AST\ASTClassFqnPostfix
     * @since  2.0.0
     */
    public function buildAstClassFqnPostfix();

    /**
     * Builds a new arguments list.
     *
     * <code>
     * //      ------------
     * Foo::bar($x, $y, $z);
     * //      ------------
     *
     * //       ------------
     * $foo->bar($x, $y, $z);
     * //       ------------
     * </code>
     *
     * @return \PDepend\Source\AST\ASTArguments
     * @since  0.9.6
     */
    public function buildAstArguments();

    /**
     * Builds a new array type node.
     *
     * @return \PDepend\Source\AST\ASTTypeArray
     * @since  0.9.6
     */
    public function buildAstTypeArray();

    /**
     * Builds a new node for the callable type.
     *
     * @return \PDepend\Source\AST\ASTTypeCallable
     * @since  1.0.0
     */
    public function buildAstTypeCallable();

    /**
     * Builds a new primitive type node.
     *
     * @param string $image
     * @return \PDepend\Source\AST\ASTScalarType
     * @since  0.9.6
     */
    public function buildAstScalarType($image);

    /**
     * Builds a new literal node.
     *
     * @param string $image The source image for the literal node.
     *
     * @return \PDepend\Source\AST\ASTLiteral
     * @since  0.9.6
     */
    public function buildAstLiteral($image);

    /**
     * Builds a new php string node.
     *
     * <code>
     * $string = "Manuel $Pichler <{$email}>";
     *
     * // \PDepend\Source\AST\ASTString
     * // |-- ASTLiteral             -  "Manuel ")
     * // |-- ASTVariable            -  $Pichler
     * // |-- ASTLiteral             -  " <"
     * // |-- ASTCompoundExpression  -  {...}
     * // |   |-- ASTVariable        -  $email
     * // |-- ASTLiteral             -  ">"
     * </code>
     *
     * @return \PDepend\Source\AST\ASTString
     * @since  0.9.10
     */
    public function buildAstString();

    /**
     * Builds a new php array node.
     *
     * @return \PDepend\Source\AST\ASTArray
     * @since  1.0.0
     */
    public function buildAstArray();

    /**
     * Builds a new array element node.
     *
     * @return \PDepend\Source\AST\ASTArrayElement
     * @since  1.0.0
     */
    public function buildAstArrayElement();

    /**
     * Builds a new heredoc node.
     *
     * @return \PDepend\Source\AST\ASTHeredoc
     * @since  0.9.12
     */
    public function buildAstHeredoc();

    /**
     * Builds a new constant definition node.
     *
     * <code>
     * class Foo
     * {
     * //  ------------------------
     *     const FOO = 42, BAR = 23;
     * //  ------------------------
     * }
     * </code>
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTConstantDefinition
     * @since  0.9.6
     */
    public function buildAstConstantDefinition($image);

    /**
     * Builds a new constant declarator node.
     *
     * <code>
     * class Foo
     * {
     *     //    --------
     *     const BAR = 42;
     *     //    --------
     * }
     * </code>
     *
     * Or in a comma separated constant defintion:
     *
     * <code>
     * class Foo
     * {
     *     //    --------
     *     const BAR = 42,
     *     //    --------
     *
     *     //    --------------
     *     const BAZ = 'Foobar',
     *     //    --------------
     *
     *     //    ----------
     *     const FOO = 3.14;
     *     //    ----------
     * }
     * </code>
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTConstantDeclarator
     * @since  0.9.6
     */
    public function buildAstConstantDeclarator($image);

    /**
     * Builds a new comment node instance.
     *
     * @param string $cdata The comment text.
     *
     * @return \PDepend\Source\AST\ASTComment
     * @since  0.9.8
     */
    public function buildAstComment($cdata);

    /**
     * Builds a new unary expression node instance.
     *
     * @param string $image The unary expression image/character.
     *
     * @return \PDepend\Source\AST\ASTUnaryExpression
     * @since  0.9.11
     */
    public function buildAstUnaryExpression($image);

    /**
     * Builds a new cast-expression node instance.
     *
     * @param string $image The cast-expression image/character.
     *
     * @return \PDepend\Source\AST\ASTCastExpression
     * @since  0.10.0
     */
    public function buildAstCastExpression($image);

    /**
     * Builds a new postfix-expression node instance.
     *
     * @param string $image The postfix-expression image/character.
     *
     * @return \PDepend\Source\AST\ASTPostfixExpression
     * @since  0.10.0
     */
    public function buildAstPostfixExpression($image);

    /**
     * Builds a new pre-increment-expression node instance.
     *
     * @return \PDepend\Source\AST\ASTPreIncrementExpression
     * @since  0.10.0
     */
    public function buildAstPreIncrementExpression();

    /**
     * Builds a new pre-decrement-expression node instance.
     *
     * @return \PDepend\Source\AST\ASTPreDecrementExpression
     * @since  0.10.0
     */
    public function buildAstPreDecrementExpression();

    /**
     * Builds a new function/method scope instance.
     *
     * @return \PDepend\Source\AST\ASTScope
     * @since  0.9.12
     */
    public function buildAstScope();

    /**
     * Builds a new statement instance.
     *
     * @return \PDepend\Source\AST\ASTStatement
     * @since  0.9.12
     */
    public function buildAstStatement();

    /**
     * Builds a new return-statement node instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTReturnStatement
     * @since  0.9.12
     */
    public function buildAstReturnStatement($image);

    /**
     * Builds a new break-statement node instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTBreakStatement
     * @since  0.9.12
     */
    public function buildAstBreakStatement($image);

    /**
     * Builds a new continue-statement node instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTContinueStatement
     * @since  0.9.12
     */
    public function buildAstContinueStatement($image);

    /**
     * Builds a new scope-statement instance.
     *
     * @return \PDepend\Source\AST\ASTScopeStatement
     * @since  0.9.12
     */
    public function buildAstScopeStatement();

    /**
     * Builds a new try-statement instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTTryStatement
     * @since  0.9.12
     */
    public function buildAstTryStatement($image);

    /**
     * Builds a new throw-statement instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTThrowStatement
     * @since  0.9.12
     */
    public function buildAstThrowStatement($image);

    /**
     * Builds a new goto-statement instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTGotoStatement
     * @since  0.9.12
     */
    public function buildAstGotoStatement($image);

    /**
     * Builds a new label-statement instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTLabelStatement
     * @since  0.9.12
     */
    public function buildAstLabelStatement($image);

    /**
     * Builds a new global-statement instance.
     *
     * @return \PDepend\Source\AST\ASTGlobalStatement
     * @since  0.9.12
     */
    public function buildAstGlobalStatement();

    /**
     * Builds a new unset-statement instance.
     *
     * @return \PDepend\Source\AST\ASTUnsetStatement
     * @since  0.9.12
     */
    public function buildAstUnsetStatement();

    /**
     * Builds a new exit-statement instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTEchoStatement
     * @since  0.9.12
     */
    public function buildAstEchoStatement($image);

    /**
     * Builds a new yield-statement instance.
     *
     * @param string $image The source code image for this node.
     *
     * @return \PDepend\Source\AST\ASTYieldStatement
     * @since  $version$
     */
    public function buildAstYieldStatement($image);
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */

namespace PDepend\Source\Builder\BuilderContext;

use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTTrait;
use PDepend\Source\Builder\Builder;
use PDepend\Source\Builder\BuilderContext;

/**
 * This class provides the default implementation of the builder context.
 *
 * This class utilizes the simple <b>static</b> language construct to share the
 * context instance between all using objects.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */
class GlobalBuilderContext implements BuilderContext
{
    /**
     * The currently used ast builder.
     *
     * @var \PDepend\Source\Builder\Builder
     */
    protected static $builder = null;

    /**
     * Constructs a new builder context instance.
     *
     * @param \PDepend\Source\Builder\Builder $builder The currently used ast builder.
     */
    public function __construct(Builder $builder)
    {
        self::$builder = $builder;
    }

    /**
     * This method can be used to register an existing function in the current
     * application context.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     */
    public function registerFunction(ASTFunction $function)
    {
        self::$builder->restoreFunction($function);
    }

    /**
     * This method can be used to register an existing trait in the current
     * class context.
     *
     * @param  \PDepend\Source\AST\ASTTrait $trait
     * @return void
     * @since  1.0.0
     */
    public function registerTrait(ASTTrait $trait)
    {
        self::$builder->restoreTrait($trait);
    }

    /**
     * This method can be used to register an existing class in the current
     * class context.
     *
     * @param  \PDepend\Source\AST\ASTClass $class The class instance.
     * @return void
     */
    public function registerClass(ASTClass $class)
    {
        self::$builder->restoreClass($class);
    }

    /**
     * This method can be used to register an existing interface in the current
     * class context.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function registerInterface(ASTInterface $interface)
    {
        self::$builder->restoreInterface($interface);
    }

    /**
     * Returns the trait instance for the given qualified name.
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\ASTTrait
     * @since  1.0.0
     */
    public function getTrait($qualifiedName)
    {
        return $this->getBuilder()->getTrait($qualifiedName);
    }

    /**
     * Returns the class instance for the given qualified name.
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\ASTClass
     */
    public function getClass($qualifiedName)
    {
        return $this->getBuilder()->getClass($qualifiedName);
    }

    /**
     * Returns a class or an interface instance for the given qualified name.
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\AbstractASTClassOrInterface
     */
    public function getClassOrInterface($qualifiedName)
    {
        return $this->getBuilder()->getClassOrInterface($qualifiedName);
    }

    /**
     * Returns the currently used builder instance.
     *
     * @return \PDepend\Source\Builder\Builder
     */
    protected function getBuilder()
    {
        return self::$builder;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */

namespace PDepend\Source\Builder;

use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTTrait;

/**
 * Base interface for a builder context.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */
interface BuilderContext
{
    /**
     * This method can be used to register an existing function in the current
     * application context.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     */
    public function registerFunction(ASTFunction $function);

    /**
     * This method can be used to register an existing trait in the current
     * class context.
     *
     * @param  \PDepend\Source\AST\ASTTrait $trait
     * @return void
     * @since  1.0.0
     */
    public function registerTrait(ASTTrait $trait);

    /**
     * This method can be used to register an existing class in the current
     * class context.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     */
    public function registerClass(ASTClass $class);

    /**
     * This method can be used to register an existing interface in the current
     * class context.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function registerInterface(ASTInterface $interface);

    /**
     * Returns the trait instance for the given qualified name.
     *
     * @param  string $qualifiedName Full qualified trait name.
     * @return \PDepend\Source\AST\ASTTrait
     * @since  1.0.0
     */
    public function getTrait($qualifiedName);

    /**
     * Returns the class instance for the given qualified name.
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\ASTClass
     */
    public function getClass($qualifiedName);

    /**
     * Returns a class or an interface instance for the given qualified name.
     *
     * @param  string $qualifiedName
     * @return \PDepend\Source\AST\AbstractASTClassOrInterface
     */
    public function getClassOrInterface($qualifiedName);
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\ASTVisitor;

use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTCompilationUnit;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\AST\ASTParameter;
use PDepend\Source\AST\ASTProperty;
use PDepend\Source\AST\ASTTrait;

/**
 * This abstract visitor implementation provides a default traversal algorithm
 * that can be used for custom visitors.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
abstract class AbstractASTVisitor implements ASTVisitor
{
    /**
     * List of all registered listeners.
     *
     * @var \PDepend\Source\ASTVisitor\ASTVisitListener[]
     */
    private $listeners = array();

    /**
     * Returns an iterator with all registered visit listeners.
     *
     * @return Iterator
     */
    public function getVisitListeners()
    {
        return new \ArrayIterator($this->listeners);
    }

    /**
     * Adds a new listener to this node visitor.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitListener $listener
     * @return void
     */
    public function addVisitListener(ASTVisitListener $listener)
    {
        if (in_array($listener, $this->listeners, true) === false) {
            $this->listeners[] = $listener;
        }
    }

    /**
     * Visits a class node.
     *
     * @param  ASTClass $class
     * @return void
     */
    public function visitClass(ASTClass $class)
    {
        $this->fireStartClass($class);

        $class->getCompilationUnit()->accept($this);

        foreach ($class->getProperties() as $property) {
            $property->accept($this);
        }
        foreach ($class->getMethods() as $method) {
            $method->accept($this);
        }

        $this->fireEndClass($class);
    }

    /**
     * Visits a trait node.
     *
     * @param  \PDepend\Source\AST\ASTTrait $trait
     * @return void
     * @since  1.0.0
     */
    public function visitTrait(ASTTrait $trait)
    {
        $this->fireStartTrait($trait);

        $trait->getCompilationUnit()->accept($this);

        foreach ($trait->getMethods() as $method) {
            $method->accept($this);
        }

        $this->fireEndTrait($trait);
    }

    /**
     * Visits a file node.
     *
     * @param  \PDepend\Source\AST\ASTCompilationUnit $compilationUnit
     * @return void
     */
    public function visitCompilationUnit(ASTCompilationUnit $compilationUnit)
    {
        $this->fireStartFile($compilationUnit);
        $this->fireEndFile($compilationUnit);
    }

    /**
     * Visits a function node.
     *
     * @param  ASTFunction $function
     * @return void
     */
    public function visitFunction(ASTFunction $function)
    {
        $this->fireStartFunction($function);

        $function->getCompilationUnit()->accept($this);

        foreach ($function->getParameters() as $parameter) {
            $parameter->accept($this);
        }

        $this->fireEndFunction($function);
    }

    /**
     * Visits a code interface object.
     *
     * @param  ASTInterface $interface
     * @return void
     */
    public function visitInterface(ASTInterface $interface)
    {
        $this->fireStartInterface($interface);

        $interface->getCompilationUnit()->accept($this);

        foreach ($interface->getMethods() as $method) {
            $method->accept($this);
        }

        $this->fireEndInterface($interface);
    }

    /**
     * Visits a method node.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function visitMethod(ASTMethod $method)
    {
        $this->fireStartMethod($method);

        foreach ($method->getParameters() as $parameter) {
            $parameter->accept($this);
        }

        $this->fireEndMethod($method);
    }

    /**
     * Visits a namespace node.
     *
     * @param  ASTNamespace $namespace
     * @return void
     */
    public function visitNamespace(ASTNamespace $namespace)
    {
        $this->fireStartNamespace($namespace);

        foreach ($namespace->getClasses() as $class) {
            $class->accept($this);
        }
        foreach ($namespace->getInterfaces() as $interface) {
            $interface->accept($this);
        }
        foreach ($namespace->getTraits() as $trait) {
            $trait->accept($this);
        }
        foreach ($namespace->getFunctions() as $function) {
            $function->accept($this);
        }

        $this->fireEndNamespace($namespace);
    }

    /**
     * Visits a parameter node.
     *
     * @param  \PDepend\Source\AST\ASTParameter $parameter
     * @return void
     */
    public function visitParameter(ASTParameter $parameter)
    {
        $this->fireStartParameter($parameter);
        $this->fireEndParameter($parameter);
    }

    /**
     * Visits a property node.
     *
     * @param  \PDepend\Source\AST\ASTProperty $property
     * @return void
     */
    public function visitProperty(ASTProperty $property)
    {
        $this->fireStartProperty($property);
        $this->fireEndProperty($property);
    }


    /**
     * Magic call method used to provide simplified visitor implementations.
     * With this method we can call <b>visit${NodeClassName}</b> on each node.
     *
     * <code>
     * $visitor->visitAllocationExpression($alloc);
     *
     * $visitor->visitStatement($stmt);
     * </code>
     *
     * All visit methods takes two argument. The first argument is the current
     * context ast node and the second argument is a data array or object that
     * is used to collect data.
     *
     * The return value of this method is the second input argument, modified
     * by the concrete visit method.
     *
     * @param string $method Name of the called method.
     * @param array  $args   Array with method argument.
     *
     * @return mixed
     * @since  0.9.12
     */
    public function __call($method, $args)
    {
        if (!isset($args[1])) {
            throw new \RuntimeException("No node to visit provided for $method.");
        }

        $value = $args[1];
        foreach ($args[0]->getChildren() as $child) {
            $value = $child->accept($this, $value);
        }
        return $value;
    }

    /**
     * Sends a start class event.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     */
    protected function fireStartClass(ASTClass $class)
    {
        foreach ($this->listeners as $listener) {
            $listener->startVisitClass($class);
        }
    }

    /**
     * Sends an end class event.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     */
    protected function fireEndClass(ASTClass $class)
    {
        foreach ($this->listeners as $listener) {
            $listener->endVisitClass($class);
        }
    }

    /**
     * Sends a start trait event.
     *
     * @param  \PDepend\Source\AST\ASTTrait $trait
     * @return void
     */
    protected function fireStartTrait(ASTTrait $trait)
    {
        foreach ($this->listeners as $listener) {
            $listener->startVisitTrait($trait);
        }
    }

    /**
     * Sends an end trait event.
     *
     * @param  \PDepend\Source\AST\ASTTrait $trait
     * @return void
     */
    protected function fireEndTrait(ASTTrait $trait)
    {
        foreach ($this->listeners as $listener) {
            $listener->endVisitTrait($trait);
        }
    }

    /**
     * Sends a start file event.
     *
     * @param  \PDepend\Source\AST\ASTCompilationUnit $compilationUnit
     * @return void
     */
    protected function fireStartFile(ASTCompilationUnit $compilationUnit)
    {
        foreach ($this->listeners as $listener) {
            $listener->startVisitFile($compilationUnit);
        }
    }

    /**
     * Sends an end file event.
     *
     * @param  \PDepend\Source\AST\ASTCompilationUnit $compilationUnit
     * @return void
     */
    protected function fireEndFile(ASTCompilationUnit $compilationUnit)
    {
        foreach ($this->listeners as $listener) {
            $listener->endVisitFile($compilationUnit);
        }
    }

    /**
     * Sends a start function event.
     *
     * @param  ASTFunction $function
     * @return void
     */
    protected function fireStartFunction(ASTFunction $function)
    {
        foreach ($this->listeners as $listener) {
            $listener->startVisitFunction($function);
        }
    }

    /**
     * Sends an end function event.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     */
    protected function fireEndFunction(ASTFunction $function)
    {
        foreach ($this->listeners as $listener) {
            $listener->endVisitFunction($function);
        }
    }

    /**
     * Sends a start interface event.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    protected function fireStartInterface(ASTInterface $interface)
    {
        foreach ($this->listeners as $listener) {
            $listener->startVisitInterface($interface);
        }
    }

    /**
     * Sends an end interface event.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    protected function fireEndInterface(ASTInterface $interface)
    {
        foreach ($this->listeners as $listener) {
            $listener->endVisitInterface($interface);
        }
    }

    /**
     * Sends a start method event.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    protected function fireStartMethod(ASTMethod $method)
    {
        foreach ($this->listeners as $listener) {
            $listener->startVisitMethod($method);
        }
    }

    /**
     * Sends an end method event.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    protected function fireEndMethod(ASTMethod $method)
    {
        foreach ($this->listeners as $listener) {
            $listener->endVisitMethod($method);
        }
    }

    /**
     * Sends a start namespace event.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespace
     * @return void
     */
    protected function fireStartNamespace(ASTNamespace $namespace)
    {
        foreach ($this->listeners as $listener) {
            $listener->startVisitNamespace($namespace);
        }
    }

    /**
     * Sends an end namespace event.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespace
     * @return void
     */
    protected function fireEndNamespace(ASTNamespace $namespace)
    {
        foreach ($this->listeners as $listener) {
            $listener->endVisitNamespace($namespace);
        }
    }

    /**
     * Sends a start parameter event.
     *
     * @param  \PDepend\Source\AST\ASTParameter $parameter
     * @return void
     */
    protected function fireStartParameter(ASTParameter $parameter)
    {
        foreach ($this->listeners as $listener) {
            $listener->startVisitParameter($parameter);
        }
    }

    /**
     * Sends a end parameter event.
     *
     * @param  \PDepend\Source\AST\ASTParameter $parameter
     * @return void
     */
    protected function fireEndParameter(ASTParameter $parameter)
    {
        foreach ($this->listeners as $listener) {
            $listener->endVisitParameter($parameter);
        }
    }

    /**
     * Sends a start property event.
     *
     * @param  \PDepend\Source\AST\ASTProperty $property
     * @return void
     */
    protected function fireStartProperty(ASTProperty $property)
    {
        foreach ($this->listeners as $listener) {
            $listener->startVisitProperty($property);
        }
    }

    /**
     * Sends an end property event.
     *
     * @param  \PDepend\Source\AST\ASTProperty $property
     * @return void
     */
    protected function fireEndProperty(ASTProperty $property)
    {
        foreach ($this->listeners as $listener) {
            $listener->endVisitProperty($property);
        }
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  */

namespace PDepend\Source\ASTVisitor;

use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTCompilationUnit;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\AST\ASTParameter;
use PDepend\Source\AST\ASTProperty;
use PDepend\Source\AST\ASTTrait;

/**
 * Base interface for visitors that work on the generated node tree.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface ASTVisitor
{
    /**
     * Adds a new listener to this node visitor.
     * @param \PDepend\Source\ASTVisitor\ASTVisitListener $listener
     * @return void
     */
    public function addVisitListener(ASTVisitListener $listener);

    /**
     * Visits a class node.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     */
    public function visitClass(ASTClass $class);

    /**
     * Visits a trait node.
     *
     * @param  \PDepend\Source\AST\ASTTrait $trait
     * @return void
     * @since  1.0.0
     */
    public function visitTrait(ASTTrait $trait);

    /**
     * Visits a file node.
     *
     * @param  \PDepend\Source\AST\ASTCompilationUnit $compilationUnit
     * @return void
     */
    public function visitCompilationUnit(ASTCompilationUnit $compilationUnit);

    /**
     * Visits a function node.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     */
    public function visitFunction(ASTFunction $function);

    /**
     * Visits a code interface object.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function visitInterface(ASTInterface $interface);

    /**
     * Visits a method node.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function visitMethod(ASTMethod $method);

    /**
     * Visits a namespace node.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespace
     * @return void
     */
    public function visitNamespace(ASTNamespace $namespace);

    /**
     * Visits a parameter node.
     *
     * @param  \PDepend\Source\AST\ASTParameter $parameter
     * @return void
     */
    public function visitParameter(ASTParameter $parameter);

    /**
     * Visits a property node.
     *
     * @param  \PDepend\Source\AST\ASTProperty $property
     * @return void
     */
    public function visitProperty(ASTProperty $property);

    /**
     * Magic call method used to provide simplified visitor implementations.
     * With this method we can call <b>visit${NodeClassName}</b> on each node.
     *
     * <code>
     * $visitor->visitAllocationExpression($alloc);
     *
     * $visitor->visitStatement($stmt);
     * </code>
     *
     * All visit methods takes two argument. The first argument is the current
     * context ast node and the second argument is a data array or object that
     * is used to collect data.
     *
     * The return value of this method is the second input argument, modified
     * by the concrete visit method.
     *
     * @param string $method Name of the called method.
     * @param array  $args   Array with method argument.
     *
     * @return mixed
     * @since  0.9.12
     */
    public function __call($method, $args);
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\ASTVisitor;

use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTCompilationUnit;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\AST\ASTParameter;
use PDepend\Source\AST\ASTProperty;
use PDepend\Source\AST\ASTTrait;

/**
 * This abstract class provides a default implementation of the node visitor
 * listener.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
abstract class AbstractASTVisitListener implements ASTVisitListener
{
    /**
     * Is called when the visitor starts a new class instance.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     */
    public function startVisitClass(ASTClass $class)
    {
        $this->startVisitNode($class);
    }

    /**
     * Is called when the visitor ends with a class instance.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     */
    public function endVisitClass(ASTClass $class)
    {
        $this->endVisitNode($class);
    }

    /**
     * Is called when the visitor starts a new trait instance.
     *
     * @param  \PDepend\Source\AST\ASTTrait $trait
     * @return void
     * @since  1.0.0
     */
    public function startVisitTrait(ASTTrait $trait)
    {
        $this->startVisitNode($trait);
    }

    /**
     * Is called when the visitor ends with a trait instance.
     *
     * @param  \PDepend\Source\AST\ASTTrait $trait
     * @return void
     * @since  1.0.0
     */
    public function endVisitTrait(ASTTrait $trait)
    {
        $this->endVisitNode($trait);
    }

    /**
     * Is called when the visitor starts a new file instance.
     *
     * @param  \PDepend\Source\AST\ASTCompilationUnit $compilationUnit
     * @return void
     */
    public function startVisitFile(ASTCompilationUnit $compilationUnit)
    {
        $this->startVisitNode($compilationUnit);
    }

    /**
     * Is called when the visitor ends with a file instance.
     *
     * @param  \PDepend\Source\AST\ASTCompilationUnit $compilationUnit
     * @return void
     */
    public function endVisitFile(ASTCompilationUnit $compilationUnit)
    {
        $this->endVisitNode($compilationUnit);
    }

    /**
     * Is called when the visitor starts a new function instance.
     *
     * @param  ASTFunction $function
     * @return void
     */
    public function startVisitFunction(ASTFunction $function)
    {
        $this->startVisitNode($function);
    }

    /**
     * Is called when the visitor ends with a function instance.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     */
    public function endVisitFunction(ASTFunction $function)
    {
        $this->endVisitNode($function);
    }

    /**
     * Is called when the visitor starts a new interface instance.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function startVisitInterface(ASTInterface $interface)
    {
        $this->startVisitNode($interface);
    }

    /**
     * Is called when the visitor ends with an interface instance.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function endVisitInterface(ASTInterface $interface)
    {
        $this->endVisitNode($interface);
    }

    /**
     * Is called when the visitor starts a new method instance.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function startVisitMethod(ASTMethod $method)
    {
        $this->startVisitNode($method);
    }

    /**
     * Is called when the visitor ends with a method instance.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function endVisitMethod(ASTMethod $method)
    {
        $this->endVisitNode($method);
    }

    /**
     * Is called when the visitor starts a new namespace instance.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespace
     * @return void
     */
    public function startVisitNamespace(ASTNamespace $namespace)
    {
        $this->startVisitNode($namespace);
    }

    /**
     * Is called when the visitor ends with a namespace instance.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespace
     * @return void
     */
    public function endVisitNamespace(ASTNamespace $namespace)
    {
        $this->endVisitNode($namespace);
    }

    /**
     * Is called when the visitor starts a new parameter instance.
     *
     * @param  \PDepend\Source\AST\ASTParameter $parameter
     * @return void
     */
    public function startVisitParameter(ASTParameter $parameter)
    {
        $this->startVisitNode($parameter);
    }

    /**
     * Is called when the visitor ends with a parameter instance.
     *
     * @param  \PDepend\Source\AST\ASTParameter $parameter
     * @return void
     */
    public function endVisitParameter(ASTParameter $parameter)
    {
        $this->endVisitNode($parameter);
    }

    /**
     * Is called when the visitor starts a new property instance.
     *
     * @param  \PDepend\Source\AST\ASTProperty $property
     * @return void
     */
    public function startVisitProperty(ASTProperty $property)
    {
        $this->startVisitNode($property);
    }

    /**
     * Is called when the visitor ends with a property instance.
     *
     * @param  \PDepend\Source\AST\ASTProperty $property
     * @return void
     */
    public function endVisitProperty(ASTProperty $property)
    {
        $this->endVisitNode($property);
    }

    /**
     * Generic notification method that is called for every node start.
     *
     * @param  \PDepend\Source\AST\AbstractASTArtifact $node
     * @return void
     */
    protected function startVisitNode(AbstractASTArtifact $node)
    {

    }

    /**
     * Generic notification method that is called when the node processing ends.
     *
     * @param  \PDepend\Source\AST\AbstractASTArtifact $node
     * @return void
     */
    protected function endVisitNode(AbstractASTArtifact $node)
    {

    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\ASTVisitor;

use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTCompilationUnit;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\AST\ASTParameter;
use PDepend\Source\AST\ASTProperty;
use PDepend\Source\AST\ASTTrait;

/**
 * Base interface for a visitor listener.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface ASTVisitListener
{
    /**
     * Is called when the visitor starts a new class instance.
     *
     * @param  \PDepend\Source\AST\ASTClass $class The context class instance.
     * @return void
     */
    public function startVisitClass(ASTClass $class);

    /**
     * Is called when the visitor ends with a class instance.
     *
     * @param  \PDepend\Source\AST\ASTClass $class The context class instance.
     * @return void
     */
    public function endVisitClass(ASTClass $class);

    /**
     * Is called when the visitor starts a new trait instance.
     *
     * @param  \PDepend\Source\AST\ASTTrait $trait
     * @return void
     * @since  1.0.0
     */
    public function startVisitTrait(ASTTrait $trait);

    /**
     * Is called when the visitor ends with a trait instance.
     *
     * @param  \PDepend\Source\AST\ASTTrait $trait
     * @return void
     * @since  1.0.0
     */
    public function endVisitTrait(ASTTrait $trait);

    /**
     * Is called when the visitor starts a new file instance.
     *
     * @param  \PDepend\Source\AST\ASTCompilationUnit $compilationUnit The context file instance.
     * @return void
     */
    public function startVisitFile(ASTCompilationUnit $compilationUnit);

    /**
     * Is called when the visitor ends with a file instance.
     *
     * @param  \PDepend\Source\AST\ASTCompilationUnit $compilationUnit The context file instance.
     * @return void
     */
    public function endVisitFile(ASTCompilationUnit $compilationUnit);

    /**
     * Is called when the visitor starts a new function instance.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     */
    public function startVisitFunction(ASTFunction $function);

    /**
     * Is called when the visitor ends with a function instance.
     *
     * @param  ASTFunction $function
     * @return void
     */
    public function endVisitFunction(ASTFunction $function);

    /**
     * Is called when the visitor starts a new interface instance.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function startVisitInterface(ASTInterface $interface);

    /**
     * Is called when the visitor ends with an interface instance.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function endVisitInterface(ASTInterface $interface);

    /**
     * Is called when the visitor starts a new method instance.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function startVisitMethod(ASTMethod $method);

    /**
     * Is called when the visitor ends with a method instance.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function endVisitMethod(ASTMethod $method);

    /**
     * Is called when the visitor starts a new namespace instance.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespace
     * @return void
     */
    public function startVisitNamespace(ASTNamespace $namespace);

    /**
     * Is called when the visitor ends with a namespace instance.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespace
     * @return void
     */
    public function endVisitNamespace(ASTNamespace $namespace);

    /**
     * Is called when the visitor starts a new parameter instance.
     *
     * @param  \PDepend\Source\AST\ASTParameter $parameter
     * @return void
     */
    public function startVisitParameter(ASTParameter $parameter);

    /**
     * Is called when the visitor ends with a parameter instance.
     *
     * @param  \PDepend\Source\AST\ASTParameter $parameter
     * @return void
     */
    public function endVisitParameter(ASTParameter $parameter);

    /**
     * Is called when the visitor starts a new property instance.
     *
     * @param  \PDepend\Source\AST\ASTProperty $property
     * @return void
     */
    public function startVisitProperty(ASTProperty $property);

    /**
     * Is called when the visitor ends with a property instance.
     *
     * @param  \PDepend\Source\AST\ASTProperty $property
     * @return void
     */
    public function endVisitProperty(ASTProperty $property);
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This node class represents an eval-expression.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTEvalExpression extends \PDepend\Source\AST\ASTExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitEvalExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

/**
 * This is an abstract base class for invocation nodes.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
abstract class ASTInvocation extends ASTExpression
{
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */

namespace PDepend\Source\AST;

use PDepend\Source\Builder\BuilderContext;
use PDepend\Util\Cache\CacheDriver;

/**
 * Represents any valid complex php type.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */
abstract class AbstractASTType extends AbstractASTArtifact
{
    /**
     * The internal used cache instance.
     *
     * @var \PDepend\Util\Cache\CacheDriver
     */
    protected $cache = null;

    /**
     * The currently used builder context.
     *
     * @var \PDepend\Source\Builder\BuilderContext
     */
    protected $context = null;

    /**
     * The parent namespace for this class.
     *
     * @var \PDepend\Source\AST\ASTNamespace
     */
    private $namespace = null;

    /**
     * An <b>array</b> with all constants defined in this class or interface.
     *
     * @var array(string=>mixed)
     */
    protected $constants = null;

    /**
     * This property will indicate that the class or interface is user defined.
     * The parser marks all classes and interfaces as user defined that have a
     * source file and were part of parsing process.
     *
     * @var boolean
     */
    protected $userDefined = false;

    /**
     * List of all parsed child nodes.
     *
     * @var \PDepend\Source\AST\ASTNode[]
     */
    protected $nodes = array();

    /**
     * Name of the parent namespace for this class or interface instance. Or
     * <b>NULL</b> when no namespace was specified.
     *
     * @var string
     */
    protected $namespaceName = null;

    /**
     * The modifiers for this class instance.
     *
     * @var integer
     */
    protected $modifiers = 0;

    /**
     * Temporary property that only holds methods during the parsing process.
     *
     * @var   \PDepend\Source\AST\ASTMethod[]
     * @since 1.0.2
     */
    protected $methods = array();


    /**
     * Setter method for the currently used token cache, where this class or
     * interface instance can store the associated tokens.
     *
     * @param  \PDepend\Util\Cache\CacheDriver $cache
     * @return \PDepend\Source\AST\AbstractASTType
     */
    public function setCache(CacheDriver $cache)
    {
        $this->cache = $cache;
        return $this;
    }

    /**
     * Sets the currently active builder context.
     *
     * @param  \PDepend\Source\Builder\BuilderContext $context
     * @return \PDepend\Source\AST\AbstractASTType
     */
    public function setContext(BuilderContext $context)
    {
        $this->context = $context;
        return $this;
    }

    /**
     * Adds a parsed child node to this node.
     *
     * @param  \PDepend\Source\AST\ASTNode $node
     * @return void
     * @access private
     */
    public function addChild(ASTNode $node)
    {
        $this->nodes[] = $node;
    }

    /**
     * Returns the child at the given index.
     *
     * @param  integer $index
     * @return \PDepend\Source\AST\ASTNode
     * @throws \OutOfBoundsException
     */
    public function getChild($index)
    {
        if (isset($this->nodes[$index])) {
            return $this->nodes[$index];
        }
        throw new \OutOfBoundsException(
            sprintf(
                'No node found at index %d in node of type: %s',
                $index,
                get_class($this)
            )
        );
    }

    /**
     * Returns all child nodes of this class.
     *
     * @return \PDepend\Source\AST\ASTNode[]
     */
    public function getChildren()
    {
        return $this->nodes;
    }

    /**
     * This method will search recursive for the first child node that is an
     * instance of the given <b>$targetType</b>. The returned value will be
     * <b>null</b> if no child exists for that.
     *
     * @param string $targetType Searched class or interface type.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @access private
     * @todo   Refactor $_methods property to getAllMethods() when it exists.
     */
    public function getFirstChildOfType($targetType)
    {
        foreach ($this->nodes as $node) {
            if ($node instanceof $targetType) {
                return $node;
            }
            if (($child = $node->getFirstChildOfType($targetType)) !== null) {
                return $child;
            }
        }
        $methods = $this->getMethods();
        foreach ($methods as $method) {
            if (($child = $method->getFirstChildOfType($targetType)) !== null) {
                return $child;
            }
        }

        return null;
    }

    /**
     * Will find all children for the given type.
     *
     * @param string $targetType The target class or interface type.
     * @param array  &$results   The found children.
     *
     * @return \PDepend\Source\AST\ASTNode[]
     * @access private
     * @todo   Refactor $_methods property to getAllMethods() when it exists.
     */
    public function findChildrenOfType($targetType, array &$results = array())
    {
        foreach ($this->nodes as $node) {
            if ($node instanceof $targetType) {
                $results[] = $node;
            }
            $node->findChildrenOfType($targetType, $results);
        }

        foreach ($this->getMethods() as $method) {
            $method->findChildrenOfType($targetType, $results);
        }

        return $results;
    }

    /**
     * This method will return <b>true</b> when this type has a declaration in
     * the analyzed source files.
     *
     * @return boolean
     */
    public function isUserDefined()
    {
        return $this->userDefined;
    }

    /**
     * This method can be used to mark a type as user defined. User defined
     * means that the type has a valid declaration in the analyzed source files.
     *
     * @return void
     */
    public function setUserDefined()
    {
        $this->userDefined = true;
    }

    /**
     * Returns all {@link \PDepend\Source\AST\ASTMethod} objects in this type.
     *
     * @return \PDepend\Source\AST\ASTMethod[]
     */
    public function getMethods()
    {
        if (is_array($this->methods)) {
            return new ASTArtifactList($this->methods);
        }

        $methods = (array) $this->cache
            ->type('methods')
            ->restore($this->getId());

        foreach ($methods as $method) {
            $method->compilationUnit = $this->compilationUnit;
            $method->setParent($this);
        }

        return new ASTArtifactList($methods);
    }

    /**
     * Adds the given method to this type.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return \PDepend\Source\AST\ASTMethod
     */
    public function addMethod(ASTMethod $method)
    {
        $method->setParent($this);

        $this->methods[] = $method;

        return $method;
    }

    /**
     * Returns an array with {@link \PDepend\Source\AST\ASTMethod} objects
     * that are imported through traits.
     *
     * @return \PDepend\Source\AST\ASTMethod[]
     * @since  1.0.0
     */
    protected function getTraitMethods()
    {
        $methods = array();

        $uses = $this->findChildrenOfType(
            'PDepend\\Source\\AST\\ASTTraitUseStatement'
        );

        foreach ($uses as $use) {
            foreach ($use->getAllMethods() as $method) {
                foreach ($uses as $use2) {
                    if ($use2->hasExcludeFor($method)) {
                        continue 2;
                    }
                }

                $name = strtolower($method->getName());

                if (false === isset($methods[$name])) {
                    $methods[$name] = $method;
                    continue;
                }

                if ($methods[$name]->isAbstract()) {
                    $methods[$name] = $method;
                    continue;
                }

                if ($method->isAbstract()) {
                    continue;
                }

                throw new ASTTraitMethodCollisionException($method, $this);
            }
        }
        return $methods;
    }

    /**
     * Returns an <b>array</b> with all tokens within this type.
     *
     * @return \PDepend\Source\Tokenizer\Token[]
     */
    public function getTokens()
    {
        return (array) $this->cache
            ->type('tokens')
            ->restore($this->id);
    }

    /**
     * Sets the tokens for this type.
     *
     * @param \PDepend\Source\Tokenizer\Token[] $tokens
     * @return void
     */
    public function setTokens(array $tokens)
    {
        $this->startLine = reset($tokens)->startLine;
        $this->endLine   = end($tokens)->endLine;

        $this->cache
            ->type('tokens')
            ->store($this->id, $tokens);
    }

    /**
     * @return string
     */
    public function getNamespacedName()
    {
        if (null === $this->namespace || $this->namespace->isPackageAnnotation()) {
            return $this->name;
        }
        return sprintf('%s\\%s', $this->namespaceName, $this->name);
    }

    /**
     * Returns the name of the parent namespace.
     *
     * @return string
     */
    public function getNamespaceName()
    {
        return $this->namespaceName;
    }

    /**
     * Returns the parent namespace for this class.
     *
     * @return \PDepend\Source\AST\ASTNamespace
     */
    public function getNamespace()
    {
        return $this->namespace;
    }

    /**
     * Sets the parent namespace for this type.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespace
     * @return void
     */
    public function setNamespace(ASTNamespace $namespace)
    {
        $this->namespace = $namespace;
        $this->namespaceName = $namespace->getName();
    }

    /**
     * Resets the associated namespace reference.
     *
     * @return void
     */
    public function unsetNamespace()
    {
        $this->namespace = null;
        $this->namespaceName = null;
    }

    /**
     * This method will return <b>true</b> when this class or interface instance
     * was restored from the cache and not currently parsed. Otherwise this
     * method will return <b>false</b>.
     *
     * @return boolean
     */
    public function isCached()
    {
        return $this->compilationUnit->isCached();
    }

    /**
     * Returns a list of all methods provided by this type or one of its parents.
     *
     * @return \PDepend\Source\AST\ASTMethod[]
     */
    abstract public function getAllMethods();

    /**
     * Checks that this user type is a subtype of the given <b>$type</b>
     * instance.
     *
     * @param  \PDepend\Source\AST\AbstractASTType $type
     * @return boolean
     * @since  1.0.6
     */
    abstract public function isSubtypeOf(AbstractASTType $type);

    /**
     * The magic sleep method is called by the PHP runtime environment before an
     * instance of this class gets serialized. It returns an array with the
     * names of all those properties that should be cached for this class or
     * interface instance.
     *
     * @return array
     */
    public function __sleep()
    {
        if (is_array($this->methods)) {
            $this->cache
                ->type('methods')
                ->store($this->id, $this->methods);

            $this->methods = null;
        }

        return array(
            'cache',
            'context',
            'comment',
            'endLine',
            'modifiers',
            'name',
            'nodes',
            'namespaceName',
            'startLine',
            'userDefined',
            'id'
        );
    }

    /**
     * The magic wakeup method is called by the PHP runtime environment when a
     * serialized instance of this class gets unserialized and all properties
     * are restored. This implementation of the <b>__wakeup()</b> method sets
     * a flag that this object was restored from the cache and it restores the
     * dependency between this class or interface and it's child methods.
     *
     * @return void
     */
    public function __wakeup()
    {
        $this->methods = null;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This is a trait only version of the type reference .
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */
class ASTTraitReference extends ASTClassOrInterfaceReference
{
    /**
     * Returns the concrete type instance associated with with this placeholder.
     *
     * @return \PDepend\Source\AST\AbstractASTType
     */
    public function getType()
    {
        if ($this->typeInstance === null) {
            $this->typeInstance = $this->context->getTrait($this->getImage());
        }
        return $this->typeInstance;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param  mixed                                 $data
     * @return mixed
     * @since  0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitTraitReference($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

/**
 * This class represents an array type node.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTTypeArray extends ASTType
{
    /**
     * The visual image for this node type.
     */
    const IMAGE = 'array';

    /**
     * @return string
     */
    public function getImage()
    {
        return self::IMAGE;
    }

    /**
     * This method will return <b>true</b> when the underlying type is an array.
     * For this concrete type implementation the returned value will be always
     * <b>true</b>.
     *
     * @return boolean
     */
    public function isArray()
    {
        return true;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitTypeArray($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This node class represents a strait use statement.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */
class ASTTraitUseStatement extends ASTStatement
{
    /**
     * @var \PDepend\Source\AST\ASTMethod[]
     */
    private $allMethods;

    /**
     * Returns an array with all aliased or directly imported methods.
     *
     * @return \PDepend\Source\AST\ASTMethod[]
     */
    public function getAllMethods()
    {
        if (false === is_array($this->allMethods)) {
            $this->allMethods = array();
            foreach ($this->nodes as $node) {
                if ($node instanceof ASTTraitReference) {
                    $this->collectMethods($node);
                }
            }
        }
        return $this->allMethods;
    }

    /**
     * This method tests if the given {@link \PDepend\Source\AST\ASTMethod} is excluded
     * by precedence statement in this use statement. It will return <b>true</b>
     * if the given <b>$method</b> is excluded, otherwise the return value of
     * this method will be <b>false</b>.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return boolean
     */
    public function hasExcludeFor(ASTMethod $method)
    {
        $methodName   = strtolower($method->getName());
        $methodParent = $method->getParent();

        $precedences = $this->findChildrenOfType('PDepend\\Source\\AST\\ASTTraitAdaptationPrecedence');

        foreach ($precedences as $precedence) {
            if (strtolower($precedence->getImage()) !== $methodName) {
                continue;
            }
            $children = $precedence->getChildren();
            for ($i = 1, $count = count($children); $i < $count; ++$i) {
                if ($methodParent === $children[$i]->getType()) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Collects all directly defined methods or method aliases for the given
     * {@link \PDepend\Source\AST\ASTTraitReference}
     *
     * @param \PDepend\Source\AST\ASTTraitReference $reference Context trait reference.
     *
     * @return void
     */
    private function collectMethods(ASTTraitReference $reference)
    {
        foreach ($reference->getType()->getAllMethods() as $method) {
            foreach ($this->getAliasesFor($method) as $alias) {
                $this->allMethods[] = $alias;
            }
        }
    }

    /**
     * Returns an <b>array</b> with all aliases for the given method. If no
     * alias exists for the given method, this method will simply return the
     * an <b>array</b> with the original method.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return \PDepend\Source\AST\ASTMethod[]
     */
    private function getAliasesFor(ASTMethod $method)
    {
        $name = strtolower($method->getName());

        $newNames = array();
        foreach ($this->getAliases() as $alias) {
            $name2 = strtolower($alias->getImage());
            if ($name2 !== $name) {
                continue;
            }

            $modifier = $method->getModifiers();
            if (-1 < $alias->getNewModifier()) {
                $modifier &= ~(
                    State::IS_PUBLIC |
                    State::IS_PROTECTED |
                    State::IS_PRIVATE
                );
                $modifier |= $alias->getNewModifier();
            }

            $newName = $method->getName();
            if ($alias->getNewName()) {
                $newName = $alias->getNewName();
            }

            if (0 === count($alias->getChildren())) {
                $newMethod = clone $method;
                $newMethod->setName($newName);
                $newMethod->setModifiers($modifier);

                $newNames[] = $newMethod;
                continue;
            }

            if ($alias->getChild(0)->getType() !== $method->getParent()) {
                continue;
            }

            $newMethod = clone $method;
            $newMethod->setName($newName);
            $newMethod->setModifiers($modifier);

            $newNames[] = $newMethod;
        }

        if (count($newNames) > 0) {
            return $newNames;
        }
        return array($method);
    }

    /**
     * Returns an <b>array</b> with all alias statements declared in this use
     * statement.
     *
     * @return \PDepend\Source\AST\ASTTraitAdaptationAlias[]
     */
    private function getAliases()
    {
        return $this->findChildrenOfType('PDepend\\Source\\AST\\ASTTraitAdaptationAlias');
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param  mixed                                 $data
     * @return mixed
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitTraitUseStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * Represents a php namespace node.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTNamespace extends AbstractASTArtifact
{
    /**
     * The unique identifier for this function.
     *
     * @var string
     */
    protected $id = null;

    /**
     * List of all {@link \PDepend\Source\AST\AbstractASTClassOrInterface}
     * objects for this namespace.
     *
     * @var \PDepend\Source\AST\AbstractASTClassOrInterface[]
     */
    protected $types = array();

    /**
     * List of all standalone {@link \PDepend\Source\AST\ASTFunction} objects
     * in this namespace.
     *
     * @var \PDepend\Source\AST\ASTFunction[]
     */
    protected $functions = array();

    /**
     * Does this namespace contain user defined functions, classes or interfaces?
     *
     * @var boolean
     */
    private $userDefined = null;

    /**
     * @var boolean
     */
    protected $packageAnnotation = false;

    /**
     * Constructs a new namespace for the given <b>$name</b>
     *
     * @param string $name
     */
    public function __construct($name)
    {
        parent::__construct($name);
        $this->id = spl_object_hash($this);
    }

    /**
     * Returns a id for this code node.
     *
     * @return string
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Returns <b>true</b> when at least one artifact <b>function</b> or a
     * <b>class/method</b> is user defined. Otherwise this method will return
     * <b>false</b>.
     *
     * @return boolean
     * @since  0.9.10
     */
    public function isUserDefined()
    {
        if ($this->userDefined === null) {
            $this->userDefined = $this->checkUserDefined();
        }
        return $this->userDefined;
    }

    /**
     * Returns <b>true</b> when at least one artifact <b>function</b> or a
     * <b>class/method</b> is user defined. Otherwise this method will return
     * <b>false</b>.
     *
     * @return boolean
     * @since  0.9.10
     */
    private function checkUserDefined()
    {
        foreach ($this->types as $type) {
            if ($type->isUserDefined()) {
                return true;
            }
        }
        return (count($this->functions) > 0);
    }

    /**
     * Returns an array with all {@link \PDepend\Source\AST\ASTTrait}
     * instances declared in this namespace.
     *
     * @return array
     * @since  1.0.0
     */
    public function getTraits()
    {
        return $this->getTypesOfType('PDepend\\Source\\AST\\ASTTrait');
    }

    /**
     * Returns an iterator with all {@link \PDepend\Source\AST\ASTClass}
     * instances within this namespace.
     *
     * @return \PDepend\Source\AST\ASTClass[]
     */
    public function getClasses()
    {
        return $this->getTypesOfType('PDepend\\Source\\AST\\ASTClass');
    }

    /**
     * Returns an iterator with all {@link \PDepend\Source\AST\ASTInterface}
     * instances within this namespace.
     *
     * @return \PDepend\Source\AST\ASTInterface[]
     */
    public function getInterfaces()
    {
        return $this->getTypesOfType('PDepend\\Source\\AST\\ASTInterface');
    }

    /**
     * Returns an iterator with all types of the given <b>$className</b> in this
     * namespace.
     *
     * @param  string $className The class/type we are looking for.
     * @return \PDepend\Source\AST\ASTArtifactList
     * @since  1.0.0
     */
    private function getTypesOfType($className)
    {
        $types = array();
        foreach ($this->types as $type) {
            if (get_class($type) === $className) {
                $types[] = $type;
            }
        }
        return new ASTArtifactList($types);
    }

    /**
     * Returns all {@link \PDepend\Source\AST\AbstractASTType} objects in
     * this namespace.
     *
     * @return \PDepend\Source\AST\AbstractASTType[]
     */
    public function getTypes()
    {
        return new ASTArtifactList($this->types);
    }

    /**
     * Adds the given type to this namespace and returns the input type instance.
     *
     * @param  \PDepend\Source\AST\AbstractASTType $type
     * @return \PDepend\Source\AST\AbstractASTType
     */
    public function addType(AbstractASTType $type)
    {
        // Skip if this namespace already contains this type
        if (in_array($type, $this->types, true)) {
            return $type;
        }

        if ($type->getNamespace() !== null) {
            $type->getNamespace()->removeType($type);
        }

        // Set this as class namespace
        $type->setNamespace($this);
        // Append class to internal list
        $this->types[$type->getId()] = $type;

        return $type;
    }

    /**
     * Removes the given type instance from this namespace.
     *
     * @param  \PDepend\Source\AST\AbstractASTType $type
     * @return void
     */
    public function removeType(AbstractASTType $type)
    {
        if (($index = array_search($type, $this->types, true)) !== false) {
            // Remove class from internal list
            unset($this->types[$index]);
            // Remove this as parent
            $type->unsetNamespace();
        }
    }

    /**
     * Returns all {@link \PDepend\Source\AST\ASTFunction} objects in this
     * namespace.
     *
     * @return \PDepend\Source\AST\ASTFunction[]
     */
    public function getFunctions()
    {
        return new ASTArtifactList($this->functions);
    }

    /**
     * Adds the given function to this namespace and returns the input instance.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return \PDepend\Source\AST\ASTFunction
     */
    public function addFunction(ASTFunction $function)
    {
        if ($function->getNamespace() !== null) {
            $function->getNamespace()->removeFunction($function);
        }

        $function->setNamespace($this);
        // Append function to internal list
        $this->functions[$function->getId()] = $function;

        return $function;
    }

    /**
     * Removes the given function from this namespace.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     */
    public function removeFunction(ASTFunction $function)
    {
        if (($index = array_search($function, $this->functions, true)) !== false) {
            // Remove function from internal list
            unset($this->functions[$index]);
            // Remove this as parent
            $function->unsetNamespace();
        }
    }

    /**
     * @return boolean
     */
    public function isPackageAnnotation()
    {
        return $this->packageAnnotation;
    }

    /**
     * @param boolean $packageAnnotation
     */
    public function setPackageAnnotation($packageAnnotation)
    {
        $this->packageAnnotation = $packageAnnotation;
    }

    /**
     * ASTVisitor method for node tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @return void
     */
    public function accept(ASTVisitor $visitor)
    {
        $visitor->visitNamespace($this);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This node class represents an exit-expression.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTExitExpression extends \PDepend\Source\AST\ASTExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitExitExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * Represents a php class node.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTClass extends AbstractASTClassOrInterface
{
    /**
     * List of associated properties.
     *
     * @var \PDepend\Source\AST\ASTProperty[]
     */
    private $properties = null;

    /**
     * Returns <b>true</b> if this is an abstract class or an interface.
     *
     * @return boolean
     */
    public function isAbstract()
    {
        return (($this->modifiers & State::IS_EXPLICIT_ABSTRACT) === State::IS_EXPLICIT_ABSTRACT);
    }

    /**
     * This method will return <b>true</b> when this class is declared as final.
     *
     * @return boolean
     */
    public function isFinal()
    {
        return (($this->modifiers & State::IS_FINAL) === State::IS_FINAL);
    }

    /**
     * Will return <b>true</b> if this class was declared anonymous in an
     * allocation expression.
     *
     * @return boolean
     */
    public function isAnonymous()
    {
        return false;
    }

    /**
     * Returns all properties for this class.
     *
     * @return \PDepend\Source\AST\ASTProperty[]
     */
    public function getProperties()
    {
        if ($this->properties === null) {
            $this->properties = array();

            $declarations = $this->findChildrenOfType('PDepend\\Source\\AST\\ASTFieldDeclaration');
            foreach ($declarations as $declaration) {
                $declarators = $declaration->findChildrenOfType('PDepend\\Source\\AST\\ASTVariableDeclarator');

                foreach ($declarators as $declarator) {
                    $property = new ASTProperty($declaration, $declarator);
                    $property->setDeclaringClass($this);
                    $property->setCompilationUnit($this->getCompilationUnit());

                    $this->properties[] = $property;
                }
            }
        }

        return new ASTArtifactList($this->properties);
    }

    /**
     * Checks that this user type is a subtype of the given <b>$type</b> instance.
     *
     * @param  \PDepend\Source\AST\AbstractASTType $type
     * @return boolean
     */
    public function isSubtypeOf(AbstractASTType $type)
    {
        if ($type === $this) {
            return true;
        } elseif ($type instanceof ASTInterface) {
            foreach ($this->getInterfaces() as $interface) {
                if ($interface === $type) {
                    return true;
                }
            }
        } elseif (($parent = $this->getParentClass()) !== null) {
            if ($parent === $type) {
                return true;
            }
            return $parent->isSubtypeOf($type);
        }
        return false;
    }

    /**
     * Returns the declared modifiers for this type.
     *
     * @return integer
     * @since  0.9.4
     */
    public function getModifiers()
    {
        return $this->modifiers;
    }

    /**
     * This method sets a OR combined integer of the declared modifiers for this
     * node.
     *
     * This method will throw an exception when the value of given <b>$modifiers</b>
     * contains an invalid/unexpected modifier
     *
     * @param  integer $modifiers
     * @return void
     * @throws \BadMethodCallException
     * @throws \InvalidArgumentException
     * @since  0.9.4
     */
    public function setModifiers($modifiers)
    {
        if ($this->modifiers !== 0) {
            throw new \BadMethodCallException(
                'Cannot overwrite previously set class modifiers.'
            );
        }

        $expected = ~State::IS_EXPLICIT_ABSTRACT
                  & ~State::IS_IMPLICIT_ABSTRACT
                  & ~State::IS_FINAL;

        if (($expected & $modifiers) !== 0) {
            throw new \InvalidArgumentException('Invalid class modifier given.');
        }

        $this->modifiers = $modifiers;
    }

    /**
     * ASTVisitor method for node tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @return void
     */
    public function accept(ASTVisitor $visitor)
    {
        $visitor->visitClass($this);
    }

    /**
     * The magic wakeup method will be called by PHP's runtime environment when
     * a serialized instance of this class was unserialized. This implementation
     * of the wakeup method will register this object in the the global class
     * context.
     *
     * @return void
     * @since  0.10.0
     */
    public function __wakeup()
    {
        parent::__wakeup();

        $this->context->registerClass($this);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This class represents a compound expression node.
 *
 * <code>
 * //    -----
 * Foo::${BAR}();
 * //    -----
 *
 * //     -----
 * Foo::$${BAR}();
 * //     -----
 *
 * //    -----
 * $foo->{BAR}();
 * //    -----
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTCompoundExpression extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return mixed
     * @since 0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitCompoundExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This class represents arguments as they are supplied to functions or
 * constructors invocations.
 *
 * <code>
 * //      ------------
 * Foo::bar($x, $y, $z);
 * //      ------------
 *
 * //       ------------
 * $foo->bar($x, $y, $z);
 * //       ------------
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTArguments extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return mixed
     * @since 0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitArguments($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This node class represents a finally-statement.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTFinallyStatement extends ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param  mixed                                 $data
     * @return mixed
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitFinallyStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a foreach-statement.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */
class ASTForeachStatement extends ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitForeachStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;
use PDepend\Source\Builder\BuilderContext;

/**
 * Represents a php function node.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTFunction extends AbstractASTCallable
{
    /**
     * The parent namespace for this function.
     *
     * @var   \PDepend\Source\AST\ASTNamespace
     * @since 0.10.0
     */
    private $namespace = null;

    /**
     * The currently used builder context.
     *
     * @var   \PDepend\Source\Builder\BuilderContext
     * @since 0.10.0
     */
    protected $context = null;

    /**
     * The name of the parent namespace for this function. We use this property
     * to restore the parent namespace while we unserialize a cached object tree.
     *
     * @var string
     */
    protected $namespaceName = null;

    /**
     * Sets the currently active builder context.
     *
     * @param  \PDepend\Source\Builder\BuilderContext $context Current builder context.
     * @return \PDepend\Source\AST\ASTFunction
     * @since  0.10.0
     */
    public function setContext(BuilderContext $context)
    {
        $this->context = $context;
        return $this;
    }

    /**
     * Returns the parent namespace for this function.
     *
     * @return \PDepend\Source\AST\ASTNamespace
     */
    public function getNamespace()
    {
        return $this->namespace;
    }

    /**
     * Sets the parent namespace for this function.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespace
     * @return void
     */
    public function setNamespace(ASTNamespace $namespace)
    {
        $this->namespaceName = $namespace->getName();
        $this->namespace = $namespace;
    }

    /**
     * Resets the namespace associated with this function node.
     *
     * @return void
     * @since  0.10.2
     */
    public function unsetNamespace()
    {
        $this->namespaceName = null;
        $this->namespace = null;
    }

    /**
     * Returns the name of the parent namespace/package or <b>NULL</b> when this
     * function does not belong to a namespace.
     *
     * @return string
     * @since  0.10.0
     */
    public function getNamespaceName()
    {
        return $this->namespaceName;
    }

    /**
     * ASTVisitor method for node tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @return void
     */
    public function accept(ASTVisitor $visitor)
    {
        $visitor->visitFunction($this);
    }

    /**
     * The magic sleep method will be called by the PHP engine when this class
     * gets serialized. It returns an array with those properties that should be
     * cached for all function instances.
     *
     * @return array(string)
     * @since  0.10.0
     */
    public function __sleep()
    {
        return array_merge(array('context', 'namespaceName'), parent::__sleep());
    }

    /**
     * The magic wakeup method will be called by PHP's runtime environment when
     * a serialized instance of this class was unserialized. This implementation
     * of the wakeup method will register this object in the the global function
     * context.
     *
     * @return void
     * @since  0.10.0
     */
    public function __wakeup()
    {
        $this->context->registerFunction($this);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This class represents a print node.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.3
 */
class ASTPrintExpression extends ASTExpression
{
    /**
     * ASTPrintExpression constructor.
     */
    public function __construct()
    {
        parent::__construct('print');
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return mixed
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitPrintExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This node class represents any kind of assignment.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTAssignmentExpression extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return mixed
     * @since 0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitAssignmentExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

/**
 * This class represents an instanceof expression node.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTInstanceOfExpression extends ASTExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitInstanceOfExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * An instance of this class represents a function or method parameter within
 * the analyzed source code.
 *
 * <code>
 * <?php
 * class Builder
 * {
 *     public function buildNode($name, $line, \PDepend\Source\AST\ASTCompilationUnit $unit) {
 *     }
 * }
 *
 * function parse(Builder $builder, $file) {
 * }
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTParameter extends AbstractASTArtifact
{
    /**
     * The parent function or method instance.
     *
     * @var \PDepend\Source\AST\AbstractASTCallable
     */
    private $declaringFunction = null;

    /**
     * The parameter position.
     *
     * @var integer
     */
    private $position = 0;

    /**
     * Is this parameter optional or mandatory?
     *
     * @var boolean
     */
    private $optional = false;

    /**
     * The wrapped formal parameter instance.
     *
     * @var \PDepend\Source\AST\ASTFormalParameter
     */
    private $formalParameter = null;

    /**
     * The wrapped variable declarator instance.
     *
     * @var \PDepend\Source\AST\ASTVariableDeclarator
     */
    private $variableDeclarator = null;

    /**
     * Constructs a new parameter instance for the given AST node.
     *
     * @param \PDepend\Source\AST\ASTFormalParameter $formalParameter
     */
    public function __construct(\PDepend\Source\AST\ASTFormalParameter $formalParameter)
    {
        $this->formalParameter    = $formalParameter;
        $this->variableDeclarator = $formalParameter->getFirstChildOfType(
            'PDepend\\Source\\AST\\ASTVariableDeclarator'
        );

        $this->id = spl_object_hash($this);
    }

    /**
     * Returns the item name.
     *
     * @return string
     */
    public function getName()
    {
        return $this->variableDeclarator->getImage();
    }

    /**
     * Returns the line number where the item declaration can be found.
     *
     * @return integer
     */
    public function getStartLine()
    {
        return $this->formalParameter->getStartLine();
    }

    /**
     * Returns the line number where the item declaration ends.
     *
     * @return integer The last source line for this item.
     */
    public function getEndLine()
    {
        return $this->formalParameter->getEndLine();
    }

    /**
     * Returns the parent function or method instance or <b>null</b>
     *
     * @return \PDepend\Source\AST\AbstractASTCallable
     * @since  0.9.5
     */
    public function getDeclaringFunction()
    {
        return $this->declaringFunction;
    }

    /**
     * Sets the parent function or method object.
     *
     * @param  \PDepend\Source\AST\AbstractASTCallable $function
     * @return void
     * @since  0.9.5
     */
    public function setDeclaringFunction(AbstractASTCallable $function)
    {
        $this->declaringFunction = $function;
    }

    /**
     * This method will return the class where the parent method was declared.
     * The returned value will be <b>null</b> if the parent is a function.
     *
     * @return \PDepend\Source\AST\AbstractASTClassOrInterface
     * @since  0.9.5
     */
    public function getDeclaringClass()
    {
        // TODO: Review this for refactoring, maybe create a empty getParent()?
        if ($this->declaringFunction instanceof ASTMethod) {
            return $this->declaringFunction->getParent();
        }
        return null;
    }

    /**
     * Returns the parameter position in the method/function signature.
     *
     * @return integer
     */
    public function getPosition()
    {
        return $this->position;
    }

    /**
     * Sets the parameter position in the method/function signature.
     *
     * @param integer $position The parameter position.
     *
     * @return void
     */
    public function setPosition($position)
    {
        $this->position = $position;
    }

    /**
     * Returns the class type of this parameter. This method will return
     * <b>null</b> for all scalar type, only classes or interfaces are used.
     *
     * @return \PDepend\Source\AST\AbstractASTClassOrInterface
     * @since  0.9.5
     */
    public function getClass()
    {
        $classReference = $this->formalParameter->getFirstChildOfType(
            'PDepend\\Source\\AST\\ASTClassOrInterfaceReference'
        );
        if ($classReference === null) {
            return null;
        }
        return $classReference->getType();
    }

    /**
     * This method will return <b>true</b> when the parameter is passed by
     * reference.
     *
     * @return boolean
     * @since  0.9.5
     */
    public function isPassedByReference()
    {
        return $this->formalParameter->isPassedByReference();
    }

    /**
     * This method will return <b>true</b> when the parameter was declared with
     * the array type hint, otherwise the it will return <b>false</b>.
     *
     * @return boolean
     * @since  0.9.5
     */
    public function isArray()
    {
        $node = $this->formalParameter->getChild(0);
        return ($node instanceof \PDepend\Source\AST\ASTTypeArray);
    }

    /**
     * This method will return <b>true</b> when current parameter is a simple
     * scalar or it is an <b>array</b> or type explicit declared with a default
     * value <b>null</b>.
     *
     * @return boolean
     * @since  0.9.5
     */
    public function allowsNull()
    {
        return (
            (
                $this->isArray() === false
                && $this->getClass() === null
            ) || (
                $this->isDefaultValueAvailable() === true
                && $this->getDefaultValue() === null
            )
        );
    }

    /**
     * This method will return <b>true</b> when this parameter is optional and
     * can be left blank on invocation.
     *
     * @return boolean
     * @since  0.9.5
     */
    public function isOptional()
    {
        return $this->optional;
    }

    /**
     * This method can be used to mark a parameter optional. Note that a
     * parameter is only optional when it has a default value an no following
     * parameter has no default value.
     *
     * @param boolean $optional Boolean flag that marks this parameter a
     *                          optional or not.
     *
     * @return void
     * @since  0.9.5
     */
    public function setOptional($optional)
    {
        $this->optional = (boolean) $optional;
    }

    /**
     * This method will return <b>true</b> when the parameter declaration
     * contains a default value.
     *
     * @return boolean
     * @since  0.9.5
     */
    public function isDefaultValueAvailable()
    {
        $value = $this->variableDeclarator->getValue();
        if ($value === null) {
            return false;
        }
        return $value->isValueAvailable();
    }

    /**
     * This method will return the declared default value for this parameter.
     * Please note that this method will return <b>null</b> when no default
     * value was declared, therefore you should combine calls to this method and
     * {@link \PDepend\Source\AST\ASTParameter::isDefaultValueAvailable()} to
     * detect a NULL-value.
     *
     * @return mixed
     * @since  0.9.5
     */
    public function getDefaultValue()
    {
        $value = $this->variableDeclarator->getValue();
        if ($value === null) {
            return null;
        }
        return $value->getValue();
    }

    /**
     * ASTVisitor method for node tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @return void
     */
    public function accept(ASTVisitor $visitor)
    {
        $visitor->visitParameter($this);
    }

    /**
     * This method returns a string representation of this parameter.
     *
     * @return string
     */
    public function __toString()
    {
        $required  = $this->isOptional() ? 'optional' : 'required';
        $reference = $this->isPassedByReference() ? '&' : '';

        $typeHint = '';
        if ($this->isArray() === true) {
            $typeHint = ' array';
        } elseif ($this->getClass() !== null) {
            $typeHint = ' ' . $this->getClass()->getName();
        }

        $default = '';
        if ($this->isDefaultValueAvailable()) {
            $default = ' = ';

            $value = $this->getDefaultValue();
            if ($value === null) {
                $default  .= 'NULL';
                $typeHint .= ($typeHint !== '' ? ' or NULL' : '');
            } elseif ($value === false) {
                $default .= 'false';
            } elseif ($value === true) {
                $default .= 'true';
            } elseif (is_array($value) === true) {
                $default .= 'Array';
            } elseif (is_string($value) === true) {
                $default .= "'" . $value . "'";
            } else {
                $default .= $value;
            }
        }

        return sprintf(
            'Parameter #%d [ <%s>%s %s%s%s ]',
            $this->position,
            $required,
            $typeHint,
            $reference,
            $this->getName(),
            $default
        );
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * Represents a php method node.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTMethod extends AbstractASTCallable
{
    /**
     * The parent type object.
     *
     * @var \PDepend\Source\AST\AbstractASTType
     */
    protected $parent = null;

    /**
     * Defined modifiers for this property node.
     *
     * @var integer
     */
    protected $modifiers = 0;

    /**
     * This method returns a OR combined integer of the declared modifiers for
     * this method.
     *
     * @return integer
     * @since  1.0.0
     */
    public function getModifiers()
    {
        return $this->modifiers;
    }

    /**
     * This method sets a OR combined integer of the declared modifiers for this
     * node.
     *
     * This method will throw an exception when the value of given <b>$modifiers</b>
     * contains an invalid/unexpected modifier
     *
     * @param  integer $modifiers
     * @return void
     * @throws \InvalidArgumentException If the given modifier contains unexpected values.
     * @since  0.9.4
     */
    public function setModifiers($modifiers)
    {
        $expected = ~State::IS_PUBLIC
                  & ~State::IS_PROTECTED
                  & ~State::IS_PRIVATE
                  & ~State::IS_STATIC
                  & ~State::IS_ABSTRACT
                  & ~State::IS_FINAL;

        if (($expected & $modifiers) !== 0) {
            throw new \InvalidArgumentException('Invalid method modifier given.');
        }

        $this->modifiers = $modifiers;
    }

    /**
     * Returns <b>true</b> if this is an abstract method.
     *
     * @return boolean
     */
    public function isAbstract()
    {
        return (($this->modifiers & State::IS_ABSTRACT) === State::IS_ABSTRACT);
    }

    /**
     * Returns <b>true</b> if this node is marked as public, otherwise the
     * returned value will be <b>false</b>.
     *
     * @return boolean
     */
    public function isPublic()
    {
        return (($this->modifiers & State::IS_PUBLIC) === State::IS_PUBLIC);
    }

    /**
     * Returns <b>true</b> if this node is marked as protected, otherwise the
     * returned value will be <b>false</b>.
     *
     * @return boolean
     */
    public function isProtected()
    {
        return (($this->modifiers & State::IS_PROTECTED) === State::IS_PROTECTED);
    }

    /**
     * Returns <b>true</b> if this node is marked as private, otherwise the
     * returned value will be <b>false</b>.
     *
     * @return boolean
     */
    public function isPrivate()
    {
        return (($this->modifiers & State::IS_PRIVATE) === State::IS_PRIVATE);
    }

    /**
     * Returns <b>true</b> when this node is declared as static, otherwise the
     * returned value will be <b>false</b>.
     *
     * @return boolean
     */
    public function isStatic()
    {
        return (($this->modifiers & State::IS_STATIC) === State::IS_STATIC);
    }

    /**
     * Returns <b>true</b> when this node is declared as final, otherwise the
     * returned value will be <b>false</b>.
     *
     * @return boolean
     */
    public function isFinal()
    {
        return (($this->modifiers & State::IS_FINAL) === State::IS_FINAL);
    }

    /**
     * Returns the parent type object or <b>null</b>
     *
     * @return \PDepend\Source\AST\AbstractASTType|null
     */
    public function getParent()
    {
        return $this->parent;
    }

    /**
     * Sets the parent type object.
     *
     * @param  \PDepend\Source\AST\AbstractASTType $parent
     * @return void
     */
    public function setParent(AbstractASTType $parent = null)
    {
        $this->parent = $parent;
    }

    /**
     * Returns the source file where this method was declared.
     *
     * @return \PDepend\Source\AST\ASTCompilationUnit
     * @throws \PDepend\Source\AST\ASTCompilationUnitNotFoundException When no parent was set.
     * @since  0.10.0
     */
    public function getCompilationUnit()
    {
        if ($this->parent === null) {
            throw new ASTCompilationUnitNotFoundException($this);
        }
        return $this->parent->getCompilationUnit();
    }

    /**
     * ASTVisitor method for node tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @return void
     */
    public function accept(ASTVisitor $visitor)
    {
        $visitor->visitMethod($this);
    }

    /**
     * The magic sleep method will be called by the PHP engine when this class
     * gets serialized. It returns an array with those properties that should be
     * cached for method instances.
     *
     * @return array(string)
     * @since  0.10.0
     */
    public function __sleep()
    {
        return array_merge(array('modifiers'), parent::__sleep());
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

/**
 * This node type represents a variable declarator. A variable declarator always
 * contains a variable name and it can optionally provide a variable default
 * value.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTVariableDeclarator extends ASTExpression
{
    /**
     * The initial declaration value for this node or <b>null</b>.
     *
     * @var \PDepend\Source\AST\ASTValue
     */
    protected $value = null;

    /**
     * Returns the initial declaration value for this node or <b>null</b> when
     * no default value exists.
     *
     * @return \PDepend\Source\AST\ASTValue
     */
    public function getValue()
    {
        return $this->value;
    }

    /**
     * Sets the declared default value for this variable node.
     *
     * @param \PDepend\Source\AST\ASTValue $value
     *
     * @return void
     */
    public function setValue(ASTValue $value)
    {
        $this->value = $value;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitVariableDeclarator($this, $data);
    }

    /**
     * The magic sleep method will be called by PHP's runtime environment right
     * before an instance of this class gets serialized. It should return an
     * array with those property names that should be serialized for this class.
     *
     * @return array(string)
     * @since  0.10.0
     */
    public function __sleep()
    {
        return array_merge(array('value'), parent::__sleep());
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This node class represents a <b>string index</b>-expression.
 *
 * <code>
 * //          ---
 * $object->foo{2}
 * //          ---
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTStringIndexExpression extends ASTIndexExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param  mixed                                 $data
     * @return mixed
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitStringIndexExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This node class represents a array-expression.
 *
 * <code>
 * ------
 * $x[42];
 * ------
 *
 *        -----------
 * $this->foo[23][42];
 *        -----------
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTArrayIndexExpression extends ASTIndexExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param  mixed                                 $data
     * @return mixed
     * @since  0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitArrayIndexExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

/**
 * Base interface for all callables.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface ASTCallable
{
    /**
     * @return \PDepend\Source\AST\ASTType
     */
    public function getReturnType();
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a clone-expression.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTCloneExpression extends \PDepend\Source\AST\ASTExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitCloneExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST\ASTArtifactList;

use PDepend\Source\AST\ASTArtifact;

/**
 * Base interface for {@link \PDepend\Source\AST\ASTArtifactList} filters.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface ArtifactFilter
{
    /**
     * Returns <b>true</b> if the given node should be part of the node iterator,
     * otherwise this method will return <b>false</b>.
     *
     * @param  \PDepend\Source\AST\ASTArtifact $node
     * @return boolean
     */
    public function accept(ASTArtifact $node);
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST\ASTArtifactList;

use PDepend\Source\AST\AbstractASTClassOrInterface;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTNamespace;

/**
 * This class implements a filter that is based on the namespace.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class PackageArtifactFilter implements ArtifactFilter
{
    /**
     * Regexp with ignorable namespace names and namespace name fragments.
     *
     * @var string
     */
    private $pattern = '';

    /**
     * Constructs a new namespace filter for the given list of namespace names.
     *
     * @param array(string) $namespaces
     */
    public function __construct(array $namespaces)
    {
        $patterns = array();
        foreach ($namespaces as $namespace) {
            $patterns[] = str_replace('\*', '\S*', preg_quote($namespace));
        }
        $this->pattern = '#^(' . join('|', $patterns) . ')$#D';
    }

    /**
     * Returns <b>true</b> if the given node should be part of the node iterator,
     * otherwise this method will return <b>false</b>.
     *
     * @param  \PDepend\Source\AST\ASTArtifact $node
     * @return boolean
     */
    public function accept(ASTArtifact $node)
    {
        $namespace = null;
        // NOTE: This looks a little bit ugly and it seems better to exclude
        //       \PDepend\Source\AST\ASTMethod and \PDepend\Source\AST\ASTProperty,
        //       but when PDepend supports more node types, this could produce errors.
        if ($node instanceof AbstractASTClassOrInterface) {
            $namespace = $node->getNamespace()->getName();
        } elseif ($node instanceof ASTFunction) {
            $namespace = $node->getNamespace()->getName();
        } elseif ($node instanceof ASTNamespace) {
            $namespace = $node->getName();
        }

        return (preg_match($this->pattern, $namespace) === 0);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST\ASTArtifactList;

use PDepend\Source\AST\ASTArtifact;

/**
 * This is a simple NULL-implementation of the code filter interface.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class NullArtifactFilter implements ArtifactFilter
{
    /**
     * Returns <b>true</b> if the given node should be part of the node iterator,
     * otherwise this method will return <b>false</b>.
     *
     * @param  \PDepend\Source\AST\ASTArtifact $node
     * @return boolean
     */
    public function accept(ASTArtifact $node)
    {
        return true;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST\ASTArtifactList;

use PDepend\Source\AST\ASTArtifact;

/**
 * Static composite filter for code nodes. This class is used for an overall
 * filtering.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php  BSD License
 *
 * @fixme Never ever use a singleton!!!
 */
final class CollectionArtifactFilter implements ArtifactFilter
{
    /**
     * Singleton instance of this filter.
     *
     * @var \PDepend\Source\AST\ASTArtifactList\CollectionArtifactFilter
     */
    private static $instance = null;

    /**
     * Singleton method for this filter class.
     *
     * @return \PDepend\Source\AST\ASTArtifactList\CollectionArtifactFilter
     */
    public static function getInstance()
    {
        if (self::$instance === null) {
            self::$instance = new CollectionArtifactFilter();
        }
        return self::$instance;
    }

    /**
     * Constructs a new static filter.
     *
     * @access private
     */
    public function __construct()
    {
    }

    /**
     * An optional configured filter instance.
     *
     * @var \PDepend\Source\AST\ASTArtifactList\ArtifactFilter
     */
    private $filter = null;

    /**
     * Sets the used filter instance.
     *
     * @param  \PDepend\Source\AST\ASTArtifactList\ArtifactFilter $filter
     * @return void
     * @since  0.9.12
     */
    public function setFilter(ArtifactFilter $filter = null)
    {
        $this->filter = $filter;
    }

    /**
     * Returns <b>true</b> if the given node should be part of the node iterator,
     * otherwise this method will return <b>false</b>.
     *
     * @param  \PDepend\Source\AST\ASTArtifact $node
     * @return boolean
     */
    public function accept(ASTArtifact $node)
    {
        if ($this->filter === null) {
            return true;
        }
        return $this->filter->accept($node);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

use PDepend\Source\AST\ASTArtifactList\CollectionArtifactFilter;

/**
 * Iterator for code nodes.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTArtifactList implements \ArrayAccess, \Iterator, \Countable
{
    /**
     * List of {@link \PDepend\Source\AST\ASTArtifact} objects in
     * this iterator.
     *
     * @var \PDepend\Source\AST\ASTArtifact[]
     */
    private $artifacts = array();

    /**
     * Total number of available nodes.
     *
     * @var integer
     */
    private $count = 0;

    /**
     * Current internal offset.
     *
     * @var integer
     */
    private $offset = 0;

    /**
     * Constructs a new node iterator from the given {@link \PDepend\Source\AST\ASTArtifact}
     * node array.
     *
     * @param \PDepend\Source\AST\ASTArtifact[] $artifacts
     */
    public function __construct(array $artifacts)
    {
        $filter = CollectionArtifactFilter::getInstance();

        $nodeKeys = array();
        foreach ($artifacts as $artifact) {
            $id = $artifact->getId();

            if (isset($nodeKeys[$id])) {
                continue;
            }

            if ($filter->accept($artifact)) {
                $nodeKeys[$id] = $id;
                $this->artifacts[]  = $artifact;

                ++$this->count;
            }
        }
    }

    /**
     * Returns the number of {@link \PDepend\Source\AST\ASTArtifact}
     * objects in this iterator.
     *
     * @return integer
     */
    public function count()
    {
        return count($this->artifacts);
    }

    /**
     * Returns the current node or <b>false</b>
     *
     * @return \PDepend\Source\AST\ASTArtifact
     */
    public function current()
    {
        if ($this->offset >= $this->count) {
            return false;
        }
        return $this->artifacts[$this->offset];
    }

    /**
     * Returns the name of the current {@link \PDepend\Source\AST\ASTArtifact}.
     *
     * @return string
     */
    public function key()
    {
        return $this->artifacts[$this->offset]->getName();
    }

    /**
     * Moves the internal pointer to the next {@link \PDepend\Source\AST\ASTArtifact}.
     *
     * @return void
     */
    public function next()
    {
        ++$this->offset;
    }

    /**
     * Rewinds the internal pointer.
     *
     * @return void
     */
    public function rewind()
    {
        $this->offset = 0;
    }

    /**
     * Returns <b>true</b> while there is a next {@link \PDepend\Source\AST\ASTArtifact}.
     *
     * @return boolean
     */
    public function valid()
    {
        return ($this->offset < $this->count);
    }

    /**
     * Whether a offset exists
     *
     * @param mixed $offset An offset to check for.
     *
     * @return boolean Returns true on success or false on failure. The return
     *                 value will be casted to boolean if non-boolean was returned.
     * @since  1.0.0
     * @link   http://php.net/manual/en/arrayaccess.offsetexists.php
     */
    public function offsetExists($offset)
    {
        return isset($this->artifacts[$offset]);
    }

    /**
     * Offset to retrieve
     *
     * @param  mixed $offset
     * @return \PDepend\Source\AST\ASTArtifact Can return all value types.
     * @throws \OutOfBoundsException
     * @since  1.0.0
     * @link   http://php.net/manual/en/arrayaccess.offsetget.php
     */
    public function offsetGet($offset)
    {
        if (isset($this->artifacts[$offset])) {
            return $this->artifacts[$offset];
        }
        throw new \OutOfBoundsException("The offset {$offset} does not exist.");
    }

    /**
     * Offset to set
     *
     * @param  mixed $offset
     * @param  mixed $value
     * @return void
     * @throws \BadMethodCallException
     * @since  1.0.0
     * @link   http://php.net/manual/en/arrayaccess.offsetset.php
     */
    public function offsetSet($offset, $value)
    {
        throw new \BadMethodCallException('Not supported operation.');
    }

    /**
     * Offset to unset
     *
     * @param  mixed $offset
     * @return void
     * @throws \BadMethodCallException
     * @since  1.0.0
     * @link   http://php.net/manual/en/arrayaccess.offsetunset.php
     */
    public function offsetUnset($offset)
    {
        throw new \BadMethodCallException('Not supported operation.');
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This class represents a single constant definition as it can occure in
 * class definition or interface declaration.
 *
 * <code>
 * class Foo
 * {
 * //  ------------------------
 *     const FOO = 42, BAR = 23;
 * //  ------------------------
 * }
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTConstantDefinition extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return mixed
     * @since 0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitConstantDefinition($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a trait adaptation alias.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */
class ASTTraitAdaptationAlias extends ASTStatement
{
    /**
     * The new aliased method name.
     *
     * @var string
     */
    protected $newName;

    /**
     * The new method modifier for the imported method.
     *
     * @var integer
     */
    protected $newModifier = -1;

    /**
     * Sets the new method modifier.
     *
     * @param integer $newModifier The new method modifier.
     *
     * @return void
     */
    public function setNewModifier($newModifier)
    {
        $this->newModifier = $newModifier;
    }

    /**
     * Returns the new method modifier or <b>-1</b> when this alias does not
     * specify a new method modifier.
     *
     * @return integer
     */
    public function getNewModifier()
    {
        return $this->newModifier;
    }

    /**
     * Sets the new aliased method name.
     *
     * @param string $newName The new aliased method name.
     *
     * @return void
     */
    public function setNewName($newName)
    {
        $this->newName = $newName;
    }

    /**
     * Returns the new aliased method name or <b>NULL</b> when this alias does
     * not specify a new method name.
     *
     * @return string
     */
    public function getNewName()
    {
        return $this->newName;
    }

    /**
     * The magic sleep method will be called by PHP's runtime environment right
     * before an instance of this class gets serialized. It should return an
     * array with those property names that should be serialized for this class.
     *
     * @return array
     */
    public function __sleep()
    {
        return array_merge(array('newName', 'newModifier'), parent::__sleep());
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitTraitAdaptationAlias($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a break-statement.
 *
 * <code>
 * ------
 * break;
 * ------
 *
 * ---------
 * break 42;
 * ---------
 *
 * ----------------------
 * break $this->foobar();
 * ----------------------
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTBreakStatement extends \PDepend\Source\AST\ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitBreakStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a logical <b>and</b>-expression.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */
class ASTLogicalAndExpression extends ASTExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitLogicalAndExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This is node represents a single statement.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTStatement extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;
use PDepend\Source\Builder\BuilderContext;

/**
 * This is a special reference container that is used whenever the keyword
 * <b>self</b> is used to reference a class or interface.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTSelfReference extends ASTClassOrInterfaceReference
{
    /**
     * The source image of this node.
     */
    const IMAGE = 'self';

    /**
     * The currently used builder context.
     *
     * @var   \PDepend\Source\Builder\BuilderContext
     * @since 0.10.0
     */
    protected $context = null;

    /**
     * The full qualified class name, including the namespace or namespace name.
     *
     * @var   string
     * @since 0.10.0
     * @todo  To reduce memory usage, move property into new metadata string
     */
    protected $qualifiedName = null;

    /**
     * Constructs a new type holder instance.
     *
     * @param \PDepend\Source\Builder\BuilderContext          $context
     * @param \PDepend\Source\AST\AbstractASTClassOrInterface
     */
    public function __construct(BuilderContext $context, AbstractASTClassOrInterface $target)
    {
        $this->context      = $context;
        $this->typeInstance = $target;
    }

    /**
     * Returns the visual representation for this node type.
     *
     * @return string
     * @since  0.10.4
     */
    public function getImage()
    {
        return self::IMAGE;
    }

    /**
     * Returns the class or interface instance that this node instance represents.
     *
     * @return \PDepend\Source\AST\AbstractASTClassOrInterface
     * @since  0.10.0
     */
    public function getType()
    {
        if ($this->typeInstance == null) {
            $this->typeInstance = $this->context
                ->getClassOrInterface($this->qualifiedName);
        }
        return $this->typeInstance;
    }

    /**
     * The magic sleep method will be called by PHP's runtime environment right
     * before an instance of this class gets serialized. It should return an
     * array with those property names that should be serialized for this class.
     *
     * @return array
     * @since  0.10.0
     */
    public function __sleep()
    {
        $this->qualifiedName = $this->getType()->getNamespaceName() . '\\' .
                               $this->getType()->getName();

        return array_merge(array('qualifiedName'), parent::__sleep());
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param  mixed                                 $data
     * @return mixed
     * @since  0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitSelfReference($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a method/function scope.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTScope extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitScope($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This node class represents an echo-statement.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTEchoStatement extends \PDepend\Source\AST\ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitEchoStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This class represents a constant node.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTConstant extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return mixed
     * @since 0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitConstant($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

/**
 * This is a special implementation of the node iterator that will translate
 * a list of given {@link \PDepend\Source\AST\ASTClassOrInterfaceReference} holders
 * into a list of unique {@link \PDepend\Source\AST\AbstractASTClassOrInterface}
 * instances.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTClassOrInterfaceReferenceIterator extends ASTArtifactList
{
    /**
     * Constructs a new reference iterator instance.
     *
     * @param \PDepend\Source\AST\ASTClassOrInterfaceReference[] $references List of
     *        references to concrete type instances.
     */
    public function __construct(array $references)
    {
        parent::__construct($this->createClassesAndInterfaces($references));
    }

    /**
     * This method creates a set of {@link \PDepend\Source\AST\AbstractASTClassOrInterface}
     * objects from the given reference array.
     *
     * @param  \PDepend\Source\AST\ASTClassOrInterfaceReference[] $references
     * @return \PDepend\Source\AST\AbstractASTClassOrInterface[]
     */
    protected function createClassesAndInterfaces(array $references)
    {
        $classesAndInterfaces = array();

        foreach ($references as $reference) {
            $classOrInterface = $reference->getType();

            if (isset($classesAndInterfaces[$classOrInterface->getId()])) {
                continue;
            }
            $classesAndInterfaces[$classOrInterface->getId()] = $classOrInterface;
        }

        return $classesAndInterfaces;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */

namespace PDepend\Source\AST;

/**
 * This type of exception will be thrown when an inheritance hierarchy is
 * recursive, so that .
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */
class ASTClassOrInterfaceRecursiveInheritanceException extends \RuntimeException
{
    /**
     * Constructs a new exception instance.
     *
     * @param \PDepend\Source\AST\AbstractASTClassOrInterface $type
     */
    public function __construct(AbstractASTClassOrInterface $type)
    {
        parent::__construct(
            sprintf(
                'Type %s\%s is part of an endless inheritance hierarchy.',
                preg_replace('(\W+)', '\\', $type->getNamespace()->getName()),
                $type->getName()
            )
        );
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * Representation of a code interface.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTInterface extends AbstractASTClassOrInterface
{
    /**
     * The modifiers for this interface instance, by default an interface is
     * always abstract.
     *
     * @var integer
     */
    protected $modifiers = State::IS_IMPLICIT_ABSTRACT;

    /**
     * Returns <b>true</b> if this is an abstract class or an interface.
     *
     * @return boolean
     */
    public function isAbstract()
    {
        return true;
    }

    /**
     * Sets a reference onto the parent class of this class node.
     *
     * @param  \PDepend\Source\AST\ASTClassReference
     * @return void
     * @throws \BadMethodCallException
     * @since  0.9.5
     */
    public function setParentClassReference(\PDepend\Source\AST\ASTClassReference $classReference)
    {
        throw new \BadMethodCallException(
            'Unsupported method ' . __METHOD__ . '() called.'
        );
    }

    /**
     * Checks that this user type is a subtype of the given <b>$type</b> instance.
     *
     * @param  \PDepend\Source\AST\AbstractASTType $type
     * @return boolean
     */
    public function isSubtypeOf(AbstractASTType $type)
    {
        if ($type === $this) {
            return true;
        } elseif ($type instanceof ASTInterface) {
            foreach ($this->getInterfaces() as $interface) {
                if ($interface === $type) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Returns the declared modifiers for this type.
     *
     * @return integer
     * @since  0.9.4
     */
    public function getModifiers()
    {
        return $this->modifiers;
    }

    /**
     * ASTVisitor method for node tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @return void
     */
    public function accept(ASTVisitor $visitor)
    {
        $visitor->visitInterface($this);
    }

    /**
     * The magic wakeup method will be called by PHP's runtime environment when
     * a serialized instance of this class was unserialized. This implementation
     * of the wakeup method will register this object in the the global class
     * context.
     *
     * @return void
     * @since  0.10.0
     */
    public function __wakeup()
    {
        parent::__wakeup();

        $this->context->registerInterface($this);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a closure-expression.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTClosure extends AbstractASTNode implements ASTCallable
{
    /**
     * @return \PDepend\Source\AST\ASTType
     */
    public function getReturnType()
    {
        foreach ($this->nodes as $node) {
            if ($node instanceof ASTType) {
                return $node;
            }
        }
        return null;
    }

    /**
     * This method will return <b>true</b> when this closure returns by
     * reference.
     *
     * @return boolean
     */
    public function returnsByReference()
    {
        return $this->getMetadataBoolean(5);
    }

    /**
     * This method can be used to flag this closure as returns by reference.
     *
     * @param boolean $returnsReference Does this closure return by reference?
     *
     * @return void
     */
    public function setReturnsByReference($returnsReference)
    {
        $this->setMetadataBoolean(5, (boolean) $returnsReference);
    }

    /**
     * Returns whether this closure was defined as static or not.
     *
     * This method will return <b>TRUE</b> when the closure was declared as
     * followed:
     *
     * <code>
     * $closure = static function( $e ) {
     *   return pow( $e, 2 );
     * }
     * </code>
     *
     * And it will return <b>FALSE</b> when we declare the closure as usual:
     *
     * <code>
     * $closure = function( $e ) {
     *   return pow( $e, 2 );
     * }
     * </code>
     *
     * @return boolean
     * @since  1.0.0
     */
    public function isStatic()
    {
        return $this->getMetadataBoolean(6);
    }

    /**
     * This method can be used to flag this closure instance as static.
     *
     * @param boolean $static Whether this closure is static or not.
     *
     * @return void
     * @since  1.0.0
     */
    public function setStatic($static)
    {
        $this->setMetadataBoolean(6, (boolean) $static);
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitClosure($this, $data);
    }

    /**
     * Returns the total number of the used property bag.
     *
     * @return integer
     * @since  1.0.0
     * @see    \PDepend\Source\AST\ASTNode#getMetadataSize()
     */
    protected function getMetadataSize()
    {
        return 7;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.10
 */

namespace PDepend\Source\AST;

/**
 * This class represents PHP strings that can embed various other expressions.
 *
 * <code>
 * $string = "Manuel $Pichler <{$email}>";
 *
 * // \PDepend\Source\AST\ASTString
 * // |-- ASTLiteral             -  "Manuel ")
 * // |-- ASTVariable            -  $Pichler
 * // |-- ASTLiteral             -  " <"
 * // |-- ASTCompoundExpression  -  {...}
 * // |   |-- ASTVariable        -  $email
 * // |-- ASTLiteral             -  ">"
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.10
 */
class ASTString extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitString($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This node class represents a pre-increment-expression.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */
class ASTPreIncrementExpression extends ASTUnaryExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param  mixed                                 $data
     * @return mixed
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitPreIncrementExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

/**
 * This class represents a property postfix expression..
 *
 * <code>
 * //   ----
 * Foo::$bar;
 * //   ----
 *
 * //   -----
 * Foo::$$bar;
 * //   -----
 *
 * //    ---
 * $foo->bar;
 * //    ---
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTPropertyPostfix extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitPropertyPostfix($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

use PDepend\Util\Cache\CacheDriver;

/**
 * Abstract base class for callable objects.
 *
 * Callable objects is a generic parent for methods and functions.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
abstract class AbstractASTCallable extends AbstractASTArtifact implements ASTCallable
{
    /**
     * The internal used cache instance.
     *
     * @var   \PDepend\Util\Cache\CacheDriver
     * @since 0.10.0
     */
    protected $cache = null;

    /**
     * A reference instance for the return value of this callable. By
     * default and for any scalar type this property is <b>null</b>.
     *
     * @var   \PDepend\Source\AST\ASTClassOrInterfaceReference
     * @since 0.9.5
     */
    protected $returnClassReference = null;

    /**
     * List of all exceptions classes referenced by this callable.
     *
     * @var   \PDepend\Source\AST\ASTClassOrInterfaceReference[]
     * @since 0.9.5
     */
    protected $exceptionClassReferences = array();

    /**
     * Does this callable return a value by reference?
     *
     * @var boolean
     */
    protected $returnsReference = false;

    /**
     * List of all parsed child nodes.
     *
     * @var   \PDepend\Source\AST\ASTNode[]
     * @since 0.9.6
     */
    protected $nodes = array();

    /**
     * The start line number of the method or function declaration.
     *
     * @var   integer
     * @since 0.9.12
     */
    protected $startLine = 0;

    /**
     * The end line number of the method or function declaration.
     *
     * @var   integer
     * @since 0.9.12
     */
    protected $endLine = 0;

    /**
     * List of method/function parameters.
     *
     * @var \PDepend\Source\AST\ASTParameter[]
     */
    private $parameters = null;

    /**
     * Setter method for the currently used token cache, where this callable
     * instance can store the associated tokens.
     *
     * @param  \PDepend\Util\Cache\CacheDriver $cache
     * @return \PDepend\Source\AST\AbstractASTCallable
     * @since  0.10.0
     */
    public function setCache(CacheDriver $cache)
    {
        $this->cache = $cache;
        return $this;
    }

    /**
     * Adds a parsed child node to this node.
     *
     * @param \PDepend\Source\AST\ASTNode $node A parsed child node instance.
     *
     * @return void
     * @access private
     * @since  0.9.6
     */
    public function addChild(ASTNode $node)
    {
        $this->nodes[] = $node;
    }

    /**
     * Returns all child nodes of this method.
     *
     * @return \PDepend\Source\AST\ASTNode[]
     * @since  0.9.8
     */
    public function getChildren()
    {
        return $this->nodes;
    }

    /**
     * This method will search recursive for the first child node that is an
     * instance of the given <b>$targetType</b>. The returned value will be
     * <b>null</b> if no child exists for that.
     *
     * @param string $targetType Searched class or interface type.
     *
     * @return \PDepend\Source\AST\ASTNode
     * @access private
     * @since  0.9.6
     */
    public function getFirstChildOfType($targetType)
    {
        foreach ($this->nodes as $node) {
            if ($node instanceof $targetType) {
                return $node;
            }
            if (($child = $node->getFirstChildOfType($targetType)) !== null) {
                return $child;
            }
        }
        return null;
    }

    /**
     * Will find all children for the given type.
     *
     * @param string $targetType The target class or interface type.
     * @param array  &$results   The found children.
     *
     * @return \PDepend\Source\AST\ASTNode[]
     * @access private
     * @since  0.9.6
     */
    public function findChildrenOfType($targetType, array &$results = array())
    {
        foreach ($this->nodes as $node) {
            if ($node instanceof $targetType) {
                $results[] = $node;
            }
            $node->findChildrenOfType($targetType, $results);
        }
        return $results;
    }

    /**
     * Returns the tokens found in the function body.
     *
     * @return array(mixed)
     */
    public function getTokens()
    {
        return (array) $this->cache
            ->type('tokens')
            ->restore($this->id);
    }

    /**
     * Sets the tokens found in the function body.
     *
     * @param \PDepend\Source\Tokenizer\Token[] $tokens The body tokens.
     *
     * @return void
     */
    public function setTokens(array $tokens)
    {
        $this->startLine = reset($tokens)->startLine;
        $this->endLine   = end($tokens)->endLine;

        $this->cache
            ->type('tokens')
            ->store($this->id, $tokens);
    }

    /**
     * Returns the line number where the callable declaration starts.
     *
     * @return integer
     * @since  0.9.6
     */
    public function getStartLine()
    {
        return $this->startLine;
    }

    /**
     * Returns the line number where the callable declaration ends.
     *
     * @return integer
     * @since  0.9.6
     */
    public function getEndLine()
    {
        return $this->endLine;
    }

    /**
     * Returns all {@link \PDepend\Source\AST\AbstractASTClassOrInterface}
     * objects this function depends on.
     *
     * @return \PDepend\Source\AST\AbstractASTClassOrInterface[]
     */
    public function getDependencies()
    {
        return new ASTClassOrInterfaceReferenceIterator(
            $this->findChildrenOfType(
                'PDepend\\Source\\AST\\ASTClassOrInterfaceReference'
            )
        );
    }

    /**
     * This method will return a class or interface instance that represents
     * the return value of this callable. The returned value will be <b>null</b>
     * if there is no return value or the return value is scalat.
     *
     * @return \PDepend\Source\AST\AbstractASTClassOrInterface
     * @since  0.9.5
     */
    public function getReturnClass()
    {
        if ($this->returnClassReference) {
            return $this->returnClassReference->getType();
        }
        if (($node = $this->getReturnType()) instanceof ASTClassOrInterfaceReference) {
            return $node->getType();
        }
        return null;
    }

    /**
     * Tests if this callable has a return class and return <b>true</b> if it is
     * configured.
     *
     * @return boolean
     * @since 2.2.4
     */
    public function hasReturnClass()
    {
        if ($this->returnClassReference) {
            return true;
        }
        if (($node = $this->getReturnType()) instanceof ASTClassOrInterfaceReference) {
            return true;
        }
        return false;
    }

    /**
     * @return \PDepend\Source\AST\ASTType
     */
    public function getReturnType()
    {
        foreach ($this->nodes as $node) {
            if ($node instanceof ASTType) {
                return $node;
            }
        }
        return null;
    }

    /**
     * This method can be used to set a reference instance for the declared
     * function return type.
     *
     * @param \PDepend\Source\AST\ASTClassOrInterfaceReference $classReference Holder
     *        instance for the declared function return type.
     *
     * @return void
     * @since  0.9.5
     */
    public function setReturnClassReference(ASTClassOrInterfaceReference $classReference)
    {
        $this->returnClassReference = $classReference;
    }

    /**
     * Adds a reference holder for a thrown exception class or interface to
     * this callable.
     *
     * @param \PDepend\Source\AST\ASTClassOrInterfaceReference $classReference A
     *        reference instance for a thrown exception.
     *
     * @return void
     * @since  0.9.5
     */
    public function addExceptionClassReference(
        \PDepend\Source\AST\ASTClassOrInterfaceReference $classReference
    ) {
        $this->exceptionClassReferences[] = $classReference;
    }

    /**
     * Returns an iterator with thrown exception
     * {@link \PDepend\Source\AST\AbstractASTClassOrInterface} instances.
     *
     * @return \PDepend\Source\AST\AbstractASTClassOrInterface[]
     */
    public function getExceptionClasses()
    {
        return new ASTClassOrInterfaceReferenceIterator(
            $this->exceptionClassReferences
        );
    }

    /**
     * Returns an array with all method/function parameters.
     *
     * @return \PDepend\Source\AST\ASTParameter[]
     */
    public function getParameters()
    {
        if ($this->parameters === null) {
            $this->initParameters();
        }
        return $this->parameters;
    }

    /**
     * This method will return <b>true</b> when this method returns a value by
     * reference, otherwise the return value will be <b>false</b>.
     *
     * @return boolean
     * @since  0.9.5
     */
    public function returnsReference()
    {
        return $this->returnsReference;
    }

    /**
     * A call to this method will flag the callable instance with the returns
     * reference flag, which means that the context function or method returns
     * a value by reference.
     *
     * @return void
     * @since  0.9.5
     */
    public function setReturnsReference()
    {
        $this->returnsReference = true;
    }

    /**
     * Returns an array with all declared static variables.
     *
     * @return array
     * @since  0.9.6
     */
    public function getStaticVariables()
    {
        $staticVariables = array();

        $declarations = $this->findChildrenOfType(
            'PDepend\\Source\\AST\\ASTStaticVariableDeclaration'
        );
        foreach ($declarations as $declaration) {
            $variables = $declaration->findChildrenOfType(
                'PDepend\\Source\\AST\\ASTVariableDeclarator'
            );
            foreach ($variables as $variable) {
                $image = $variable->getImage();
                $value = $variable->getValue();
                if ($value !== null) {
                    $value = $value->getValue();
                }

                $staticVariables[substr($image, 1)] = $value;
            }
        }
        return $staticVariables;
    }

    /**
     * This method will return <b>true</b> when this callable instance was
     * restored from the cache and not currently parsed. Otherwise this method
     * will return <b>false</b>.
     *
     * @return boolean
     * @since  0.10.0
     */
    public function isCached()
    {
        return $this->compilationUnit->isCached();
    }

    /**
     * This method will initialize the <b>$_parameters</b> property.
     *
     * @return void
     * @since  0.9.6
     */
    private function initParameters()
    {
        $parameters = array();

        $formalParameters = $this->getFirstChildOfType(
            'PDepend\\Source\\AST\\ASTFormalParameters'
        );

        $formalParameters = $formalParameters->findChildrenOfType(
            'PDepend\\Source\\AST\\ASTFormalParameter'
        );

        foreach ($formalParameters as $formalParameter) {
            $parameter = new ASTParameter($formalParameter);
            $parameter->setDeclaringFunction($this);
            $parameter->setPosition(count($parameters));

            $parameters[] = $parameter;
        }

        $optional = true;
        foreach (array_reverse($parameters) as $parameter) {
            if ($parameter->isDefaultValueAvailable() === false) {
                $optional = false;
            }
            $parameter->setOptional($optional);
        }

        $this->parameters = $parameters;
    }

    /**
     * The magic sleep method will be called by the PHP engine when this class
     * gets serialized. It returns an array with those properties that should be
     * cached for all callable instances.
     *
     * @return array
     * @since  0.10.0
     */
    public function __sleep()
    {
        return array(
            'cache',
            'id',
            'name',
            'nodes',
            'startLine',
            'endLine',
            'comment',
            'returnsReference',
            'returnClassReference',
            'exceptionClassReferences'
        );
    }

    // @codeCoverageIgnoreStart

    /**
     * This method can be called by the PDepend runtime environment or a
     * utilizing component to free up memory. This methods are required for
     * PHP version < 5.3 where cyclic references can not be resolved
     * automatically by PHP's garbage collector.
     *
     * @return void
     * @since  0.9.12
     */
    public function free()
    {
        trigger_error(__METHOD__ . '() is deprecated.', E_USER_DEPRECATED);
    }

    // @codeCoverageIgnoreEnd
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

/**
 * This node class represent the init part of a for-statement.
 *
 * <code>
 *      ------------------------
 * for ($x = 0, $y = 23, $z = 42; $x < $y; ++$x) {}
 *      ------------------------
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTForInit extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitForInit($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This node class represent the update part of a for-statement.
 *
 * <code>
 *                                        -------------------------------
 * for ($x = 0, $y = 23, $z = 42; $x < $y; ++$x, $y = $x + 1, $z = $x + 2) {}
 *                                        -------------------------------
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTForUpdate extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitForUpdate($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This class represents a yield statement node.
 *
 * <code>
 * //   -------
 *      yield 24;
 * //   -------
 *
 * //   ----------
 *      yield $variable;
 * //   ----------
 *
 * //   ---------------------------------------------
 *      yield $foo => $bar;
 * //   ---------------------------------------------
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since @TODO
 */
class ASTYieldStatement extends ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitYieldStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;
use PDepend\Util\Cache\CacheDriver;

/**
 * This class provides an interface to a single source file.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTCompilationUnit extends AbstractASTArtifact
{
    /**
     * The internal used cache instance.
     *
     * @var   \PDepend\Util\Cache\CacheDriver
     * @since 0.10.0
     */
    protected $cache = null;

    /**
     * The unique identifier for this function.
     *
     * @var string
     */
    protected $id = null;

    /**
     * The source file name/path.
     *
     * @var string
     */
    protected $fileName = null;

    /**
     * The comment for this type.
     *
     * @var string
     */
    protected $comment = null;

    /**
     * The files start line. This property must always have the value <em>1</em>.
     *
     * @var   integer
     * @since 0.10.0
     */
    protected $startLine = 0;

    /**
     * The files end line.
     *
     * @var   integer
     * @since 0.10.0
     */
    protected $endLine = 0;

    /**
     * List of classes, interfaces and functions that parsed from this file.
     *
     * @var   \PDepend\Source\AST\AbstractASTArtifact[]
     * @since 0.10.0
     */
    protected $childNodes = array();

    /**
     * Was this file instance restored from the cache?
     *
     * @var   boolean
     * @since 0.10.0
     */
    protected $cached = false;

    /**
     * Normalized code in this file.
     *
     * @var string
     */
    private $source = null;

    /**
     * Constructs a new source file instance.
     *
     * @param string $fileName The source file name/path.
     */
    public function __construct($fileName)
    {
        if (strpos($fileName, 'php://') === 0) {
            $this->fileName = $fileName;
        } elseif ($fileName !== null) {
            $this->fileName = realpath($fileName);
        }
    }

    /**
     * Returns the physical file name for this object.
     *
     * @return string
     */
    public function getName()
    {
        return $this->fileName;
    }

    /**
     * Returns the physical file name for this object.
     *
     * @return string
     */
    public function getFileName()
    {
        return $this->fileName;
    }

    /**
     * Returns a id for this code node.
     *
     * @return string
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Sets the unique identifier for this file instance.
     *
     * @param  string $id Identifier for this file.
     * @return void
     * @since  0.9.12
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * Setter method for the used parser and token cache.
     *
     * @param  \PDepend\Util\Cache\CacheDriver $cache
     * @return \PDepend\Source\AST\ASTCompilationUnit
     * @since  0.10.0
     */
    public function setCache(CacheDriver $cache)
    {
        $this->cache = $cache;
        return $this;
    }

    /**
     * Returns normalized source code with stripped whitespaces.
     *
     * @return array(integer=>string)
     */
    public function getSource()
    {
        $this->readSource();
        return $this->source;
    }

    /**
     * Returns an <b>array</b> with all tokens within this file.
     *
     * @return array(array)
     */
    public function getTokens()
    {
        return (array) $this->cache
            ->type('tokens')
            ->restore($this->getId());
    }

    /**
     * Sets the tokens for this file.
     *
     * @param array(array) $tokens The generated tokens.
     *
     * @return void
     */
    public function setTokens(array $tokens)
    {
        $this->cache
            ->type('tokens')
            ->store($this->getId(), $tokens);
    }

    /**
     * Adds a source item that was parsed from this source file.
     *
     * @param  \PDepend\Source\AST\AbstractASTArtifact $artifact
     * @return void
     * @since  0.10.0
     */
    public function addChild(AbstractASTArtifact $artifact)
    {
        $this->childNodes[$artifact->getId()] = $artifact;
    }

    /**
     * Returns the start line number for this source file. For an existing file
     * this value must always be <em>1</em>, while it can be <em>0</em> for a
     * not existing dummy file.
     *
     * @return integer
     * @since  0.10.0
     */
    public function getStartLine()
    {
        if ($this->startLine === 0) {
            $this->readSource();
        }
        return $this->startLine;
    }

    /**
     * Returns the start line number for this source file. For an existing file
     * this value must always be greater <em>0</em>, while it can be <em>0</em>
     * for a not existing dummy file.
     *
     * @return integer
     * @since  0.10.0
     */
    public function getEndLine()
    {
        if ($this->endLine === 0) {
            $this->readSource();
        }
        return $this->endLine;
    }

    /**
     * This method will return <b>true</b> when this file instance was restored
     * from the cache and not currently parsed. Otherwise this method will return
     * <b>false</b>.
     *
     * @return boolean
     * @since  0.10.0
     */
    public function isCached()
    {
        return $this->cached;
    }

    /**
     * ASTVisitor method for node tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @return void
     */
    public function accept(ASTVisitor $visitor)
    {
        $visitor->visitCompilationUnit($this);
    }

    /**
     * The magic sleep method will be called by PHP's runtime environment right
     * before it serializes an instance of this class. This method returns an
     * array with those property names that should be serialized.
     *
     * @return array(string)
     * @since  0.10.0
     */
    public function __sleep()
    {
        return array(
            'cache',
            'childNodes',
            'comment',
            'endLine',
            'fileName',
            'startLine',
            'id'
        );
    }

    /**
     * The magic wakeup method will is called by PHP's runtime environment when
     * a serialized instance of this class was unserialized. This implementation
     * of the wakeup method restores the references between all parsed entities
     * in this source file and this file instance.
     *
     * @return void
     * @since  0.10.0
     * @see    \PDepend\Source\AST\ASTCompilationUnit::$childNodes
     */
    public function __wakeup()
    {
        $this->cached = true;

        foreach ($this->childNodes as $childNode) {
            $childNode->setCompilationUnit($this);
        }
    }

    /**
     * Returns the string representation of this class.
     *
     * @return string
     */
    public function __toString()
    {
        return ($this->fileName === null ? '' : $this->fileName);
    }

    /**
     * Reads the source file if required.
     *
     * @return void
     */
    protected function readSource()
    {
        if ($this->source === null && (file_exists($this->fileName) || strpos($this->fileName, 'php://') === 0)) {
            $source = file_get_contents($this->fileName);

            $this->source = str_replace(array("\r\n", "\r"), "\n", $source);

            $this->startLine = 1;
            $this->endLine   = substr_count($this->source, "\n") + 1;
        }
    }
    
    // Deprecated methods
    // @codeCoverageIgnoreStart

    /**
     * This method can be called by the PDepend runtime environment or a
     * utilizing component to free up memory. This methods are required for
     * PHP version < 5.3 where cyclic references can not be resolved
     * automatically by PHP's garbage collector.
     *
     * @return     void
     * @since  0.9.12
     * @deprecated Since 0.10.0
     */
    public function free()
    {
        fwrite(STDERR, __METHOD__ . ' is deprecated since version 0.10.0' . PHP_EOL);
    }

    // @codeCoverageIgnoreEnd
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */

namespace PDepend\Source\AST;

/**
 * This node class represents an elseif-statement.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */
class ASTElseIfStatement extends \PDepend\Source\AST\ASTStatement
{
    /**
     * Returns <b>true</b> when this <b>elseif</b>-statement is followed by an
     * <b>else</b>-statement.
     *
     * @return boolean
     * @since  0.9.12
     */
    public function hasElse()
    {
        if (count($this->nodes) === 3) {
            return (count($this->nodes) === 3);
        }
        return false;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitElseIfStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a throw-statement.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTThrowStatement extends ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitThrowStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

/**
 * This class represents primitive types like integer, float, boolean, string
 * etc.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTScalarType extends ASTType
{
    /**
     * This method will return <b>true</b> when this type is a php primitive.
     * For this concrete implementation the return value will be always true.
     *
     * @return boolean
     */
    public function isScalar()
    {
        return true;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitScalarType($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

/**
 * This is an abstract base implementation of the ast node interface.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.3
 */
interface ASTNode
{
    /**
     * Returns the source image of this ast node.
     *
     * @return string
     */
    public function getImage();

    /**
     * Returns the start line for this ast node.
     *
     * @return integer
     */
    public function getStartLine();

    /**
     * Returns the start column for this ast node.
     *
     * @return integer
     */
    public function getStartColumn();

    /**
     * Returns the end line for this ast node.
     *
     * @return integer
     */
    public function getEndLine();

    /**
     * Returns the end column for this ast node.
     *
     * @return integer
     */
    public function getEndColumn();

    /**
     * Returns the node instance for the given index or throws an exception.
     *
     * @param integer $index
     * @return \PDepend\Source\AST\ASTNode
     * @throws \OutOfBoundsException When no node exists at the given index.
     */
    public function getChild($index);

    /**
     * This method returns all direct children of the actual node.
     *
     * @return \PDepend\Source\AST\ASTNode[]
     */
    public function getChildren();

    /**
     * This method will search recursive for the first child node that is an
     * instance of the given <b>$targetType</b>. The returned value will be
     * <b>null</b> if no child exists for that.
     *
     * @param string $targetType
     * @return \PDepend\Source\AST\ASTNode
     */
    public function getFirstChildOfType($targetType);

    /**
     * This method will search recursive for all child nodes that are an
     * instance of the given <b>$targetType</b>. The returned value will be
     * an empty <b>array</b> if no child exists for that.
     *
     * @param string $targetType Searched class or interface type.
     * @param array &$results Already found node instances. This parameter
     *        is only for internal usage.
     * @return \PDepend\Source\AST\ASTNode[]
     */
    public function findChildrenOfType($targetType, array &$results = array());

    /**
     * Returns the parent node of this node or <b>null</b> when this node is
     * the root of a node tree.
     *
     * @return \PDepend\Source\AST\ASTNode
     */
    public function getParent();

    /**
     * Sets the parent node of this node.
     *
     * @param \PDepend\Source\AST\ASTNode $node
     * @return void
     */
    public function setParent(ASTNode $node);

    /**
     * Traverses up the node tree and finds all parent nodes that are instances
     * of <b>$parentType</b>.
     *
     * @param string $parentType
     * @return \PDepend\Source\AST\ASTNode[]
     */
    public function getParentsOfType($parentType);

    /**
     * Returns a doc comment for this node or <b>null</b> when no comment was
     * found.
     *
     * @return string
     */
    public function getComment();

    /**
     * Sets the raw doc comment for this node.
     *
     * @param string $comment The doc comment block for this node.
     *
     * @return void
     */
    public function setComment($comment);

    /**
     * For better performance we have moved the single setter methods for the
     * node columns and lines into this configure method.
     *
     * @param integer $startLine
     * @param integer $endLine
     * @param integer $startColumn
     * @param integer $endColumn
     * @return void
     * @since 0.9.10
     */
    public function configureLinesAndColumns($startLine, $endLine, $startColumn, $endColumn);
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a switch statement.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTSwitchStatement extends ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitSwitchStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

/**
 * This class represents a field or property declaration of a class.
 *
 * <code>
 * // Simple field declaration
 * class Foo {
 *     protected $foo;
 * }
 *
 * // Field declaration with multiple properties
 * class Foo {
 *     protected $foo = 23
 *               $bar = 42,
 *               $baz = null;
 * }
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTFieldDeclaration extends AbstractASTNode
{
    /**
     * This method returns a OR combined integer of the declared modifiers for
     * this property.
     *
     * @return integer
     */
    public function getModifiers()
    {
        return $this->getMetadataInteger(5);
    }

    /**
     * This method sets a OR combined integer of the declared modifiers for this
     * node.
     *
     * This method will throw an exception when the value of given <b>$modifiers</b>
     * contains an invalid/unexpected modifier
     *
     * @param integer $modifiers The declared modifiers for this node.
     *
     * @return void
     * @throws \InvalidArgumentException If the given modifier contains unexpected values.
     */
    public function setModifiers($modifiers)
    {
        $expected = ~State::IS_PUBLIC
                  & ~State::IS_PROTECTED
                  & ~State::IS_PRIVATE
                  & ~State::IS_STATIC;

        if (($expected & $modifiers) !== 0) {
            throw new \InvalidArgumentException(
                'Invalid field modifiers given, allowed modifiers are ' .
                'IS_PUBLIC, IS_PROTECTED, IS_PRIVATE and IS_STATIC.'
            );
        }

        $this->setMetadataInteger(5, $modifiers);
    }

    /**
     * Returns <b>true</b> if this node is marked as public, otherwise the
     * returned value will be <b>false</b>.
     *
     * @return boolean
     */
    public function isPublic()
    {
        return (($this->getModifiers() & State::IS_PUBLIC) === State::IS_PUBLIC);
    }

    /**
     * Returns <b>true</b> if this node is marked as protected, otherwise the
     * returned value will be <b>false</b>.
     *
     * @return boolean
     */
    public function isProtected()
    {
        return (($this->getModifiers() & State::IS_PROTECTED) === State::IS_PROTECTED);
    }

    /**
     * Returns <b>true</b> if this node is marked as private, otherwise the
     * returned value will be <b>false</b>.
     *
     * @return boolean
     */
    public function isPrivate()
    {
        return (($this->getModifiers() & State::IS_PRIVATE) === State::IS_PRIVATE);
    }

    /**
     * Returns <b>true</b> when this node is declared as static, otherwise
     * the returned value will be <b>false</b>.
     *
     * @return boolean
     */
    public function isStatic()
    {
        return (($this->getModifiers() & State::IS_STATIC) === State::IS_STATIC);
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitFieldDeclaration($this, $data);
    }

    /**
     * Returns the total number of the used property bag.
     *
     * @return integer
     * @since  0.10.4
     * @see    \PDepend\Source\AST\ASTNode#getMetadataSize()
     */
    protected function getMetadataSize()
    {
        return 6;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This class represents a single constant declarator within a constant
 * definition.
 *
 * <code>
 * class Foo
 * {
 *     //    --------
 *     const BAR = 42;
 *     //    --------
 * }
 * </code>
 *
 * Or in a comma separated constant defintion:
 *
 * <code>
 * class Foo
 * {
 *     //    --------
 *     const BAR = 42,
 *     //    --------
 *
 *     //    --------------
 *     const BAZ = 'Foobar',
 *     //    --------------
 *
 *     //    ----------
 *     const FOO = 3.14;
 *     //    ----------
 * }
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTConstantDeclarator extends AbstractASTNode
{
    /**
     * The initial declaration value for this node or <b>null</b>.
     *
     * @var \PDepend\Source\AST\ASTValue
     */
    protected $value = null;

    /**
     * Returns the initial declaration value for this node.
     *
     * @return \PDepend\Source\AST\ASTValue
     */
    public function getValue()
    {
        return $this->value;
    }

    /**
     * Sets the declared default value for this constant node.
     *
     * @param  \PDepend\Source\AST\ASTValue $value
     * @return void
     */
    public function setValue(ASTValue $value)
    {
        $this->value = $value;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return mixed
     * @since  0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitConstantDeclarator($this, $data);
    }

    /**
     * Magic sleep method that returns an array with those property names that
     * should be cached for this node instance.
     *
     * @return array(string)
     */
    public function __sleep()
    {
        return array_merge(array('value'), parent::__sleep());
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This node class represents a boolean or-expression.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */
class ASTBooleanOrExpression extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return mixed
     * @since 0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitBooleanOrExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */

namespace PDepend\Source\AST;

/**
 * This type of exception will be thrown when the source file of a code object
 * is accessed, but this property is not available.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */
class ASTCompilationUnitNotFoundException extends \RuntimeException
{
    /**
     * Constructs a new exception instance.
     *
     * @param \PDepend\Source\AST\AbstractASTArtifact $owner
     */
    public function __construct(AbstractASTArtifact $owner)
    {
        parent::__construct('The mandatory parent was not defined.');
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

/**
 * Holds constants with internal state constants
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface State
{
    /**
     * Marks a class or interface as implicit abstract.
     */
    const IS_IMPLICIT_ABSTRACT = \ReflectionClass::IS_IMPLICIT_ABSTRACT;

    /**
     * Marks a class or interface as explicit abstract.
     */
    const IS_EXPLICIT_ABSTRACT = \ReflectionClass::IS_EXPLICIT_ABSTRACT;

    /**
     * Marks a node as public.
     */
    const IS_PUBLIC = \ReflectionMethod::IS_PUBLIC;

    /**
     * Marks a node as protected.
     */
    const IS_PROTECTED = \ReflectionMethod::IS_PROTECTED;

    /**
     * Marks a node as private.
     */
    const IS_PRIVATE = \ReflectionMethod::IS_PRIVATE;

    /**
     * Marks a node as abstract.
     */
    const IS_ABSTRACT = \ReflectionMethod::IS_ABSTRACT;

    /**
     * Marks a node as final.
     */
    const IS_FINAL = \ReflectionMethod::IS_FINAL;

    /**
     * Marks a node as static.
     */
    const IS_STATIC = \ReflectionMethod::IS_STATIC;
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

/**
 * This class represents a variable node.
 *
 * <code>
 * //   ----
 * Foo::$bar();
 * //   ----
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTVariable extends ASTExpression
{
    /**
     * This method will return <b>true</b> when this variable instance represents
     * the <b>$this</b> scope of a class instance.
     *
     * @return boolean
     * @since  0.10.0
     */
    public function isThis()
    {
        return ($this->getImage() === '$this');
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitVariable($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a logical <b>xor</b>-expression.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */
class ASTLogicalXorExpression extends ASTExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitLogicalXorExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a continue-statement.
 *
 * <code>
 * ---------
 * continue;
 * ---------
 *
 * ------------
 * continue 42;
 * ------------
 *
 * -------------------------
 * continue $this->foobar();
 * -------------------------
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTContinueStatement extends \PDepend\Source\AST\ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitContinueStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a list-expression.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTListExpression extends ASTExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitListExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This node class represents a trait adaptation precedence.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */
class ASTTraitAdaptationPrecedence extends ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param  mixed                                 $data
     * @return mixed
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitTraitAdaptationPrecedence($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.15
 */

namespace PDepend\Source\AST;

/**
 * This class represents a cast-expression node.
 *
 * <code>
 * //     ----------
 * $foo = (int) $bar;
 * //     ----------
 *
 * //     -----------
 * $foo = (bool) $bar;
 * //     -----------
 *
 * //     ------------
 * $foo = (array) $bar;
 * //     ------------
 *
 * //     ------------
 * $foo = (unset) $bar;
 * //     ------------
 *
 * //     -------------
 * $foo = (double) $bar;
 * //     -------------
 *
 * //     -------------
 * $foo = (string) $bar;
 * //     -------------
 *
 * //     -------------
 * $foo = (object) $bar;
 * //     -------------
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.15
 */
class ASTCastExpression extends \PDepend\Source\AST\ASTUnaryExpression
{
    /**
     * Constructs a new cast-expression node.
     *
     * @param string $image The original cast image.
     */
    public function __construct($image)
    {
        parent::__construct(preg_replace('(\s+)', '', strtolower($image)));
    }

    /**
     * Returns <b>true</b> when this node represents an array cast-expression.
     *
     * @return boolean
     */
    public function isArray()
    {
        return ($this->getImage() === '(array)');
    }

    /**
     * Returns <b>true</b> when this node represents an object cast-expression.
     *
     * @return boolean
     */
    public function isObject()
    {
        return ($this->getImage() === '(object)');
    }

    /**
     * Returns <b>true</b> when this node represents a boolean cast-expression.
     *
     * @return boolean
     */
    public function isBoolean()
    {
        return ($this->getImage() === '(bool)' || $this->getImage() === '(boolean)');
    }

    /**
     * Returns <b>true</b> when this node represents an integer cast-expression.
     *
     * @return boolean
     */
    public function isInteger()
    {
        return ($this->getImage() === '(int)' || $this->getImage() === '(integer)');
    }

    /**
     * Returns <b>true</b> when this node represents a float cast-expression.
     *
     * @return boolean
     */
    public function isFloat()
    {
        return ($this->getImage() === '(real)'
            || $this->getImage() === '(float)'
            || $this->getImage() === '(double)'
        );
    }

    /**
     * Returns <b>true</b> when this node represents a string cast-expression.
     *
     * @return boolean
     */
    public function isString()
    {
        return (strcmp('(string)', $this->getImage()) === 0);
    }

    /**
     * Returns <b>true</b> when this node represents an unset cast-expression.
     *
     * @return boolean
     */
    public function isUnset()
    {
        return ($this->getImage() === '(unset)');
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitCastExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */

namespace PDepend\Source\AST;

/**
 * This class represents a single array element expression.
 *
 * <code>
 * //              _  ______  __________________________
 * //                                __  ___  __________
 * $array = array( 1, 2 => 3, array( $a, &$b, 1 => &$c ) );
 *
 * //         _  ______  _____________________
 * //                      __  ___  ________
 * $array = [ 1, 2 => 3, [ $a, &$b, 1 => &$c ] ];
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */
class ASTArrayElement extends \PDepend\Source\AST\ASTExpression
{
    /**
     * This method will return <b>true</b> when the element value is passed by
     * reference.
     *
     * @return boolean
     */
    public function isByReference()
    {
        return $this->getMetadataBoolean(5);
    }

    /**
     * This method can be used to mark the element value as passed by reference.
     *
     * @return void
     */
    public function setByReference()
    {
        return $this->setMetadataBoolean(5, true);
    }

    /**
     * Returns the total number of the used property bag.
     *
     * @return integer
     * @since  0.10.4
     * @see    \PDepend\Source\AST\ASTNode#getMetadataSize()
     */
    protected function getMetadataSize()
    {
        return 6;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitArrayElement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.3
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * Represents a php class node.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.3
 */
class ASTAnonymousClass extends ASTClass implements ASTNode
{
    /**
     * The parent node of this node or <b>null</b> when this node is the root
     * of a node tree.
     *
     * @var \PDepend\Source\AST\ASTNode
     */
    protected $parent = null;

    /**
     * Metadata for this node instance, serialized in a string. This string
     * contains the start, end line, and the start, end column and the node
     * image in a colon separated string.
     *
     * @var string
     * @since 0.10.4
     */
    protected $metadata = ':::';

    /**
     * @param string $image
     * @return void
     */
    public function setImage($image)
    {
        $this->setName($image);
    }

    /**
     * Returns the source image of this ast node.
     *
     * @return string
     */
    public function getImage()
    {
        return $this->getName();
    }

    /**
     * Returns the start line for this ast node.
     *
     * @return integer
     */
    public function getStartLine()
    {
        return $this->getMetadataInteger(0);
    }

    /**
     * Returns the start column for this ast node.
     *
     * @return integer
     */
    public function getStartColumn()
    {
        return $this->getMetadataInteger(2);
    }

    /**
     * Returns the end line for this ast node.
     *
     * @return integer
     */
    public function getEndLine()
    {
        return $this->getMetadataInteger(1);
    }

    /**
     * Returns the end column for this ast node.
     *
     * @return integer
     */
    public function getEndColumn()
    {
        return $this->getMetadataInteger(3);
    }

    /**
     * For better performance we have moved the single setter methods for the
     * node columns and lines into this configure method.
     *
     * @param integer $startLine
     * @param integer $endLine
     * @param integer $startColumn
     * @param integer $endColumn
     * @return void
     * @since 0.9.10
     */
    public function configureLinesAndColumns($startLine, $endLine, $startColumn, $endColumn)
    {
        $this->setMetadataInteger(0, $startLine);
        $this->setMetadataInteger(1, $endLine);
        $this->setMetadataInteger(2, $startColumn);
        $this->setMetadataInteger(3, $endColumn);
    }

    /**
     * Returns the parent node of this node or <b>null</b> when this node is
     * the root of a node tree.
     *
     * @return \PDepend\Source\AST\ASTNode
     */
    public function getParent()
    {
        return $this->parent;
    }

    /**
     * Sets the parent node of this node.
     *
     * @param \PDepend\Source\AST\ASTNode $node
     * @return void
     */
    public function setParent(ASTNode $node)
    {
        $this->parent = $node;
    }

    /**
     * Traverses up the node tree and finds all parent nodes that are instances
     * of <b>$parentType</b>.
     *
     * @param string $parentType
     * @return \PDepend\Source\AST\ASTNode[]
     */
    public function getParentsOfType($parentType)
    {
        $parents = array();

        $parentNode = $this->parent;
        while (is_object($parentNode)) {
            if ($parentNode instanceof $parentType) {
                array_unshift($parents, $parentNode);
            }
            $parentNode = $parentNode->getParent();
        }
        return $parents;
    }

    /**
     * This method adds a new child node at the first position of the children.
     *
     * @param \PDepend\Source\AST\ASTNode $node
     * @return void
     */
    public function prependChild(ASTNode $node)
    {
        array_unshift($this->nodes, $node);
        $node->setParent($this);
    }

    /**
     * Will return <b>true</b> if this class was declared anonymous in an
     * allocation expression.
     *
     * @return boolean
     */
    public function isAnonymous()
    {
        return true;
    }

    /**
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return void
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitAnonymousClass($this, $data);
    }

    /**
     * The magic sleep method will be called by PHP's runtime environment right
     * before an instance of this class gets serialized. It should return an
     * array with those property names that should be serialized for this class.
     *
     * @return array
     * @since 0.10.0
     */
    public function __sleep()
    {
        return array_merge(array('metadata'), parent::__sleep());
    }

    /**
     * The magic wakeup method will be called by PHP's runtime environment when
     * a serialized instance of this class was unserialized. This implementation
     * of the wakeup method will register this object in the the global class
     * context.
     *
     * @return void
     */
    public function __wakeup()
    {
        $this->methods = null;

        foreach ($this->nodes as $node) {
            $node->setParent($this);
        }

        parent::__wakeup();

    }

    /**
     * Returns an integer value that was stored under the given index.
     *
     * @param integer $index
     * @return integer
     * @since 0.10.4
     */
    protected function getMetadataInteger($index)
    {
        return (int) $this->getMetadata($index);
    }

    /**
     * Stores an integer value under the given index in the internally used data
     * string.
     *
     * @param integer $index
     * @param integer $value
     * @return void
     * @since 0.10.4
     */
    protected function setMetadataInteger($index, $value)
    {
        $this->setMetadata($index, $value);
    }

    /**
     * Returns the value that was stored under the given index.
     *
     * @param integer $index
     * @return mixed
     * @since 0.10.4
     */
    protected function getMetadata($index)
    {
        $metadata = explode(':', $this->metadata, $this->getMetadataSize());
        return $metadata[$index];
    }

    /**
     * Stores the given value under the given index in an internal storage
     * container.
     *
     * @param integer $index
     * @param mixed $value
     * @return void
     * @since 0.10.4
     */
    protected function setMetadata($index, $value)
    {
        $metadata         = explode(':', $this->metadata, $this->getMetadataSize());
        $metadata[$index] = $value;

        $this->metadata = join(':', $metadata);
    }

    /**
     * Returns the total number of the used property bag.
     *
     * @return integer
     * @since 0.10.4
     */
    protected function getMetadataSize()
    {
        return 4;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a switch-label.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */
class ASTSwitchLabel extends AbstractASTNode
{
    /**
     * Is this switch label the default label?
     *
     * @var boolean
     */
    protected $default = false;

    /**
     * Returns <b>true</b> when this node is the default label.
     *
     * @return boolean
     */
    public function isDefault()
    {
        return $this->default;
    }

    /**
     * Flags this node instance as the default switch label.
     *
     * @return void
     */
    public function setDefault()
    {
        $this->default = true;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitSwitchLabel($this, $data);
    }

    /**
     * The magic sleep method will be called by PHP's runtime environment right
     * before an instance of this class gets serialized. It should return an
     * array with those property names that should be serialized for this class.
     *
     * @return array(string)
     * @since  0.10.0
     */
    public function __sleep()
    {
        return array_merge(array('default'), parent::__sleep());
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a logical <b>or</b>-expression.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */
class ASTLogicalOrExpression extends ASTExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitLogicalOrExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.5
 */

namespace PDepend\Source\AST;

/**
 * This class encapsulates possible default values for functions, methods,
 * parameters and properties. We use a separate class because otherwise you
 * cannot differentiate between no default value and a scalar <b>null</b>.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.5
 */
class ASTValue
{
    /**
     * Boolean flag that is <b>true</b> when a PHP-value was set.
     *
     * @var boolean
     */
    private $valueAvailable = false;

    /**
     * The parsed PHP-value,
     *
     * @var mixed
     */
    private $value = null;

    /**
     * This method will return the parsed PHP value.
     *
     * @return mixed
     */
    public function getValue()
    {
        return $this->value;
    }

    /**
     * This method will set the parsed PHP-value. Please note that this method
     * acts as a one-way-function, only the first call with set the value all
     * following calls will be ignored.
     *
     * @param mixed $value The parsed PHP-value.
     *
     * @return void
     */
    public function setValue($value)
    {
        if ($this->valueAvailable === false) {
            $this->value          = $value;
            $this->valueAvailable = true;
        }
    }

    /**
     * This method will return <b>true</b> when the PHP-value is already set.
     *
     * @return boolean
     */
    public function isValueAvailable()
    {
        return $this->valueAvailable;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.11
 */

namespace PDepend\Source\AST;

/**
 * This class represents an unary expression node.
 *
 * <code>
 * //   -
 *      -$foo
 * //   -
 *
 * //   -
 *      +$foo
 * //   -
 *
 * //   -
 *      &$foo
 * //   -
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.11
 */
class ASTUnaryExpression extends ASTExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitUnaryExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This class represents a return statement node.
 *
 * <code>
 * //   -------
 *      return;
 * //   -------
 *
 * //   ----------
 *      return 42;
 * //   ----------
 *
 * //   ---------------------------------------------
 *      return $this->createValue($this->getValue());
 * //   ---------------------------------------------
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTReturnStatement extends ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitReturnStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

use PDepend\Source\AST\ASTArtifactList\CollectionArtifactFilter;

/**
 * Represents an interface or a class type.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
abstract class AbstractASTClassOrInterface extends AbstractASTType
{
    /**
     * The parent for this class node.
     *
     * @var   \PDepend\Source\AST\ASTClassReference
     * @since 0.9.5
     */
    protected $parentClassReference = null;

    /**
     * List of all interfaces implemented/extended by the this type.
     *
     * @var \PDepend\Source\AST\ASTClassOrInterfaceReference[]
     */
    protected $interfaceReferences = array();

    /**
     * An <b>array</b> with all constants defined in this class or interface.
     *
     * @var array(string=>mixed)
     */
    protected $constants = null;

    /**
     * Returns the parent class or <b>null</b> if this class has no parent.
     *
     * @return \PDepend\Source\AST\ASTClass
     * @throws \PDepend\Source\AST\ASTClassOrInterfaceRecursiveInheritanceException
     */
    public function getParentClass()
    {
        // No parent? Stop here!
        if ($this->parentClassReference === null) {
            return null;
        }

        $parentClass = $this->parentClassReference->getType();

        if ($parentClass === $this) {
            throw new ASTClassOrInterfaceRecursiveInheritanceException($this);
        }

        // Check parent against global filter
        $collection = CollectionArtifactFilter::getInstance();
        if ($collection->accept($parentClass) === false) {
            return null;
        }

        return $parentClass;
    }

    /**
     * Returns an array with all parents for the current class.
     *
     * The returned array contains class instances for each parent of this class.
     * They are ordered in the reverse inheritance order. This means that the
     * direct parent of this class is the first element in the returned array
     * and parent of this parent the second element and so on.
     *
     * @return \PDepend\Source\AST\ASTClass[]
     * @throws \PDepend\Source\AST\ASTClassOrInterfaceRecursiveInheritanceException
     * @since  1.0.0
     */
    public function getParentClasses()
    {
        $parents = array();
        $parent  = $this;
        while (is_object($parent = $parent->getParentClass())) {
            if (in_array($parent, $parents, true)) {
                throw new ASTClassOrInterfaceRecursiveInheritanceException($parent);
            }
            $parents[] = $parent;
        }
        return $parents;
    }

    /**
     * Returns a reference onto the parent class of this class node or <b>null</b>.
     *
     * @return \PDepend\Source\AST\ASTClassReference
     * @since  0.9.5
     */
    public function getParentClassReference()
    {
        return $this->parentClassReference;
    }

    /**
     * Sets a reference onto the parent class of this class node.
     *
     * @param \PDepend\Source\AST\ASTClassReference $classReference Reference to the
     *        declared parent class.
     *
     * @return void
     * @since  0.9.5
     */
    public function setParentClassReference(ASTClassReference $classReference)
    {
        $this->nodes[]              = $classReference;
        $this->parentClassReference = $classReference;
    }

    /**
     * Returns a node iterator with all implemented interfaces.
     *
     * @return \PDepend\Source\AST\ASTInterface[]
     * @since  0.9.5
     */
    public function getInterfaces()
    {
        $stack = $this->getParentClasses();
        array_unshift($stack, $this);

        $interfaces = array();

        while (($top = array_pop($stack)) !== null) {
            foreach ($top->interfaceReferences as $interfaceReference) {
                $interface = $interfaceReference->getType();
                if (in_array($interface, $interfaces, true) === true) {
                    continue;
                }
                $interfaces[] = $interface;
                $stack[] = $interface;
            }
        }

        return new ASTArtifactList($interfaces);
    }

    /**
     * Returns an array of references onto the interfaces of this class node.
     *
     * @return array
     * @since  0.10.4
     */
    public function getInterfaceReferences()
    {
        return $this->interfaceReferences;
    }

    /**
     * Adds a interface reference node.
     *
     * @param  \PDepend\Source\AST\ASTClassOrInterfaceReference $interfaceReference
     * @return void
     * @since  0.9.5
     */
    public function addInterfaceReference(ASTClassOrInterfaceReference $interfaceReference)
    {
        $this->nodes[] = $interfaceReference;
        $this->interfaceReferences[] = $interfaceReference;
    }

    /**
     * Returns an <b>array</b> with all constants defined in this class or
     * interface.
     *
     * @return array(string=>mixed)
     */
    public function getConstants()
    {
        if ($this->constants === null) {
            $this->initConstants();
        }
        return $this->constants;
    }

    /**
     * This method returns <b>true</b> when a constant for <b>$name</b> exists,
     * otherwise it returns <b>false</b>.
     *
     * @param string $name Name of the searched constant.
     *
     * @return boolean
     * @since  0.9.6
     */
    public function hasConstant($name)
    {
        if ($this->constants === null) {
            $this->initConstants();
        }
        return array_key_exists($name, $this->constants);
    }

    /**
     * This method will return the value of a constant for <b>$name</b> or it
     * will return <b>false</b> when no constant for that name exists.
     *
     * @param string $name Name of the searched constant.
     *
     * @return mixed
     * @since  0.9.6
     */
    public function getConstant($name)
    {
        if ($this->hasConstant($name) === true) {
            return $this->constants[$name];
        }
        return false;
    }

    /**
     * Returns a list of all methods provided by this type or one of its parents.
     *
     * @return \PDepend\Source\AST\ASTMethod[]
     * @since  0.9.10
     */
    public function getAllMethods()
    {
        $methods = array();
        foreach ($this->getInterfaces() as $interface) {
            foreach ($interface->getAllMethods() as $method) {
                $methods[strtolower($method->getName())] = $method;
            }
        }

        if (is_object($parentClass = $this->getParentClass())) {
            foreach ($parentClass->getAllMethods() as $methodName => $method) {
                $methods[$methodName] = $method;
            }
        }

        foreach ($this->getTraitMethods() as $method) {
            $methods[strtolower($method->getName())] = $method;
        }

        foreach ($this->getMethods() as $method) {
            $methods[strtolower($method->getName())] = $method;
        }

        return $methods;
    }

    /**
     * Returns all {@link \PDepend\Source\AST\AbstractASTClassOrInterface}
     * objects this type depends on.
     *
     * @return \PDepend\Source\AST\AbstractASTClassOrInterface[]
     */
    public function getDependencies()
    {
        $references = $this->interfaceReferences;
        if ($this->parentClassReference !== null) {
            $references[] = $this->parentClassReference;
        }

        return new ASTClassOrInterfaceReferenceIterator($references);
    }

    /**
     * Returns <b>true</b> if this is an abstract class or an interface.
     *
     * @return boolean
     */
    abstract public function isAbstract();

    /**
     * Returns the declared modifiers for this type.
     *
     * @return integer
     */
    abstract public function getModifiers();

    /**
     * This method initializes the constants defined in this class or interface.
     *
     * @return void
     * @since  0.9.6
     */
    private function initConstants()
    {
        $this->constants = array();
        if (($parentClass = $this->getParentClass()) !== null) {
            $this->constants = $parentClass->getConstants();
        }

        foreach ($this->getInterfaces() as $interface) {
            $this->constants = array_merge(
                $this->constants,
                $interface->getConstants()
            );
        }

        $definitions = $this->findChildrenOfType('PDepend\\Source\\AST\\ASTConstantDefinition');

        foreach ($definitions as $definition) {
            $declarators = $definition->findChildrenOfType('PDepend\\Source\\AST\\ASTConstantDeclarator');

            foreach ($declarators as $declarator) {
                $image = $declarator->getImage();
                $value = $declarator->getValue()->getValue();

                $this->constants[$image] = $value;
            }
        }
    }

    /**
     * The magic sleep method is called by the PHP runtime environment before an
     * instance of this class gets serialized. It returns an array with the
     * names of all those properties that should be cached for this class or
     * interface instance.
     *
     * @return array
     * @since  0.10.0
     */
    public function __sleep()
    {
        return array_merge(
            array('constants', 'interfaceReferences', 'parentClassReference'),
            parent::__sleep()
        );
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a for-statement.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */
class ASTForStatement extends ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitForStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This node class represents a pre-decrement-expression.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */
class ASTPreDecrementExpression extends ASTUnaryExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param  mixed                                 $data
     * @return mixed
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitPreDecrementExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a static variable declaration.
 *
 * <code>
 * function foo()
 * {
 *     // First declaration
 *     static $foo;
 *     // Second declaration
 *     static $bar = array();
 *     // Third declaration
 *     static $baz    = array(),
 *            $foobar = null,
 *            $barbaz;
 * }
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTStaticVariableDeclaration extends ASTExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitStaticVariableDeclaration($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This node class represents a boolean and-expression.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */
class ASTBooleanAndExpression extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return mixed
     * @since 0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitBooleanAndExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a <b>include</b>- or <b>include_once</b>-expression.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTIncludeExpression extends ASTExpression
{
    /**
     * Does this node represent a <b>include_once</b>-expression?
     *
     * @var boolean
     */
    protected $once = false;

    /**
     * Does this node represent a <b>include_once</b>-expression?
     *
     * @return boolean
     */
    public function isOnce()
    {
        return $this->once;
    }

    /**
     * Flags this node as a <b>include_once</b>-expression.
     *
     * @return void
     */
    public function setOnce()
    {
        $this->once = true;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitIncludeExpression($this, $data);
    }

    /**
     * The magic sleep method will be called by PHP's runtime environment right
     * before an instance of this class gets serialized. It should return an
     * array with those property names that should be serialized for this class.
     *
     * @return array(string)
     * @since  0.10.0
     */
    public function __sleep()
    {
        return array_merge(array('once'), parent::__sleep());
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This node class represents a postfix-expression.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */
class ASTPostfixExpression extends ASTExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param  mixed                                 $data
     * @return mixed
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitPostfixExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This node class represents an isste-expression/function.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTIssetExpression extends ASTExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return mixed
     * @since 0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitIssetExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

/**
 * A static identifier as it can be used to access a function, method, constant
 * or property.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTIdentifier extends ASTExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitIdentifier($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This is an abstract base class for index nodes.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
abstract class ASTIndexExpression extends ASTExpression
{
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

/**
 * This is a special reference container that is used whenever the keyword
 * <b>static</b> is used to reference a class or interface.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTStaticReference extends ASTSelfReference
{
    /**
     * The source image of this node.
     */
    const IMAGE = 'static';

    /**
     * Returns the visual representation for this node type.
     *
     * @return string
     * @since  0.10.4
     */
    public function getImage()
    {
        return self::IMAGE;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitStaticReference($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * Representation of a trait.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */
class ASTTrait extends ASTClass
{
    /**
     * Returns all properties for this class.
     *
     * @return \PDepend\Source\AST\ASTProperty[]
     * @since  1.0.6
     * @todo   Return properties declared by a trait.
     */
    public function getProperties()
    {
        return array();
    }

    /**
     * Returns an array with {@link \PDepend\Source\AST\ASTMethod} objects
     * that are implemented or imported by this trait.
     *
     * @return \PDepend\Source\AST\ASTMethod[]
     */
    public function getAllMethods()
    {
        $methods = $this->getTraitMethods();

        foreach ($this->getMethods() as $method) {
            $methods[strtolower($method->getName())] = $method;
        }

        return $methods;
    }

    /**
     * Checks that this user type is a subtype of the given <b>$type</b> instance.
     *
     * @param  \PDepend\Source\AST\AbstractASTType $type
     * @return boolean
     * @todo   Should we handle trait subtypes?
     */
    public function isSubtypeOf(AbstractASTType $type)
    {
        return false;
    }

    /**
     * ASTVisitor method for node tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @return void
     */
    public function accept(ASTVisitor $visitor)
    {
        $visitor->visitTrait($this);
    }

    /**
     * The magic wakeup method will be called by PHP's runtime environment when
     * a serialized instance of this class was unserialized. This implementation
     * of the wakeup method will register this object in the the global class
     * context.
     *
     * @return void
     */
    public function __wakeup()
    {
        parent::__wakeup();

        $this->context->registerTrait($this);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a goto-statement.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTGotoStatement extends ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitGotoStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

/**
 * This is an abstract base implementation of the ast node interface.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
abstract class AbstractASTNode implements ASTNode
{
    /**
     * Parsed child nodes of this node.
     *
     * @var \PDepend\Source\AST\ASTNode[]
     */
    protected $nodes = array();

    /**
     * The parent node of this node or <b>null</b> when this node is the root
     * of a node tree.
     *
     * @var \PDepend\Source\AST\ASTNode
     */
    protected $parent = null;

    /**
     * An optional doc comment for this node.
     *
     * @var string
     */
    protected $comment = null;

    /**
     * Metadata for this node instance, serialized in a string. This string
     * contains the start, end line, and the start, end column and the node
     * image in a colon seperated string.
     *
     * @var string
     * @since 0.10.4
     */
    protected $metadata = '::::';

    /**
     * Constructs a new ast node instance.
     *
     * @param string $image The source image for this node.
     */
    public function __construct($image = null)
    {
        $this->metadata = str_repeat(':', $this->getMetadataSize() - 1);

        $this->setImage($image);
    }

    /**
     * Sets the image for this ast node.
     *
     * @param string $image
     * @return void
     */
    public function setImage($image)
    {
        $this->setMetadata(4, $image);
    }

    /**
     * Returns the source image of this ast node.
     *
     * @return string
     */
    public function getImage()
    {
        return $this->getMetadata(4);
    }

    /**
     * Returns the start line for this ast node.
     *
     * @return integer
     */
    public function getStartLine()
    {
        return $this->getMetadataInteger(0);
    }

    /**
     * Returns the start column for this ast node.
     *
     * @return integer
     */
    public function getStartColumn()
    {
        return $this->getMetadataInteger(2);
    }

    /**
     * Returns the end line for this ast node.
     *
     * @return integer
     */
    public function getEndLine()
    {
        return $this->getMetadataInteger(1);
    }

    /**
     * Returns the end column for this ast node.
     *
     * @return integer
     */
    public function getEndColumn()
    {
        return $this->getMetadataInteger(3);
    }

    /**
     * For better performance we have moved the single setter methods for the
     * node columns and lines into this configure method.
     *
     * @param integer $startLine
     * @param integer $endLine
     * @param integer $startColumn
     * @param integer $endColumn
     * @return void
     * @since 0.9.10
     */
    public function configureLinesAndColumns(
        $startLine,
        $endLine,
        $startColumn,
        $endColumn
    ) {
        $this->setMetadataInteger(0, $startLine);
        $this->setMetadataInteger(1, $endLine);
        $this->setMetadataInteger(2, $startColumn);
        $this->setMetadataInteger(3, $endColumn);
    }

    /**
     * Returns an integer value that was stored under the given index.
     *
     * @param integer $index
     * @return integer
     * @since 0.10.4
     */
    protected function getMetadataInteger($index)
    {
        return (int) $this->getMetadata($index);
    }

    /**
     * Stores an integer value under the given index in the internally used data
     * string.
     *
     * @param integer $index
     * @param integer $value
     * @return void
     * @since 0.10.4
     */
    protected function setMetadataInteger($index, $value)
    {
        $this->setMetadata($index, $value);
    }

    /**
     * Returns a boolean value that was stored under the given index.
     *
     * @param integer $index
     * @return boolean
     * @since 0.10.4
     */
    protected function getMetadataBoolean($index)
    {
        return (bool) $this->getMetadata($index);
    }

    /**
     * Stores a boolean value under the given index in the internally used data
     * string.
     *
     * @param integer $index
     * @param boolean $value
     * @return void
     * @since 0.10.4
     */
    protected function setMetadataBoolean($index, $value)
    {
        $this->setMetadata($index, $value ? 1 : 0);
    }

    /**
     * Returns the value that was stored under the given index.
     *
     * @param integer $index
     * @return mixed
     * @since 0.10.4
     */
    protected function getMetadata($index)
    {
        $metadata = explode(':', $this->metadata, $this->getMetadataSize());
        return $metadata[$index];
    }

    /**
     * Stores the given value under the given index in an internal storage
     * container.
     *
     * @param integer $index
     * @param mixed $value
     * @return void
     * @since 0.10.4
     */
    protected function setMetadata($index, $value)
    {
        $metadata         = explode(':', $this->metadata, $this->getMetadataSize());
        $metadata[$index] = $value;

        $this->metadata = join(':', $metadata);
    }

    /**
     * Returns the total number of the used property bag.
     *
     * @return integer
     * @since 0.10.4
     */
    protected function getMetadataSize()
    {
        return 5;
    }

    /**
     * Returns the node instance for the given index or throws an exception.
     *
     * @param integer $index
     * @return \PDepend\Source\AST\ASTNode
     * @throws \OutOfBoundsException When no node exists at the given index.
     */
    public function getChild($index)
    {
        if (isset($this->nodes[$index])) {
            return $this->nodes[$index];
        }
        throw new \OutOfBoundsException(
            sprintf(
                'No node found at index %d in node of type: %s',
                $index,
                get_class($this)
            )
        );
    }

    /**
     * This method returns all direct children of the actual node.
     *
     * @return \PDepend\Source\AST\ASTNode[]
     */
    public function getChildren()
    {
        return $this->nodes;
    }

    /**
     * This method will search recursive for the first child node that is an
     * instance of the given <b>$targetType</b>. The returned value will be
     * <b>null</b> if no child exists for that.
     *
     * @param string $targetType
     * @return \PDepend\Source\AST\ASTNode
     */
    public function getFirstChildOfType($targetType)
    {
        foreach ($this->nodes as $node) {
            if ($node instanceof $targetType) {
                return $node;
            }
            if (($child = $node->getFirstChildOfType($targetType)) !== null) {
                return $child;
            }
        }
        return null;
    }

    /**
     * This method will search recursive for all child nodes that are an
     * instance of the given <b>$targetType</b>. The returned value will be
     * an empty <b>array</b> if no child exists for that.
     *
     * @param string $targetType Searched class or interface type.
     * @param array  &$results   Already found node instances. This parameter
     *        is only for internal usage.
     * @return \PDepend\Source\AST\ASTNode[]
     */
    public function findChildrenOfType($targetType, array &$results = array())
    {
        foreach ($this->nodes as $node) {
            if ($node instanceof $targetType) {
                $results[] = $node;
            }
            $node->findChildrenOfType($targetType, $results);
        }
        return $results;
    }

    /**
     * This method adds a new child node at the first position of the children.
     *
     * @param \PDepend\Source\AST\ASTNode $node
     * @return void
     */
    public function prependChild(ASTNode $node)
    {
        array_unshift($this->nodes, $node);
        $node->setParent($this);
    }

    /**
     * This method adds a new child node to this node instance.
     *
     * @param \PDepend\Source\AST\ASTNode $node
     * @return void
     */
    public function addChild(ASTNode $node)
    {
        $this->nodes[] = $node;
        $node->setParent($this);
    }

    /**
     * Returns the parent node of this node or <b>null</b> when this node is
     * the root of a node tree.
     *
     * @return \PDepend\Source\AST\ASTNode
     */
    public function getParent()
    {
        return $this->parent;
    }

    /**
     * Traverses up the node tree and finds all parent nodes that are instances
     * of <b>$parentType</b>.
     *
     * @param string $parentType
     * @return \PDepend\Source\AST\ASTNode[]
     */
    public function getParentsOfType($parentType)
    {
        $parents = array();

        $parentNode = $this->parent;
        while (is_object($parentNode)) {
            if ($parentNode instanceof $parentType) {
                array_unshift($parents, $parentNode);
            }
            $parentNode = $parentNode->getParent();
        }
        return $parents;
    }

    /**
     * Sets the parent node of this node.
     *
     * @param \PDepend\Source\AST\ASTNode $node
     * @return void
     */
    public function setParent(ASTNode $node)
    {
        $this->parent = $node;
    }

    /**
     * Returns a doc comment for this node or <b>null</b> when no comment was
     * found.
     *
     * @return string
     */
    public function getComment()
    {
        return $this->comment;
    }

    /**
     * Sets the raw doc comment for this node.
     *
     * @param string $comment The doc comment block for this node.
     *
     * @return void
     */
    public function setComment($comment)
    {
        $this->comment = $comment;
    }

    /**
     * The magic sleep method will be called by PHP's runtime environment right
     * before an instance of this class gets serialized. It should return an
     * array with those property names that should be serialized for this class.
     *
     * @return array
     * @since 0.10.0
     */
    public function __sleep()
    {
        return array(
            'comment',
            'metadata',
            'nodes'
        );
    }

    /**
     * The magic wakeup method will be called by PHP's runtime environment when
     * a previously serialized object gets unserialized. This implementation of
     * the wakeup method restores the dependencies between an ast node and the
     * node's children.
     *
     * @return void
     * @since 0.10.0
     */
    public function __wakeup()
    {
        foreach ($this->nodes as $node) {
            $node->setParent($this);
        }
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

/**
 * This class represents a method postfix expression..
 *
 * <code>
 * //   ---------
 * Foo::bar($baz);
 * //   ---------
 *
 * //   ----------
 * Foo::$bar($baz);
 * //   ----------
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTMethodPostfix extends ASTInvocation
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitMethodPostfix($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a catch-statement.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTCatchStatement extends ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitCatchStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.5
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This is a classes only version of the class or interface reference .
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.5
 */
class ASTClassReference extends ASTClassOrInterfaceReference
{
    /**
     * Returns the concrete type instance associated with with this placeholder.
     *
     * @return \PDepend\Source\AST\AbstractASTClassOrInterface
     */
    public function getType()
    {
        if ($this->typeInstance === null) {
            $this->typeInstance = $this->context->getClass($this->getImage());
        }
        return $this->typeInstance;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param  mixed                                 $data
     * @return mixed
     * @since  0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitClassReference($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a declare-statement.
 *
 * <code>
 * -------------------------------
 * declare(encoding='ISO-8859-1');
 * -------------------------------
 *
 * -------------------
 * declare(ticks=42) {
 *     // ...
 * }
 * -
 *
 * ------------------
 * declare(ticks=42):
 *     // ...
 * enddeclare;
 * -----------
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.10.0
 */
class ASTDeclareStatement extends \PDepend\Source\AST\ASTStatement
{
    /**
     * The parsed declare values.
     *
     * @var \PDepend\Source\AST\ASTValue[]
     */
    protected $values = array();

    /**
     * Returns all values/parameters for this declare statement.
     *
     * @return \PDepend\Source\AST\ASTValue[]
     */
    public function getValues()
    {
        return $this->values;
    }

    /**
     * Adds a parameter/value for this declare-statement.
     *
     * @param string                       $name
     * @param \PDepend\Source\AST\ASTValue $value
     *
     * @return void
     */
    public function addValue($name, ASTValue $value)
    {
        $this->values[$name] = $value;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.10.0
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitDeclareStatement($this, $data);
    }

    /**
     * The magic sleep method will be called by PHP's runtime environment right
     * before an instance of this class gets serialized. It should return an
     * array with those property names that should be serialized for this class.
     *
     * @return array(string)
     * @since  0.10.0
     */
    public function __sleep()
    {
        return array_merge(array('values'), parent::__sleep());
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This class represents a constant postfix expression..
 *
 * <code>
 * //   ---
 * Foo::BAR;
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTConstantPostfix extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return mixed
     * @since 0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitConstantPostfix($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */

namespace PDepend\Source\AST;

/**
 * This class represents a callable type node.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */
class ASTTypeCallable extends ASTType
{
    /**
     * The visual image for this node type.
     */
    const IMAGE = 'callable';

    /**
     * @return string
     */
    public function getImage()
    {
        return self::IMAGE;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitTypeCallable($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a <b>require</b>- or <b>require_once</b>-expression.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTRequireExpression extends ASTExpression
{
    /**
     * Does this node represent a <b>require_once</b>-expression?
     *
     * @var boolean
     */
    protected $once = false;

    /**
     * Does this node represent a <b>require_once</b>-expression?
     *
     * @return boolean
     */
    public function isOnce()
    {
        return $this->once;
    }

    /**
     * Flags this node as a <b>require_once</b>-expression.
     *
     * @return void
     */
    public function setOnce()
    {
        $this->once = true;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitRequireExpression($this, $data);
    }

    /**
     * The magic sleep method will be called by PHP's runtime environment right
     * before an instance of this class gets serialized. It should return an
     * array with those property names that should be serialized for this class.
     *
     * @return array(string)
     * @since  0.10.0
     */
    public function __sleep()
    {
        return array_merge(array('once'), parent::__sleep());
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */

namespace PDepend\Source\AST;

/**
 * This node class encapsultes a shift right expression.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.1
 */
class ASTShiftRightExpression extends ASTExpression
{
    /**
     * The default image for this node.
     */
    const IMAGE = '>>';

    /**
     * Returns the source image of this ast node.
     *
     * @return string
     */
    public function getImage()
    {
        return self::IMAGE;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitShiftRightExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

/**
 * Abstract base class for code item.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
abstract class AbstractASTArtifact implements ASTArtifact
{
    /**
     * The name for this item.
     *
     * @var string
     */
    protected $name = '';

    /**
     * The unique identifier for this function.
     *
     * @var string
     */
    protected $id = null;

    /**
     * The line number where the item declaration starts.
     *
     * @var integer
     */
    protected $startLine = 0;

    /**
     * The line number where the item declaration ends.
     *
     * @var integer
     */
    protected $endLine = 0;

    /**
     * The source file for this item.
     *
     * @var \PDepend\Source\AST\ASTCompilationUnit
     */
    protected $compilationUnit = null;

    /**
     * The comment for this type.
     *
     * @var string
     */
    protected $comment = null;

    /**
     * Constructs a new item for the given <b>$name</b>.
     *
     * @param string $name The item name.
     */
    public function __construct($name)
    {
        $this->name = $name;
    }

    /**
     * Returns the source image of this ast node.
     *
     * @return string
     */
    public function getImage()
    {
        return $this->name;
    }

    /**
     * Returns the item name.
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Sets the item name.
     *
     * @param string $name The item name.
     *
     * @return void
     * @since  1.0.0
     */
    public function setName($name)
    {
        $this->name = $name;
    }



    /**
     * Returns a id for this code node.
     *
     * @return string
     */
    public function getId()
    {
        if ($this->id === null) {
            $this->id = md5(microtime());
        }
        return $this->id;
    }

    /**
     * Sets the unique identifier for this node instance.
     *
     * @param  string $id Identifier for this node.
     * @return void
     * @since  0.9.12
     */
    public function setId($id)
    {
        $this->id = $id;
    }

    /**
     * Returns the source file for this item.
     *
     * @return \PDepend\Source\AST\ASTCompilationUnit
     */
    public function getCompilationUnit()
    {
        return $this->compilationUnit;
    }

    /**
     * Sets the source file for this item.
     *
     * @param  \PDepend\Source\AST\ASTCompilationUnit $compilationUnit
     * @return void
     */
    public function setCompilationUnit(ASTCompilationUnit $compilationUnit)
    {
        if ($this->compilationUnit === null || $this->compilationUnit->getName() === null) {
            $this->compilationUnit = $compilationUnit;
        }
    }

    /**
     * Returns a doc comment for this node or <b>null</b> when no comment was
     * found.
     *
     * @return string
     */
    public function getComment()
    {
        return $this->comment;
    }

    /**
     * Sets the raw doc comment for this node.
     *
     * @param string $comment
     * @return void
     */
    public function setComment($comment)
    {
        $this->comment = $comment;
    }

    /**
     * Returns the line number where the class or interface declaration starts.
     *
     * @return integer
     */
    public function getStartLine()
    {
        return $this->startLine;
    }

    /**
     * Returns the line number where the class or interface declaration ends.
     *
     * @return integer
     */
    public function getEndLine()
    {
        return $this->endLine;
    }

    // BEGIN@deprecated

    /**
     * Returns the doc comment for this item or <b>null</b>.
     *
     * @return string
     * @deprecated Use getComment() inherit from ASTNode instead.
     */
    public function getDocComment()
    {
        return $this->getComment();
    }

    /**
     * Sets the doc comment for this item.
     *
     * @param string $docComment
     * @return void
     * @deprecated Use setComment() inherit from ASTNode instead.
     */
    public function setDocComment($docComment)
    {
        $this->setComment($docComment);
    }

    // END@deprecated
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */

namespace PDepend\Source\AST;

/**
 * This class represents a while-statement.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */
class ASTWhileStatement extends ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitWhileStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This class represents a formal parameter within the signature of a function,
 * method or closure.
 *
 * Formal parameters can include a type hint, a by reference identifier and a
 * default value. The only mandatory part is the parameter identifier.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTFormalParameter extends AbstractASTNode
{
    /**
     * Checks if this parameter has a type.
     *
     * @return boolean
     */
    public function hasType()
    {
        return (reset($this->nodes) instanceof ASTType);
    }

    /**
     * Returns the type of this parameter.
     *
     * @return \PDepend\Source\AST\ASTType
     */
    public function getType()
    {
        if ($this->hasType()) {
            return $this->getChild(0);
        }
        throw new \OutOfBoundsException('The parameter does not has a type specification.');
    }

    /**
     * This method will return <b>true</b> when the parameter is declared as a
     * variable argument list <b>...</b>.
     *
     * @return boolean
     * @since 2.0.7
     */
    public function isVariableArgList()
    {
        return $this->getMetadataBoolean(6);
    }

    /**
     * This method can be used to mark this parameter as passed by reference.
     *
     * @return void
    @since 2.0.7
     */
    public function setVariableArgList()
    {
        return $this->setMetadataBoolean(6, true);
    }

    /**
     * This method will return <b>true</b> when the parameter is passed by
     * reference.
     *
     * @return boolean
     */
    public function isPassedByReference()
    {
        return $this->getMetadataBoolean(5);
    }

    /**
     * This method can be used to mark this parameter as passed by reference.
     *
     * @return void
     */
    public function setPassedByReference()
    {
        return $this->setMetadataBoolean(5, true);
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param  mixed                                 $data
     * @return mixed
     * @since  0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitFormalParameter($this, $data);
    }

    /**
     * Returns the total number of the used property bag.
     *
     * @return integer
     * @since  0.10.4
     * @see    \PDepend\Source\AST\ASTNode#getMetadataSize()
     */
    protected function getMetadataSize()
    {
        return 7;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This node class represents a trait adaptation scope.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */
class ASTTraitAdaptation extends ASTScope
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param  mixed                                 $data
     * @return mixed
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitTraitAdaptation($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This ast class represents a list for formal parameters. This means the
 * parameters of a method, function or closure declaration.
 *
 * <code>
 * //          --
 * function foo() {}
 * //          --
 *
 * //           --------
 * $x = function($x, $y) {}
 * //           --------
 *
 * class Foo {
 *     //                 -----------------
 *     public function bar(Foo $obj = null) {}
 *     //                 -----------------
 * }
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTFormalParameters extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param  mixed                                 $data
     * @return mixed
     * @since  0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitFormalParameters($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * Abstract base class for code item.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface ASTArtifact /* extends ASTNode */
{
    /**
     * Returns the artifact name.
     *
     * @return string
     * @deprecated Use getImage() inherit from ASTNode class.
     */
    public function getName();

    /**
     * Returns a id for this code node.
     *
     * @return string
     */
    public function getId();

    /**
     * ASTVisitor method for node tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @return void
     */
    public function accept(ASTVisitor $visitor);
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This class represents a unset-statement node.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTUnsetStatement extends ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitUnsetStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

/**
 * This class represents a variable variable node.
 *
 * <code>
 * //   -
 * Foo::$$bar();
 * //   -
 *
 * //   --
 * Foo::$$$bar();
 * //   --
 *
 * //   -
 * Foo::$${BAR}();
 * //   -
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTVariableVariable extends ASTExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitVariableVariable($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This class represents a program scope statement.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTScopeStatement extends ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitScopeStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This class represents a compound variable node.
 *
 * <code>
 * //   ------
 * Foo::${BAR}();
 * //   ------
 *
 * //    ------
 * Foo::$${BAR}();
 * //    ------
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTCompoundVariable extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return mixed
     * @since 0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitCompoundVariable($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a do/while-statement.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTDoWhileStatement extends \PDepend\Source\AST\ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitDoWhileStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */

namespace PDepend\Source\AST;

/**
 * This node class represents an if-statement.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */
class ASTIfStatement extends ASTStatement
{
    /**
     * Returns <b>true</b> when this <b>if</b>-statement is followed by an
     * <b>else</b>-statement.
     *
     * @return boolean
     * @since  0.9.12
     */
    public function hasElse()
    {
        return (count($this->nodes) === 3);
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitIfStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

/**
 * This class represents a function postfix expression.
 *
 * <code>
 * //-------
 * foo($bar);
 * //-------
 *
 * //--------
 * $foo($bar);
 * //--------
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTFunctionPostfix extends ASTInvocation
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitFunctionPostfix($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * An instance of this class represents an object allocation.
 *
 * <code>
 * function foo()
 * {
 * //  -------------
 *     new bar\Baz();
 * //  -------------
 *
 * //  ---------
 *     new Foo();
 * //  ---------
 * }
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTAllocationExpression extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return mixed
     * @since 0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitAllocationExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */

namespace PDepend\Source\AST;

/**
 * This type of exception will be thrown when a trait related method collision
 * occurred.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */
class ASTTraitMethodCollisionException extends \RuntimeException
{
    /**
     * Constructs a new exception instance.
     *
     * @param \PDepend\Source\AST\ASTMethod       $method
     * @param \PDepend\Source\AST\AbstractASTType $type
     */
    public function __construct(ASTMethod $method, AbstractASTType $type)
    {
        parent::__construct(
            sprintf(
                'Trait method %s has not been applied, because there are ' .
                'collisions with other trait methods on %s\%s.',
                $method->getName(),
                preg_replace('(\W+)', '\\', $type->getNamespace()->getName()),
                $type->getName()
            )
        );
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */

namespace PDepend\Source\AST;

/**
 * This node class encapsultes any expression.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */
class ASTExpression extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */

namespace PDepend\Source\AST;

/**
 * This class represents an array expression.
 *
 * <code>
 * //       -------------------------------------
 * $array = array( 1, 2, 3, array( $a, $b, $c ) );
 * //       -------------------------------------
 *
 * //       ---------------------------
 * $array = [ 1, 2, 3, [ $a, $b, $c ] ];
 * //       ---------------------------
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */
class ASTArray extends \PDepend\Source\AST\ASTExpression
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param  mixed                                 $data
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitArray($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This code class represents a class property.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTProperty extends AbstractASTArtifact
{
    /**
     * The parent type object.
     *
     * @var ASTClass
     */
    private $declaringClass = null;

    /**
     * The wrapped field declaration instance.
     *
     * @var   \PDepend\Source\AST\ASTFieldDeclaration
     * @since 0.9.6
     */
    private $fieldDeclaration = null;

    /**
     * The wrapped variable declarator instance.
     *
     * @var   \PDepend\Source\AST\ASTVariableDeclarator
     * @since 0.9.6
     */
    private $variableDeclarator = null;

    /**
     * Constructs a new item for the given field declaration and variable
     * declarator.
     *
     * @param \PDepend\Source\AST\ASTFieldDeclaration   $fieldDeclaration   The context
     *        field declaration where this property was declared in the source.
     * @param \PDepend\Source\AST\ASTVariableDeclarator $variableDeclarator The context
     *        variable declarator for this property instance.
     */
    public function __construct(
        \PDepend\Source\AST\ASTFieldDeclaration $fieldDeclaration,
        \PDepend\Source\AST\ASTVariableDeclarator $variableDeclarator
    ) {
        $this->fieldDeclaration   = $fieldDeclaration;
        $this->variableDeclarator = $variableDeclarator;

        $this->id = spl_object_hash($this);
    }

    /**
     * Returns the item name.
     *
     * @return string
     */
    public function getName()
    {
        return $this->variableDeclarator->getImage();
    }

    /**
     * This method returns a OR combined integer of the declared modifiers for
     * this property.
     *
     * @return integer
     * @since  0.9.6
     */
    public function getModifiers()
    {
        return $this->fieldDeclaration->getModifiers();
    }

    /**
     * Returns <b>true</b> if this node is marked as public, otherwise the
     * returned value will be <b>false</b>.
     *
     * @return boolean
     */
    public function isPublic()
    {
        return $this->fieldDeclaration->isPublic();
    }

    /**
     * Returns <b>true</b> if this node is marked as protected, otherwise the
     * returned value will be <b>false</b>.
     *
     * @return boolean
     */
    public function isProtected()
    {
        return $this->fieldDeclaration->isProtected();
    }

    /**
     * Returns <b>true</b> if this node is marked as private, otherwise the
     * returned value will be <b>false</b>.
     *
     * @return boolean
     */
    public function isPrivate()
    {
        return $this->fieldDeclaration->isPrivate();
    }

    /**
     * Returns <b>true</b> when this node is declared as static, otherwise
     * the returned value will be <b>false</b>.
     *
     * @return boolean
     */
    public function isStatic()
    {
        return $this->fieldDeclaration->isStatic();
    }

    /**
     * This method will return <b>true</b> when this property doc comment
     * contains an array type hint, otherwise the it will return <b>false</b>.
     *
     * @return boolean
     * @since  0.9.6
     */
    public function isArray()
    {
        $typeNode = $this->fieldDeclaration->getFirstChildOfType(
            'PDepend\\Source\\AST\\ASTType'
        );
        if ($typeNode === null) {
            return false;
        }
        return $typeNode->isArray();
    }

    /**
     * This method will return <b>true</b> when this property doc comment
     * contains a primitive type hint, otherwise the it will return <b>false</b>.
     *
     * @return boolean
     * @since  0.9.6
     */
    public function isScalar()
    {
        $typeNode = $this->fieldDeclaration->getFirstChildOfType(
            'PDepend\\Source\\AST\\ASTType'
        );
        if ($typeNode === null) {
            return false;
        }
        return $typeNode->isScalar();
    }

    /**
     * Returns the type of this property. This method will return <b>null</b>
     * for all scalar type, only class properties will have a type.
     *
     * @return \PDepend\Source\AST\AbstractASTClassOrInterface
     * @since  0.9.5
     */
    public function getClass()
    {
        $reference = $this->fieldDeclaration->getFirstChildOfType(
            'PDepend\\Source\\AST\\ASTClassOrInterfaceReference'
        );
        if ($reference === null) {
            return null;
        }
        return $reference->getType();
    }

    /**
     * Returns the doc comment for this item or <b>null</b>.
     *
     * @return string
     */
    public function getComment()
    {
        return $this->fieldDeclaration->getComment();
    }

    /**
     * Returns the line number where the property declaration can be found.
     *
     * @return integer
     * @since  0.9.6
     */
    public function getStartLine()
    {
        return $this->variableDeclarator->getStartLine();
    }

    /**
     * Returns the column number where the property declaration starts.
     *
     * @return integer
     * @since  0.9.8
     */
    public function getStartColumn()
    {
        return $this->variableDeclarator->getStartColumn();
    }

    /**
     * Returns the line number where the property declaration ends.
     *
     * @return integer
     * @since  0.9.6
     */
    public function getEndLine()
    {
        return $this->variableDeclarator->getEndLine();
    }

    /**
     * Returns the column number where the property declaration ends.
     *
     * @return integer
     * @since  0.9.8
     */
    public function getEndColumn()
    {
        return $this->variableDeclarator->getEndColumn();
    }

    /**
     * This method will return the class where this property was declared.
     *
     * @return \PDepend\Source\AST\AbstractASTClassOrInterface
     * @since  0.9.6
     */
    public function getDeclaringClass()
    {
        return $this->declaringClass;
    }

    /**
     * Sets the declaring class object.
     *
     * @param  \PDepend\Source\AST\ASTClass $declaringClass
     * @return void
     * @since  0.9.6
     */
    public function setDeclaringClass(ASTClass $declaringClass)
    {
        $this->declaringClass = $declaringClass;
    }

    /**
     * This method will return <b>true</b> when the parameter declaration
     * contains a default value.
     *
     * @return boolean
     * @since  0.9.6
     */
    public function isDefaultValueAvailable()
    {
        $value = $this->variableDeclarator->getValue();
        if ($value === null) {
            return false;
        }
        return $value->isValueAvailable();
    }

    /**
     * This method will return the default value for this property instance or
     * <b>null</b> when this property was only declared and not initialized.
     *
     * @return mixed
     * @since  0.9.6
     */
    public function getDefaultValue()
    {
        $value = $this->variableDeclarator->getValue();
        if ($value === null) {
            return null;
        }
        return $value->getValue();
    }

    /**
     * ASTVisitor method for node tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @return void
     */
    public function accept(ASTVisitor $visitor)
    {
        $visitor->visitProperty($this);
    }

    /**
     * This method returns a string representation of this parameter.
     *
     * @return string
     * @since  0.9.6
     */
    public function __toString()
    {
        $default = ($this->isDefault() === true ? ' <default>' : '');
        $static  = '';

        if ($this->isStatic() === true) {
            $default = '';
            $static  = ' static';
        }

        $visibility = ' public';
        if ($this->isProtected() === true) {
            $visibility = ' protected';
        } elseif ($this->isPrivate() === true) {
            $visibility = ' private';
        }

        return sprintf(
            'Property [%s%s%s %s ]%s',
            $default,
            $visibility,
            $static,
            $this->getName(),
            PHP_EOL
        );
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This node class represents a comment.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ASTComment extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return mixed
     * @since 0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitComment($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a try-statement.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTTryStatement extends ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitTryStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a label-statement.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTLabelStatement extends ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitLabelStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This class represents a here-/nowdoc node.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTHeredoc extends ASTExpression
{
    /**
     * Delimiter used for this heredoc instance.
     *
     * @var string
     */
    protected $delimiter = null;

    /**
     * Sets the delimiter used for this heredoc instance.
     *
     * @param string $delimiter The heredoc delimiter.
     *
     * @return void
     */
    public function setDelimiter($delimiter)
    {
        $this->delimiter = $delimiter;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitHeredoc($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This is a special reference container that is used whenever the keyword
 * <b>parent</b> is used to reference a class or interface.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
final class ASTParentReference extends ASTClassOrInterfaceReference
{
    /**
     * The source image of this node.
     */
    const IMAGE = 'parent';

    /**
     * The wrapped reference node.
     *
     * @var \PDepend\Source\AST\ASTClassOrInterfaceReference
     */
    protected $reference = null;

    /**
     * Constructs a new type holder instance.
     *
     * @param \PDepend\Source\AST\ASTClassOrInterfaceReference $reference The type
     *        instance that reference the concrete target of self.
     *
     * @todo Call parent constructor, otherwise this could cause bad side effects.
     */
    public function __construct(ASTClassOrInterfaceReference $reference)
    {
        $this->reference = $reference;
    }

    /**
     * Returns the visual representation for this node type.
     *
     * @return string
     * @since  0.10.4
     */
    public function getImage()
    {
        return self::IMAGE;
    }

    /**
     * Returns the concrete type instance associated with with this placeholder.
     *
     * @return \PDepend\Source\AST\AbstractASTClassOrInterface
     */
    public function getType()
    {
        return $this->reference->getType();
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param  \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param  mixed                                 $data
     * @return mixed
     * @since  0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitParentReference($this, $data);
    }

    /**
     * The magic sleep method will be called by PHP's runtime environment right
     * before an instance of this class gets serialized. It should return an
     * array with those property names that should be serialized for this class.
     *
     * @return array(string)
     * @since  0.10.0
     */
    public function __sleep()
    {
        return array_merge(array('reference'), parent::__sleep());
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * Abstract base class for a type node.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTType extends AbstractASTNode
{
    /**
     * This method will return <b>true</b> when the underlying type is an array.
     *
     * @return boolean
     */
    public function isArray()
    {
        return false;
    }

    /**
     * This method will return <b>true</b> when the underlying data type is a
     * php primitive.
     *
     * @return boolean
     */
    public function isScalar()
    {
        return false;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return mixed
     * @since 0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitType($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

/**
 * This class represents a literal node.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTLiteral extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitLiteral($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */

namespace PDepend\Source\AST;

/**
 * This node class encapsultes a shift left expression.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.1
 */
class ASTShiftLeftExpression extends ASTExpression
{
    /**
     * The default image for this node.
     */
    const IMAGE = '<<';

    /**
     * Returns the source image of this ast node.
     *
     * @return string
     */
    public function getImage()
    {
        return self::IMAGE;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitShiftLeftExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */

namespace PDepend\Source\AST;

/**
 * This node class represents a global-statement.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.12
 */
class ASTGlobalStatement extends ASTStatement
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitGlobalStatement($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.0.0
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This class represents the full qualified class name postfix.
 *
 * <code>
 * //   -----
 * Foo::class
 * //   -----
 *
 * //     -----
 * $bar:: class;
 * //     -----
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 2.0.0
 */
class ASTClassFqnPostfix extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitClassFqnPostfix($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.5
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;
use PDepend\Source\Builder\BuilderContext;

/**
 * This class is used as a placeholder for unknown classes or interfaces. It
 * will resolve the concrete type instance on demand.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.5
 */
class ASTClassOrInterfaceReference extends ASTType
{
    /**
     * The global AST builder context.
     *
     * @var \PDepend\Source\Builder\BuilderContext
     */
    protected $context = null;

    /**
     * An already loaded type instance.
     *
     * @var \PDepend\Source\AST\AbstractASTClassOrInterface
     */
    protected $typeInstance = null;

    /**
     * Constructs a new type holder instance.
     *
     * @param \PDepend\Source\Builder\BuilderContext $context
     * @param string                                 $qualifiedName
     */
    public function __construct(BuilderContext $context, $qualifiedName)
    {
        parent::__construct($qualifiedName);

        $this->context = $context;
    }

    /**
     * Returns the concrete type instance associated with with this placeholder.
     *
     * @return \PDepend\Source\AST\AbstractASTClassOrInterface
     */
    public function getType()
    {
        if ($this->typeInstance === null) {
            $this->typeInstance = $this->context->getClassOrInterface(
                $this->getImage()
            );
        }
        return $this->typeInstance;
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return mixed
     * @since  0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitClassOrInterfaceReference($this, $data);
    }

    /**
     * Magic method which returns the names of all those properties that should
     * be cached for this node instance.
     *
     * @return array
     * @since  0.10.0
     */
    public function __sleep()
    {
        return array_merge(array('context'), parent::__sleep());
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */

namespace PDepend\Source\AST;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * This node class represents a conditional expression.
 *
 * <code>
 *       --------------
 * $x = ($foo ? 42 : 23)
 *       --------------
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.8
 */
class ASTConditionalExpression extends AbstractASTNode
{
    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor
     * @param mixed $data
     * @return mixed
     * @since 0.9.12
     */
    public function accept(ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitConditionalExpression($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */

namespace PDepend\Source\AST;

/**
 * Primary prefix expression as it is used to access class or interface members
 * like methods, properties and constants.
 *
 * <code>
 * //--------
 * Foo::bar();
 * //--------
 *
 * //---------
 * Foo::$bar();
 * //---------
 *
 * //---------
 * $obj->bar();
 * //---------
 *
 * //----------
 * $obj->$bar();
 * //----------
 * </code>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.6
 */
class ASTMemberPrimaryPrefix extends AbstractASTNode
{
    /**
     * Returns <b>true</b> when this member primary prefix represents a static
     * property or method access.
     *
     * @return boolean
     */
    public function isStatic()
    {
        return ($this->getImage() === '::');
    }

    /**
     * Accept method of the visitor design pattern. This method will be called
     * by a visitor during tree traversal.
     *
     * @param \PDepend\Source\ASTVisitor\ASTVisitor $visitor The calling visitor instance.
     * @param mixed                                 $data
     *
     * @return mixed
     * @since  0.9.12
     */
    public function accept(\PDepend\Source\ASTVisitor\ASTVisitor $visitor, $data = null)
    {
        return $visitor->visitMemberPrimaryPrefix($this, $data);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\Tokenizer;

/**
 * This struct represents a code token.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class Token
{
    /**
     * The token type identifier.
     *
     * @var integer
     */
    public $type = null;

    /**
     * The token image/textual representation.
     *
     * @var string
     */
    public $image = null;

    /**
     * The start line number for this token.
     *
     * @var integer
     */
    public $startLine = null;

    /**
     * The end line number for this token.
     *
     * @var integer
     */
    public $endLine = null;

    /**
     * The start column number for this token.
     *
     * @var integer
     */
    public $startColumn = null;

    /**
     * The end column number for this token.
     *
     * @var integer
     */
    public $endColumn = null;

    /**
     * Constructs a new source token.
     *
     * @param integer $type        The token type identifier.
     * @param string  $image       The token image/textual representation.
     * @param integer $startLine   The start line number for this token.
     * @param integer $endLine     The end line number for this token.
     * @param integer $startColumn The start column number for this token.
     * @param integer $endColumn   The end column number for this token.
     */
    public function __construct($type, $image, $startLine, $endLine, $startColumn, $endColumn)
    {
        $this->type        = $type;
        $this->image       = $image;
        $this->startLine   = $startLine;
        $this->endLine     = $endLine;
        $this->startColumn = $startColumn;
        $this->endColumn   = $endColumn;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\Tokenizer;

/**
 * This interface holds the different tokenizer, builder and parser constants.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface Tokens
{
    /**
     * Marks a class token.
     */
    const T_CLASS = 1;

    /**
     * Marks an interface token.
     */
    const T_INTERFACE = 2;

    /**
     * Marks an abstract token.
     */
    const T_ABSTRACT = 3;

    /**
     * Marks a curly brace open.
     */
    const T_CURLY_BRACE_OPEN = 4;

    /**
     * Marks a curly brace close.
     */
    const T_CURLY_BRACE_CLOSE = 5;

    /**
     * Marks a parenthesis open.
     */
    const T_PARENTHESIS_OPEN = 6;

    /**
     * Marks a parenthesis close.
     */
    const T_PARENTHESIS_CLOSE = 7;

    /**
     * Marks a new token.
     */
    const T_NEW = 8;

    /**
     * Marks a function.
     */
    const T_FUNCTION = 9;

    /**
     * Marks a double colon.
     */
    const T_DOUBLE_COLON = 10;

    /**
     * Marks a string token.
     */
    const T_STRING = 11;

    /**
     * Marks a doc comment.
     */
    const T_DOC_COMMENT = 12;

    /**
     * Marks a semicolon.
     */
    const T_SEMICOLON = 13;

    /**
     * Marks a null token.
     */
    const T_NULL = 14;

    /**
     * Marks a true token.
     */
    const T_TRUE = 15;

    /**
     * Marks a false token.
     */
    const T_FALSE = 16;

    /**
     * Marks a array token.
     */
    const T_ARRAY = 17;

    /**
     * Marks a 'parent' token.
     */
    const T_PARENT = 18;

    /**
     * Marks a '=' token.
     */
    const T_EQUAL = 19;

    /**
     * Marks a '&=' token.
     */
    const T_AND_EQUAL = 20;

    /**
     * Marks a '.=' token.
     */
    const T_CONCAT_EQUAL = 21;

    /**
     * Marks a '/=' token.
     */
    const T_DIV_EQUAL = 22;

    /**
     * Marks a '==' token.
     */
    const T_IS_EQUAL = 23;

    /**
     * Marks a '>=' token.
     */
    const T_IS_GREATER_OR_EQUAL = 24;

    /**
     * Marks a '===' token.
     */
    const T_IS_IDENTICAL = 25;

    /**
     * Marks a '!=' or '<>' token.
     */
    const T_IS_NOT_EQUAL = 26;

    /**
     * Marks a '!==' token.
     */
    const T_IS_NOT_IDENTICAL = 27;

    /**
     * Marks a '<=' token.
     */
    const T_IS_SMALLER_OR_EQUAL = 28;

    /**
     * Marks a '-=' token.
     */
    const T_MINUS_EQUAL = 29;

    /**
     * Marks a '%=' token.
     */
    const T_MOD_EQUAL = 30;

    /**
     * Marks a '*=' token.
     */
    const T_MUL_EQUAL = 31;

    /**
     * Marks a '|=' token.
     */
    const T_OR_EQUAL = 32;

    /**
     * Marks a '+=' token.
     */
    const T_PLUS_EQUAL = 33;

    /**
     * Marks a '^=' token.
     */
    const T_XOR_EQUAL = 34;

    /**
     * Marks a '.' token.
     */
    const T_CONCAT = 35;

    /**
     * Marks a 'as' token.
     */
    const T_AS = 36;

    /**
     * Marks a '(array)' cast token.
     */
    const T_ARRAY_CAST = 37;

    /**
     * Marks a '&&' token.
     */
    const T_BOOLEAN_AND = 38;

    /**
     * Marks a '||' token.
     */
    const T_BOOLEAN_OR = 39;

    /**
     * Marks a '(bool)' or '(boolean)' cast token.
     */
    const T_BOOL_CAST = 40;

    /**
     * Marks a 'break' token.
     */
    const T_BREAK = 41;

    /**
     * Marks a 'case' token.
     */
    const T_CASE = 42;

    /**
     * Marks a 'catch' token.
     */
    const T_CATCH = 43;

    /**
     * Marks a '__CLASS__' token.
     */
    const T_CLASS_C = 44;

    /**
     * Marks a 'clone' token.
     */
    const T_CLONE = 45;

    /**
     * Marks a '?>' token.
     */
    const T_CLOSE_TAG = 46;

    /**
     * Marks a 'const' token.
     */
    const T_CONST = 47;

    /**
     * Marks a constant string like 'foo' or "foo".
     */
    const T_CONSTANT_ENCAPSED_STRING = 48;

    /**
     * Marks a 'continue' token.
     */
    const T_CONTINUE = 49;

    /**
     * Marks a '--' token.
     */
    const T_DEC = 50;

    /**
     * Marks a 'declare' token.
     */
    const T_DECLARE = 51;

    /**
     * Marks a 'default' token.
     */
    const T_DEFAULT = 52;

    /**
     * Marks a floating point number.
     */
    const T_DNUMBER = 53;

    /**
     * Marks a 'do' token.
     */
    const T_DO = 54;

    /**
     * Marks a '=>' token.
     */
    const T_DOUBLE_ARROW = 55;

    /**
     * Marks a '(real)', '(float)' or '(double)' cast token.
     */
    const T_DOUBLE_CAST = 56;

    /**
     * Marks a 'echo' token.
     */
    const T_ECHO = 57;

    /**
     * Marks a 'else' token.
     */
    const T_ELSE = 58;

    /**
     * Marks a 'elseif' token.
     */
    const T_ELSEIF = 59;

    /**
     * Marks a 'empty' token.
     */
    const T_EMPTY = 60;

    /**
     * Marks the end of a heredoc block.
     */
    const T_END_HEREDOC = 61;

    /**
     * Marks a 'evil' token.
     */
    const T_EVAL = 62;

    /**
     * Marks a 'exit' or 'die' token.
     */
    const T_EXIT = 63;

    /**
     * Marks a 'extends' token.
     */
    const T_EXTENDS = 64;

    /**
     * Marks a '__FILE__' token.
     */
    const T_FILE = 65;

    /**
     * Marks a 'final' token.
     */
    const T_FINAL = 66;

    /**
     * Marks a 'for' token.
     */
    const T_FOR = 67;

    /**
     * Marks a 'foreach' token.
     */
    const T_FOREACH = 68;

    /**
     * Marks a '__FUNCTION__' token.
     */
    const T_FUNC_C = 69;

    /**
     * Marks a 'global' token.
     */
    const T_GLOBAL = 70;

    /**
     * Marks a '__halt_compiler()' token.
     */
    const T_HALT_COMPILER = 71;

    /**
     * Marks a 'if' token.
     */
    const T_IF = 72;

    /**
     * Marks a 'implements' token.
     */
    const T_IMPLEMENTS = 73;

    /**
     * Marks a '++' token.
     */
    const T_INC = 74;

    /**
     * Marks a 'include' token.
     */
    const T_INCLUDE = 75;

    /**
     * Marks a 'include_once' token.
     */
    const T_INCLUDE_ONCE = 76;

    /**
     * Marks inline html???
     */
    const T_INLINE_HTML = 77;

    /**
     * Marks a 'instanceof' token.
     */
    const T_INSTANCEOF = 78;

    /**
     * Marks a '(int)' or '(integer)' cast token.
     */
    const T_INT_CAST = 79;

    /**
     * Marks a 'isset' token.
     */
    const T_ISSET = 80;

    /**
     * Marks a '__LINE__' token.
     */
    const T_LINE = 81;

    /**
     * Marks a 'list' token.
     */
    const T_LIST = 82;

    /**
     * Marks a integer number token.
     */
    const T_LNUMBER = 83;

    /**
     * Marks a 'and' token.
     */
    const T_LOGICAL_AND = 84;

    /**
     * Marks a 'or' token.
     */
    const T_LOGICAL_OR = 85;

    /**
     * Marks a 'xor' token.
     */
    const T_LOGICAL_XOR = 86;

    /**
     * Marks a '__METHOD__' token.
     */
    const T_METHOD_C = 87;

    /**
     * Marks a '__NAMESPACE__' token.
     */
    const T_NS_C = 88;

    /**
     * A number string token???
     */
    const T_NUM_STRING = 89;

    /**
     * Marks a '(object)' cast token.
     */
    const T_OBJECT_CAST = 90;

    /**
     * Marks a '->' object access token.
     */
    const T_OBJECT_OPERATOR = 91;

    /**
     * Marks a php open token.
     */
    const T_OPEN_TAG = 92;

    /**
     * Marks a php open token.
     */
    const T_OPEN_TAG_WITH_ECHO = 93;

    /**
     * Marks a 'print' token.
     */
    const T_PRINT = 94;

    /**
     * Marks a 'private' token.
     */
    const T_PRIVATE = 95;

    /**
     * Marks a 'public' token.
     */
    const T_PUBLIC = 96;

    /**
     * Marks a 'protected' token.
     */
    const T_PROTECTED = 97;

    /**
     * Marks a 'require' token.
     */
    const T_REQUIRE = 98;

    /**
     * Marks a 'require_once' token.
     */
    const T_REQUIRE_ONCE = 99;

    /**
     * Marks a 'return' token.
     */
    const T_RETURN = 100;

    /**
     * Marks a '<<' token.
     */
    const T_SL = 101;

    /**
     * Marks a '<<=' token.
     */
    const T_SL_EQUAL = 102;

    /**
     * Marks a '>>' token.
     */
    const T_SR = 103;

    /**
     * Marks a '>>=' token.
     */
    const T_SR_EQUAL = 104;

    /**
     * Marks the beginning of a here doc block.
     */
    const T_START_HEREDOC = 105;

    /**
     * Marks a 'static' token.
     */
    const T_STATIC = 106;

    /**
     * Marks a '(string)' cast token.
     */
    const T_STRING_CAST = 107;

    /**
     * Marks a string var name???
     */
    const T_STRING_VARNAME = 108;

    /**
     * Marks a 'switch' token.
     */
    const T_SWITCH = 109;

    /**
     * Marks a 'throw' token.
     */
    const T_THROW = 110;

    /**
     * Marks a 'try' token.
     */
    const T_TRY = 111;

    /**
     * Marks a 'unset' token.
     */
    const T_UNSET = 112;

    /**
     * Marks a '(unset)' cast token.
     */
    const T_UNSET_CAST = 113;

    /**
     * Marks a 'use' token.
     */
    const T_USE = 114;

    /**
     * Marks a 'var' token.
     */
    const T_VAR = 115;

    /**
     * Marks a variable token.
     */
    const T_VARIABLE = 116;

    /**
     * Marks a 'while' token.
     */
    const T_WHILE = 117;

    /**
     * Marks a ',' token.
     */
    const T_COMMA = 118;

    /**
     * Marks a '*' token.
     */
    const T_MUL = 119;

    /**
     * Marks a '[' token.
     */
    const T_SQUARED_BRACKET_OPEN = 120;

    /**
     * Marks a ']' token.
     */
    const T_SQUARED_BRACKET_CLOSE = 121;

    /**
     * Marks a '<' token.
     */
    const T_ANGLE_BRACKET_OPEN = 122;

    /**
     * Marks a '>' token.
     */
    const T_ANGLE_BRACKET_CLOSE = 123;

    /**
     * Marks a '"' token.
     */
    const T_DOUBLE_QUOTE = 124;

    /**
     * Marks a ':' token.
     */
    const T_COLON = 125;

    /**
     * Marks a '@' token.
     */
    const T_AT = 126;

    /**
     * Marks a '+' token.
     */
    const T_PLUS = 127;

    /**
     * Marks a '-' token.
     */
    const T_MINUS = 128;

    /**
     * Marks a '!' token.
     */
    const T_EXCLAMATION_MARK = 129;

    /**
     * Marks a '?' token.
     */
    const T_QUESTION_MARK = 130;

    /**
     * Marks a '&' token.
     */
    const T_BITWISE_AND = 131;

    /**
     * Marks a '|' token.
     */
    const T_BITWISE_OR = 132;

    /**
     * Marks a '~' token.
     */
    const T_BITWISE_NOT = 133;

    /**
     * Marks a '^' token.
     */
    const T_BITWISE_XOR = 134;

    /**
     * Marks a '/' token.
     */
    const T_DIV = 135;

    /**
     * Marks a '%' token.
     */
    const T_MOD = 136;

    /**
     * Marks a comment token.
     */
    const T_COMMENT = 137;

    /**
     * Marks a 'namespace' token.
     */
    const T_NAMESPACE = 138;

    /**
     * Marks an escape token.
     */
    const T_ENCAPSED_AND_WHITESPACE = 139;

    /**
     * Marks a '$' string token.
     */
    const T_DOLLAR = 140;

    /**
     * Marks any character token.
     */
    const T_CHARACTER = 141;

    /**
     * Marks any bad character token.
     */
    const T_BAD_CHARACTER = 142;

    /**
     * Marks a 'self' token.
     */
    const T_SELF = 143;

    /**
     * Marks a '`' backtick token.
     */
    const T_BACKTICK = 144;

    /**
     * Marks a '\' backslash token.
     */
    const T_BACKSLASH = 145;

    /**
     * Marks a '__DIR__' token.
     */
    const T_DIR = 146;

    /**
     * Marks a 'goto' token.
     */
    const T_GOTO = 147;

    /**
     * Alternative end token for an if-statement.
     */
    const T_ENDIF = 148;

    /**
     * Alternative end token for a for-statement.
     */
    const T_ENDFOR = 149;

    /**
     * Alternative end token for a foreach-statement.
     */
    const T_ENDFOREACH = 150;

    /**
     * Alternative end token for a switch-statement.
     */
    const T_ENDSWITCH = 151;

    /**
     * Alternative end token for a while-statement.
     */
    const T_ENDWHILE = 152;

    /**
     * Alternative end token for a declare-statement.
     */
    const T_ENDDECLARE = 153;

    /**
     * Marks a 'trait' keyword token.
     */
    const T_TRAIT = 154;

    /**
     * Marks a '__TRAIT__' magic constant token.
     */
    const T_TRAIT_C = 155;

    /**
     * Token that represents the new Callable type hint.
     */
    const T_CALLABLE = 156;

    /**
     * Token that represents the new 'insteadof' keyword.
     */
    const T_INSTEADOF = 157;

    /**
     * Token that represents the stdClass::class and $class::class constant.
     */
    const T_CLASS_FQN = 158;

    /**
     * Token that represents the new 'yield' keyword.
     */
    const T_YIELD = 159;

    /**
     * Token that represents the 'finally' keyword.
     */
    const T_FINALLY = 160;

    /**
     * Token that represents the '...' token
     *
     * @since 2.0.7
     */
    const T_ELLIPSIS = 161;

    /**
     * Token that represents the '<=>' spaceship operator
     */
    const T_SPACESHIP = 162;

    /**
     * Token that represents the '??' null coalescing operator
     */
    const T_COALESCE = 163;

    /**
     * Token that represents the '**' null coalescing operator
     */
    const T_POW = 164;

    /**
     * Marks any content not between php tags.
     */
    const T_NO_PHP = 255;
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\Tokenizer;

/**
 * Base interface for all php code tokenizers.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface Tokenizer
{
    /**
     * Marks the end of the token stream.
     */
    const T_EOF = -1;

    /**
     * Marks the beginning of the token stream.
     */
    const T_BOF = -2;

    /**
     * Returns the name of the source file.
     *
     * @return string
     */
    public function getSourceFile();

    /**
     * Sets a new php source file.
     *
     * @param string $sourceFile A php source file.
     *
     * @return void
     */
    public function setSourceFile($sourceFile);

    /**
     * Returns the next token or {@link \PDepend\Source\Tokenizer\Tokenizer::T_EOF} if
     * there is no next token.
     *
     * @return \PDepend\Source\Tokenizer\Token
     */
    public function next();

    /**
     * Returns the next token type or {@link \PDepend\Source\Tokenizer\Tokenizer::T_EOF} if
     * there is no next token.
     *
     * @return integer
     */
    public function peek();
    
    /**
     * Returns the type of next token, after the current token. This method
     * ignores all comments between the current and the next token.
     *
     * @return integer
     * @since  0.9.12
     */
    public function peekNext();

    /**
     * Returns the previous token type or {@link \PDepend\Source\Tokenizer\Tokenizer::T_BOF}
     * if there is no previous token.
     *
     * @return integer
     */
    public function prev();
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics;

/**
 * This interface is used to mark a result set as project summary aware.
 *
 * A result set that implements this interface provides overview or calculated
 * values for the complete analyzed source code.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface AnalyzerProjectAware extends Analyzer
{
    /**
     * Provides the project summary as an <b>array</b>.
     *
     * <code>
     * array(
     *     'loc'  =>  1742,
     *     'nop'  =>  23,
     *     'noc'  =>  17
     * )
     * </code>
     *
     * @return array(string=>mixed)
     */
    public function getProjectMetrics();
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer;

use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Metrics\AnalyzerProjectAware;
use PDepend\Source\AST\AbstractASTCallable;
use PDepend\Source\AST\AbstractASTType;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTProperty;

/**
 * This analyzer collects coupling values for the hole project. It calculates
 * all function and method <b>calls</b> and the <b>fanout</b>, that means the
 * number of referenced types.
 *
 * The FANOUT calculation is based on the definition used by the apache maven
 * project.
 *
 * <ul>
 *   <li>field declarations (Uses doc comment annotations)</li>
 *   <li>formal parameters and return types (The return type uses doc comment
 *   annotations)</li>
 *   <li>throws declarations (Uses doc comment annotations)</li>
 *   <li>local variables</li>
 * </ul>
 *
 * http://www.jajakarta.org/turbine/en/turbine/maven/reference/metrics.html
 *
 * The implemented algorithm counts each type only once for a method and function.
 * Any type that is either a supertype or a subtype of the class is not counted.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class CouplingAnalyzer extends AbstractAnalyzer implements AnalyzerNodeAware, AnalyzerProjectAware
{
    /**
     * Metrics provided by the analyzer implementation.
     */
    const M_CALLS  = 'calls',
          M_FANOUT = 'fanout',
          M_CA     = 'ca',
          M_CBO    = 'cbo',
          M_CE     = 'ce';

    /**
     * Has this analyzer already processed the source under test?
     *
     * @var   boolean
     * @since 0.10.2
     */
    private $uninitialized = true;

    /**
     * The number of method or function calls.
     *
     * @var integer
     */
    private $calls = 0;

    /**
     * Number of fanouts.
     *
     * @var integer
     */
    private $fanout = 0;

    /**
     * Temporary map that is used to hold the id combinations of dependee and
     * depender.
     *
     * @var   array(string=>array)
     * @since 0.10.2
     */
    private $dependencyMap = array();

    /**
     * This array holds a mapping between node identifiers and an array with
     * the node's metrics.
     *
     * @var   array(string=>array)
     * @since 0.10.2
     */
    private $nodeMetrics = array();

    /**
     * Provides the project summary as an <b>array</b>.
     *
     * <code>
     * array(
     *     'calls'   =>  23,
     *     'fanout'  =>  42
     * )
     * </code>
     *
     * @return array(string=>mixed)
     */
    public function getProjectMetrics()
    {
        return array(
            self::M_CALLS   =>  $this->calls,
            self::M_FANOUT  =>  $this->fanout
        );
    }

    /**
     * This method will return an <b>array</b> with all generated metric values
     * for the given node instance. If there are no metrics for the given node
     * this method will return an empty <b>array</b>.
     *
     * <code>
     * array(
     *     'loc'    =>  42,
     *     'ncloc'  =>  17,
     *     'cc'     =>  12
     * )
     * </code>
     *
     * @param  \PDepend\Source\AST\ASTArtifact $artifact
     * @return array(string=>mixed)
     */
    public function getNodeMetrics(ASTArtifact $artifact)
    {
        if (isset($this->nodeMetrics[$artifact->getId()])) {
            return $this->nodeMetrics[$artifact->getId()];
        }
        return array();
    }

    /**
     * Processes all {@link \PDepend\Source\AST\ASTNamespace} code nodes.
     *
     * @param  \PDepend\Source\AST\ASTNamespace[] $namespaces
     * @return void
     */
    public function analyze($namespaces)
    {
        if ($this->uninitialized) {
            $this->doAnalyze($namespaces);
            $this->uninitialized = false;
        }
    }

    /**
     * This method traverses all namespaces in the given iterator and calculates
     * the coupling metrics for them.
     *
     * @param  \PDepend\Source\AST\ASTNamespace[] $namespaces
     * @return void
     * @since  0.10.2
     */
    private function doAnalyze($namespaces)
    {
        $this->fireStartAnalyzer();
        $this->reset();

        foreach ($namespaces as $namespace) {
            $namespace->accept($this);
        }

        $this->postProcessTemporaryCouplingMap();
        $this->fireEndAnalyzer();
    }

    /**
     * This method resets all internal state variables before the analyzer can
     * start the object tree traversal.
     *
     * @return void
     * @since  0.10.2
     */
    private function reset()
    {
        $this->calls         = 0;
        $this->fanout        = 0;
        $this->nodeMetrics   = array();
        $this->dependencyMap = array();
    }

    /**
     * This method takes the temporary coupling map with node IDs and calculates
     * the concrete node metrics.
     *
     * @return void
     * @since  0.10.2
     */
    private function postProcessTemporaryCouplingMap()
    {
        foreach ($this->dependencyMap as $id => $metrics) {
            $afferentCoupling = count($metrics['ca']);
            $efferentCoupling = count($metrics['ce']);

            $this->nodeMetrics[$id] = array(
                self::M_CA   =>  $afferentCoupling,
                self::M_CBO  =>  $efferentCoupling,
                self::M_CE   =>  $efferentCoupling
            );

            $this->fanout += $efferentCoupling;
        }

        $this->dependencyMap = array();
    }

    /**
     * Visits a function node.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     */
    public function visitFunction(ASTFunction $function)
    {
        $this->fireStartFunction($function);

        $fanouts = array();
        if (($type = $function->getReturnClass()) !== null) {
            $fanouts[] = $type;
            ++$this->fanout;
        }
        foreach ($function->getExceptionClasses() as $type) {
            if (in_array($type, $fanouts, true) === false) {
                $fanouts[] = $type;
                ++$this->fanout;
            }
        }
        foreach ($function->getDependencies() as $type) {
            if (in_array($type, $fanouts, true) === false) {
                $fanouts[] = $type;
                ++$this->fanout;
            }
        }

        foreach ($fanouts as $fanout) {
            $this->initDependencyMap($fanout);

            $this->dependencyMap[$fanout->getId()]['ca'][$function->getId()] = true;
        }

        $this->countCalls($function);

        $this->fireEndFunction($function);
    }

    /**
     * Visit method for classes that will be called by PDepend during the
     * analysis phase with the current context class.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     * @since  0.10.2
     */
    public function visitClass(ASTClass $class)
    {
        $this->initDependencyMap($class);
        return parent::visitClass($class);
    }

    /**
     * Visit method for interfaces that will be called by PDepend during the
     * analysis phase with the current context interface.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     * @since  0.10.2
     */
    public function visitInterface(ASTInterface $interface)
    {
        $this->initDependencyMap($interface);
        return parent::visitInterface($interface);
    }

    /**
     * Visits a method node.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function visitMethod(ASTMethod $method)
    {
        $this->fireStartMethod($method);

        $declaringClass = $method->getParent();

        $this->calculateCoupling(
            $declaringClass,
            $method->getReturnClass()
        );

        foreach ($method->getExceptionClasses() as $type) {
            $this->calculateCoupling($declaringClass, $type);
        }
        foreach ($method->getDependencies() as $type) {
            $this->calculateCoupling($declaringClass, $type);
        }

        $this->countCalls($method);

        $this->fireEndMethod($method);
    }

    /**
     * Visits a property node.
     *
     * @param  \PDepend\Source\AST\ASTProperty $property
     * @return void
     */
    public function visitProperty(ASTProperty $property)
    {
        $this->fireStartProperty($property);

        $this->calculateCoupling(
            $property->getDeclaringClass(),
            $property->getClass()
        );

        $this->fireEndProperty($property);
    }

    /**
     * Calculates the coupling between the given types.
     *
     * @param  \PDepend\Source\AST\AbstractASTType $declaringType
     * @param  \PDepend\Source\AST\AbstractASTType $coupledType
     * @return void
     * @since  0.10.2
     */
    private function calculateCoupling(
        AbstractASTType $declaringType,
        AbstractASTType $coupledType = null
    ) {
        $this->initDependencyMap($declaringType);

        if (null === $coupledType) {
            return;
        }
        if ($coupledType->isSubtypeOf($declaringType)
            || $declaringType->isSubtypeOf($coupledType)
        ) {
            return;
        }

        $this->initDependencyMap($coupledType);

        $this->dependencyMap[
            $declaringType->getId()
        ]['ce'][
            $coupledType->getId()
        ] = true;

        $this->dependencyMap[
            $coupledType->getId()
        ]['ca'][
            $declaringType->getId()
        ] = true;
    }

    /**
     * This method will initialize a temporary coupling container for the given
     * given class or interface instance.
     *
     * @param  \PDepend\Source\AST\AbstractASTType $type
     * @return void
     * @since  0.10.2
     */
    private function initDependencyMap(AbstractASTType $type)
    {
        if (isset($this->dependencyMap[$type->getId()])) {
            return;
        }

        $this->dependencyMap[$type->getId()] = array(
            'ce' => array(),
            'ca' => array()
        );
    }

    /**
     * Counts all calls within the given <b>$callable</b>
     *
     * @param  \PDepend\Source\AST\AbstractASTCallable $callable
     * @return void
     */
    private function countCalls(AbstractASTCallable $callable)
    {
        $invocations = $callable->findChildrenOfType('PDepend\\Source\\AST\\ASTInvocation');

        $invoked = array();

        foreach ($invocations as $invocation) {
            $parents = $invocation->getParentsOfType('PDepend\\Source\\AST\\ASTMemberPrimaryPrefix');

            $image = '';
            foreach ($parents as $parent) {
                $child = $parent->getChild(0);
                if ($child !== $invocation) {
                    $image .= $child->getImage() . '.';
                }
            }
            $image .= $invocation->getImage() . '()';

            $invoked[$image] = $image;
        }

        $this->calls += count($invoked);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer\CodeRankAnalyzer;

use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Source\AST\AbstractASTClassOrInterface;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\ASTVisitor\AbstractASTVisitor;

/**
 * Collects class and namespace metrics based on inheritance.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class InheritanceStrategy extends AbstractASTVisitor implements CodeRankStrategyI
{
    /**
     * All found nodes.
     *
     * @var array(string=>array)
     */
    private $nodes = array();

    /**
     * Returns the collected nodes.
     *
     * @return array(string=>array)
     */
    public function getCollectedNodes()
    {
        return $this->nodes;
    }

    /**
     * Visits a code class object.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     */
    public function visitClass(ASTClass $class)
    {
        $this->fireStartClass($class);
        $this->visitType($class);
        $this->fireEndClass($class);
    }

    /**
     * Visits a code interface object.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function visitInterface(ASTInterface $interface)
    {
        $this->fireStartInterface($interface);
        $this->visitType($interface);
        $this->fireEndInterface($interface);
    }

    /**
     * Generic visitor method for classes and interfaces. Both visit methods
     * delegate calls to this method.
     *
     * @param  \PDepend\Source\AST\AbstractASTClassOrInterface $type
     * @return void
     */
    protected function visitType(AbstractASTClassOrInterface $type)
    {
        $namespace = $type->getNamespace();

        $this->initNode($namespace);
        $this->initNode($type);

        foreach ($type->getDependencies() as $dependency) {
            $depPkg = $dependency->getNamespace();

            $this->initNode($dependency);
            $this->initNode($depPkg);

            $this->nodes[$type->getId()]['in'][] = $dependency->getId();
            $this->nodes[$dependency->getId()]['out'][] = $type->getId();

            // No self references
            if ($namespace !== $depPkg) {
                $this->nodes[$namespace->getId()]['in'][]     = $depPkg->getId();
                $this->nodes[$depPkg->getId()]['out'][] = $namespace->getId();
            }
        }
    }

    /**
     * Initializes the temporary node container for the given <b>$node</b>.
     *
     * @param  \PDepend\Source\AST\AbstractASTArtifact $node
     * @return void
     */
    protected function initNode(AbstractASTArtifact $node)
    {
        if (!isset($this->nodes[$node->getId()])) {
            $this->nodes[$node->getId()] = array(
                'in'    =>  array(),
                'out'   =>  array(),
                'name'  =>  $node->getName(),
                'type'  =>  get_class($node)
            );
        }
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer\CodeRankAnalyzer;

use PDepend\Source\ASTVisitor\ASTVisitor;

/**
 * The code rank strategy provides an interface for dependency collection.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface CodeRankStrategyI extends ASTVisitor
{
    /**
     * Returns the collected nodes.
     *
     * @return array(string=>array)
     */
    public function getCollectedNodes();
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer\CodeRankAnalyzer;

use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Source\AST\ASTProperty;
use PDepend\Source\ASTVisitor\AbstractASTVisitor;

/**
 * Collects class and namespace metrics based on class properties.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class PropertyStrategy extends AbstractASTVisitor implements CodeRankStrategyI
{
    /**
     * All found nodes.
     *
     * @var array(string=>array)
     */
    private $nodes = array();

    /**
     * Returns the collected nodes.
     *
     * @return array(string=>array)
     */
    public function getCollectedNodes()
    {
        return $this->nodes;
    }

    /**
     * Visits a property node.
     *
     * @param  \PDepend\Source\AST\ASTProperty $property
     * @return void
     */
    public function visitProperty(ASTProperty $property)
    {
        $this->fireStartProperty($property);

        if (($depClass = $property->getClass()) === null) {
            $this->fireEndProperty($property);
            return;
        }

        $depNamespace = $depClass->getNamespace();

        $class = $property->getDeclaringClass();
        $namespace = $class->getNamespace();

        if ($depClass !== $class) {
            $this->initNode($class);
            $this->initNode($depClass);

            $this->nodes[$class->getId()]['in'][]     = $depClass->getId();
            $this->nodes[$depClass->getId()]['out'][] = $class->getId();
        }

        if ($depNamespace !== $namespace) {
            $this->initNode($namespace);
            $this->initNode($depNamespace);

            $this->nodes[$namespace->getId()]['in'][]     = $depNamespace->getId();
            $this->nodes[$depNamespace->getId()]['out'][] = $namespace->getId();
        }

        $this->fireEndProperty($property);
    }

    /**
     * Initializes the temporary node container for the given <b>$node</b>.
     *
     * @param  \PDepend\Source\AST\AbstractASTArtifact $node
     * @return void
     */
    protected function initNode(AbstractASTArtifact $node)
    {
        if (!isset($this->nodes[$node->getId()])) {
            $this->nodes[$node->getId()] = array(
                'in'   =>  array(),
                'out'  =>  array(),
                'name'  =>  $node->getName(),
                'type'  =>  get_class($node)
            );
        }
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer\CodeRankAnalyzer;

/**
 * Factory for the different code rank strategies.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class StrategyFactory
{
    /**
     * The identifier for the inheritance strategy.
     */
    const STRATEGY_INHERITANCE = 'inheritance';

    /**
     * The identifier for the property strategy.
     */
    const STRATEGY_PROPERTY = 'property';

    /**
     * The identifier for the method strategy.
     */
    const STRATEGY_METHOD = 'method';

    /**
     * The default strategy.
     *
     * @var string
     */
    private $defaultStrategy = self::STRATEGY_INHERITANCE;

    /**
     * List of all valid properties.
     *
     * @var array(string)
     */
    private $validStrategies = array(
        self::STRATEGY_INHERITANCE,
        self::STRATEGY_METHOD,
        self::STRATEGY_PROPERTY
    );

    /**
     * Creates the default code rank strategy.
     *
     * @return \PDepend\Metrics\Analyzer\CodeRankAnalyzer\CodeRankStrategyI
     */
    public function createDefaultStrategy()
    {
        return $this->createStrategy($this->defaultStrategy);
    }

    /**
     * Creates a code rank strategy for the given identifier.
     *
     * @param  string $strategyName The strategy identifier.
     * @return \PDepend\Metrics\Analyzer\CodeRankAnalyzer\CodeRankStrategyI
     * @throws \InvalidArgumentException If the given <b>$id</b> is not valid or
     *                                  no matching class declaration exists.
     */
    public function createStrategy($strategyName)
    {
        if (in_array($strategyName, $this->validStrategies) === false) {
            throw new \InvalidArgumentException(
                sprintf('Cannot load file for identifier "%s".', $strategyName)
            );
        }

        // Prepare identifier
        $name = ucfirst(strtolower($strategyName));

        $className = "PDepend\\Metrics\\Analyzer\\CodeRankAnalyzer\\{$name}Strategy";

        if (false === class_exists($className)) {
            $fileName = "PDepend/Metrics/Analyzer/CodeRankAnalyzer/{$name}Strategy.php";

            include_once $fileName;
        }

        return new $className();
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer\CodeRankAnalyzer;

use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Source\AST\AbstractASTClassOrInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\ASTVisitor\AbstractASTVisitor;

/**
 * Collects class and namespace metrics based on class and interface methods.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class MethodStrategy extends AbstractASTVisitor implements CodeRankStrategyI
{
    /**
     * All found nodes.
     *
     * @var array(string=>array)
     */
    private $nodes = array();

    /**
     * Returns the collected nodes.
     *
     * @return array(string=>array)
     */
    public function getCollectedNodes()
    {
        return $this->nodes;
    }

    /**
     * Visits a method node.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function visitMethod(ASTMethod $method)
    {
        $this->fireStartMethod($method);

        // Get owner type
        $type = $method->getParent();

        if (($depType = $method->getReturnClass()) !== null) {
            $this->processType($type, $depType);
        }
        foreach ($method->getExceptionClasses() as $depType) {
            $this->processType($type, $depType);
        }
        foreach ($method->getDependencies() as $depType) {
            $this->processType($type, $depType);
        }

        $this->fireEndMethod($method);
    }

    /**
     * Extracts the coupling information between the two given types and their
     * parent namespacess.
     *
     * @param  \PDepend\Source\AST\AbstractASTClassOrInterface $type
     * @param  \PDepend\Source\AST\AbstractASTClassOrInterface $dependency
     * @return void
     */
    private function processType(AbstractASTClassOrInterface $type, AbstractASTClassOrInterface $dependency)
    {
        if ($type !== $dependency) {
            $this->initNode($type);
            $this->initNode($dependency);

            $this->nodes[$type->getId()]['in'][] = $dependency->getId();
            $this->nodes[$dependency->getId()]['out'][] = $type->getId();
        }

        $namespace = $type->getNamespace();
        $dependencyNamespace = $dependency->getNamespace();

        if ($namespace !== $dependencyNamespace) {
            $this->initNode($namespace);
            $this->initNode($dependencyNamespace);

            $this->nodes[$namespace->getId()]['in'][] = $dependencyNamespace->getId();
            $this->nodes[$dependencyNamespace->getId()]['out'][] = $namespace->getId();
        }
    }

    /**
     * Initializes the temporary node container for the given <b>$node</b>.
     *
     * @param  \PDepend\Source\AST\AbstractASTArtifact $node
     * @return void
     */
    private function initNode(AbstractASTArtifact $node)
    {
        if (!isset($this->nodes[$node->getId()])) {
            $this->nodes[$node->getId()] = array(
                'in'   =>  array(),
                'out'  =>  array(),
                'name'  =>  $node->getName(),
                'type'  =>  get_class($node)
            );
        }
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer;

use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Metrics\AggregateAnalyzer;
use PDepend\Metrics\Analyzer;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Source\AST\AbstractASTCallable;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTMethod;

/**
 * This analyzer calculates the C.R.A.P. index for methods an functions when a
 * clover coverage report was supplied. This report can be supplied by using the
 * command line option <b>--coverage-report=</b>.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class CrapIndexAnalyzer extends AbstractAnalyzer implements AggregateAnalyzer, AnalyzerNodeAware
{
    /**
     * Metrics provided by the analyzer implementation.
     */
    const M_CRAP_INDEX = 'crap',
          M_COVERAGE = 'cov';

    /**
     * The report option name.
     */
    const REPORT_OPTION = 'coverage-report';

    /**
     * Calculated crap metrics.
     *
     * @var array(string=>array)
     */
    private $metrics = null;

    /**
     * The coverage report instance representing the supplied coverage report
     * file.
     *
     * @var \PDepend\Util\Coverage\Report
     */
    private $report = null;

    /**
     *
     * @var \PDepend\Metrics\Analyzer\CyclomaticComplexityAnalyzer
     */
    private $ccnAnalyzer = array();

    /**
     * Returns <b>true</b> when this analyzer is enabled.
     *
     * @return boolean
     */
    public function isEnabled()
    {
        return isset($this->options[self::REPORT_OPTION]);
    }

    /**
     * Returns the calculated metrics for the given node or an empty <b>array</b>
     * when no metrics exist for the given node.
     *
     * @param  \PDepend\Source\AST\ASTArtifact $artifact
     * @return array(string=>float)
     */
    public function getNodeMetrics(ASTArtifact $artifact)
    {
        if (isset($this->metrics[$artifact->getId()])) {
            return $this->metrics[$artifact->getId()];
        }
        return array();
    }

    /**
     * Returns an array with analyzer class names that are required by the crap
     * index analyzers.
     *
     * @return array(string)
     */
    public function getRequiredAnalyzers()
    {
        return array('PDepend\\Metrics\\Analyzer\\CyclomaticComplexityAnalyzer');
    }

    /**
     * Adds an analyzer that this analyzer depends on.
     *
     * @param  \PDepend\Metrics\Analyzer $analyzer
     * @return void
     */
    public function addAnalyzer(Analyzer $analyzer)
    {
        $this->ccnAnalyzer = $analyzer;
    }

    /**
     * Performs the crap index analysis.
     *
     * @param  \PDepend\Source\AST\ASTNamespace[] $namespaces
     * @return void
     */
    public function analyze($namespaces)
    {
        if ($this->isEnabled() && $this->metrics === null) {
            $this->doAnalyze($namespaces);
        }
    }

    /**
     * Performs the crap index analysis.
     *
     * @param  \PDepend\Source\AST\ASTNamespace[] $namespaces
     * @return void
     */
    private function doAnalyze($namespaces)
    {
        $this->metrics = array();
        
        $this->ccnAnalyzer->analyze($namespaces);

        $this->fireStartAnalyzer();

        foreach ($namespaces as $namespace) {
            $namespace->accept($this);
        }

        $this->fireEndAnalyzer();
    }

    /**
     * Visits the given method.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function visitMethod(ASTMethod $method)
    {
        if ($method->isAbstract() === false) {
            $this->visitCallable($method);
        }
    }

    /**
     * Visits the given function.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     */
    public function visitFunction(ASTFunction $function)
    {
        $this->visitCallable($function);
    }

    /**
     * Visits the given callable instance.
     *
     * @param  \PDepend\Source\AST\AbstractASTCallable $callable
     * @return void
     */
    private function visitCallable(AbstractASTCallable $callable)
    {
        $this->metrics[$callable->getId()] = array(
            self::M_CRAP_INDEX => $this->calculateCrapIndex($callable),
            self::M_COVERAGE   => $this->calculateCoverage($callable)
        );
    }

    /**
     * Calculates the crap index for the given callable.
     *
     * @param  \PDepend\Source\AST\AbstractASTCallable $callable
     * @return float
     */
    private function calculateCrapIndex(AbstractASTCallable $callable)
    {
        $report = $this->createOrReturnCoverageReport();

        $complexity = $this->ccnAnalyzer->getCcn2($callable);
        $coverage   = $report->getCoverage($callable);

        if ($coverage == 0) {
            return pow($complexity, 2) + $complexity;
        } elseif ($coverage > 99.5) {
            return $complexity;
        }
        return pow($complexity, 2) * pow(1 - $coverage / 100, 3) + $complexity;
    }

    /**
     * Calculates the code coverage for the given callable object.
     *
     * @param  \PDepend\Source\AST\AbstractASTCallable $callable
     * @return float
     */
    private function calculateCoverage(AbstractASTCallable $callable)
    {
        return $this->createOrReturnCoverageReport()->getCoverage($callable);
    }

    /**
     * Returns a previously created report instance or creates a new report
     * instance.
     *
     * @return \PDepend\Util\Coverage\Report
     */
    private function createOrReturnCoverageReport()
    {
        if ($this->report === null) {
            $this->report = $this->createCoverageReport();
        }
        return $this->report;
    }

    /**
     * Creates a new coverage report instance.
     *
     * @return \PDepend\Util\Coverage\Report
     */
    private function createCoverageReport()
    {
        $factory = new \PDepend\Util\Coverage\Factory();
        return $factory->create($this->options['coverage-report']);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer;

use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Source\AST\AbstractASTClassOrInterface;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;

/**
 * This visitor generates the metrics for the analyzed namespaces.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ClassDependencyAnalyzer extends AbstractAnalyzer
{
    /**
     * Metrics provided by the analyzer implementation.
     */
    const M_AFFERENT_COUPLING          = 'ca',
          M_EFFERENT_COUPLING          = 'ce';

    /**
     * Hash with all calculated node metrics.
     *
     * <code>
     * array(
     *     '0375e305-885a-4e91-8b5c-e25bda005438'  =>  array(
     *         'loc'    =>  42,
     *         'ncloc'  =>  17,
     *         'cc'     =>  12
     *     ),
     *     'e60c22f0-1a63-4c40-893e-ed3b35b84d0b'  =>  array(
     *         'loc'    =>  42,
     *         'ncloc'  =>  17,
     *         'cc'     =>  12
     *     )
     * )
     * </code>
     *
     * @var array(string=>array)
     */
    private $nodeMetrics = null;

    protected $nodeSet = array();

    private $efferentNodes = array();

    private $afferentNodes = array();

    /**
     * All collected cycles for the input code.
     *
     * <code>
     * array(
     *     <type-id> => array(
     *         \PDepend\Source\AST\AbstractASTClassOrInterface {},
     *         \PDepend\Source\AST\AbstractASTClassOrInterface {},
     *     ),
     *     <type-id> => array(
     *         \PDepend\Source\AST\AbstractASTClassOrInterface {},
     *         \PDepend\Source\AST\AbstractASTClassOrInterface {},
     *     ),
     * )
     * </code>
     *
     * @var array(string=>array)
     */
    private $collectedCycles = array();

    /**
     * Processes all {@link \PDepend\Source\AST\ASTNamespace} code nodes.
     *
     * @param  \PDepend\Source\AST\ASTNamespace[] $namespaces
     * @return void
     */
    public function analyze($namespaces)
    {
        if ($this->nodeMetrics === null) {
            $this->fireStartAnalyzer();

            $this->nodeMetrics = array();

            foreach ($namespaces as $namespace) {
                $namespace->accept($this);
            }

            $this->postProcess();

            $this->fireEndAnalyzer();
        }
    }

    /**
     * Returns an array of all afferent nodes.
     *
     * @param  \PDepend\Source\AST\AbstractASTArtifact $node
     * @return \PDepend\Source\AST\AbstractASTArtifact[]
     */
    public function getAfferents(AbstractASTArtifact $node)
    {
        $afferents = array();
        if (isset($this->afferentNodes[$node->getId()])) {
            $afferents = $this->afferentNodes[$node->getId()];
        }
        return $afferents;
    }

    /**
     * Returns an array of all efferent nodes.
     *
     * @param  \PDepend\Source\AST\AbstractASTArtifact $node
     * @return \PDepend\Source\AST\AbstractASTArtifact[]
     */
    public function getEfferents(AbstractASTArtifact $node)
    {
        $efferents = array();
        if (isset($this->efferentNodes[$node->getId()])) {
            $efferents = $this->efferentNodes[$node->getId()];
        }
        return $efferents;
    }

    /**
     * Visits a method node.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function visitMethod(ASTMethod $method)
    {
        $this->fireStartMethod($method);

        $type = $method->getParent();
        foreach ($method->getDependencies() as $dependency) {
            $this->collectDependencies($type, $dependency);
        }

        $this->fireEndMethod($method);
    }

    /**
     * Visits a namespace node.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespace
     * @return void
     */
    public function visitNamespace(ASTNamespace $namespace)
    {
        $this->fireStartNamespace($namespace);

        $this->nodeSet[$namespace->getId()] = $namespace;

        foreach ($namespace->getTypes() as $type) {
            $type->accept($this);
        }

        $this->fireEndNamespace($namespace);
    }

    /**
     * Visits a class node.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     */
    public function visitClass(ASTClass $class)
    {
        $this->fireStartClass($class);
        $this->visitType($class);
        $this->fireEndClass($class);
    }

    /**
     * Visits an interface node.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function visitInterface(ASTInterface $interface)
    {
        $this->fireStartInterface($interface);
        $this->visitType($interface);
        $this->fireEndInterface($interface);
    }

    /**
     * Generic visit method for classes and interfaces. Both visit methods
     * delegate calls to this method.
     *
     * @param  \PDepend\Source\AST\AbstractASTClassOrInterface $type
     * @return void
     */
    protected function visitType(AbstractASTClassOrInterface $type)
    {
        $id = $type->getId();

        foreach ($type->getDependencies() as $dependency) {
            $this->collectDependencies($type, $dependency);
        }

        foreach ($type->getMethods() as $method) {
            $method->accept($this);
        }
    }

    /**
     * Collects the dependencies between the two given classes.
     *
     * @param \PDepend\Source\AST\AbstractASTClassOrInterface $typeB
     * @param \PDepend\Source\AST\AbstractASTClassOrInterface $typeB
     *
     * @return void
     */
    private function collectDependencies(AbstractASTClassOrInterface $typeA, AbstractASTClassOrInterface $typeB)
    {
        $idA = $typeA->getId();
        $idB = $typeB->getId();

        if ($idB === $idA) {
            return;
        }

        // Create a container for this dependency
        $this->initTypeMetric($typeA);
        $this->initTypeMetric($typeB);

        if (!in_array($idB, $this->nodeMetrics[$idA][self::M_EFFERENT_COUPLING])) {
            $this->nodeMetrics[$idA][self::M_EFFERENT_COUPLING][] = $idB;
            $this->nodeMetrics[$idB][self::M_AFFERENT_COUPLING][] = $idA;
        }
    }

    /**
     * Initializes the node metric record for the given <b>$type</b>.
     *
     * @param \PDepend\Source\AST\AbstractASTClassOrInterface $type
     * @return void
     */
    protected function initTypeMetric(AbstractASTClassOrInterface $type)
    {
        $id = $type->getId();

        if (!isset($this->nodeMetrics[$id])) {
            $this->nodeSet[$id] = $type;

            $this->nodeMetrics[$id] = array(
                self::M_AFFERENT_COUPLING =>  array(),
                self::M_EFFERENT_COUPLING =>  array(),
            );
        }
    }

    /**
     * Post processes all analyzed nodes.
     *
     * @return void
     */
    protected function postProcess()
    {
        foreach ($this->nodeMetrics as $id => $metrics) {
            $this->afferentNodes[$id] = array();
            foreach ($metrics[self::M_AFFERENT_COUPLING] as $caId) {
                $this->afferentNodes[$id][] = $this->nodeSet[$caId];
            }

            $this->efferentNodes[$id] = array();
            foreach ($metrics[self::M_EFFERENT_COUPLING] as $ceId) {
                $this->efferentNodes[$id][] = $this->nodeSet[$ceId];
            }

            $afferent = count($metrics[self::M_AFFERENT_COUPLING]);
            $efferent = count($metrics[self::M_EFFERENT_COUPLING]);

            $this->nodeMetrics[$id][self::M_AFFERENT_COUPLING] = $afferent;
            $this->nodeMetrics[$id][self::M_EFFERENT_COUPLING] = $efferent;
        }
    }

    /**
     * Collects a single cycle that is reachable by this namespace. All namespaces
     * that are part of the cylce are stored in the given <b>$list</b> array.
     *
     * @param  \PDepend\Source\AST\AbstractASTArtifact[] &$list
     * @param  \PDepend\Source\AST\AbstractASTArtifact   $namespace
     * @return boolean If this method detects a cycle the return value is <b>true</b>
     *                 otherwise this method will return <b>false</b>.
     */
    protected function collectCycle(array &$list, AbstractASTArtifact $node)
    {
        if (in_array($node, $list, true)) {
            $list[] = $node;
            return true;
        }

        $list[] = $node;

        foreach ($this->getEfferents($node) as $efferent) {
            if ($this->collectCycle($list, $efferent)) {
                return true;
            }
        }

        if (is_int($idx = array_search($node, $list, true))) {
            unset($list[$idx]);
        }
        return false;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer;

use PDepend\Metrics\AbstractCachingAnalyzer;
use PDepend\Metrics\AnalyzerFilterAware;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Source\AST\AbstractASTCallable;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTBooleanAndExpression;
use PDepend\Source\AST\ASTBooleanOrExpression;
use PDepend\Source\AST\ASTConditionalExpression;
use PDepend\Source\AST\ASTExpression;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTLogicalAndExpression;
use PDepend\Source\AST\ASTLogicalOrExpression;
use PDepend\Source\AST\ASTLogicalXorExpression;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTStatement;
use PDepend\Source\AST\ASTSwitchLabel;
use PDepend\Util\MathUtil;

/**
 * This analyzer calculates the NPath complexity of functions and methods. The
 * NPath complexity metric measures the acyclic execution paths through a method
 * or function. See Nejmeh, Communications of the ACM Feb 1988 pp 188-200.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class NPathComplexityAnalyzer extends AbstractCachingAnalyzer implements AnalyzerFilterAware, AnalyzerNodeAware
{
    /**
     * Metrics provided by the analyzer implementation.
     */
    const M_NPATH_COMPLEXITY = 'npath';

    /**
     * Processes all {@link \PDepend\Source\AST\ASTNamespace} code nodes.
     *
     * @param  \PDepend\Source\AST\ASTNamespace[] $namespaces
     * @return void
     */
    public function analyze($namespaces)
    {
        if ($this->metrics === null) {
            $this->loadCache();
            $this->fireStartAnalyzer();

            $this->metrics = array();
            foreach ($namespaces as $namespace) {
                $namespace->accept($this);
            }

            $this->fireEndAnalyzer();
            $this->unloadCache();
        }
    }

    /**
     * This method will return an <b>array</b> with all generated metric values
     * for the node with the given <b>$id</b> identifier. If there are no
     * metrics for the requested node, this method will return an empty <b>array</b>.
     *
     * <code>
     * array(
     *     'npath'  =>  '17'
     * )
     * </code>
     *
     * @param  \PDepend\Source\AST\ASTArtifact $artifact
     * @return array
     */
    public function getNodeMetrics(ASTArtifact $artifact)
    {
        $metric = array();
        if (isset($this->metrics[$artifact->getId()])) {
            $metric = array(self::M_NPATH_COMPLEXITY  =>  $this->metrics[$artifact->getId()]);
        }
        return $metric;
    }

    /**
     * Visits a code interface object.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function visitInterface(ASTInterface $interface)
    {
        // Empty visit method, we don't want interface metrics
    }

    /**
     * Visits a function node.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     */
    public function visitFunction(ASTFunction $function)
    {
        $this->fireStartFunction($function);

        if (false === $this->restoreFromCache($function)) {
            $this->calculateComplexity($function);
        }

        $this->fireEndFunction($function);
    }

    /**
     * Visits a method node.
     *
     * @param \PDepend\Source\AST\ASTMethod $method
     *
     * @return void
     */
    public function visitMethod(ASTMethod $method)
    {
        $this->fireStartMethod($method);

        if (false === $this->restoreFromCache($method)) {
            $this->calculateComplexity($method);
        }

        $this->fireEndMethod($method);
    }

    /**
     * This method will calculate the NPath complexity for the given callable
     * instance.
     *
     * @param  \PDepend\Source\AST\AbstractASTCallable $callable
     * @return void
     * @since  0.9.12
     */
    protected function calculateComplexity(AbstractASTCallable $callable)
    {
        $npath = '1';
        foreach ($callable->getChildren() as $child) {
            $stmt  = $child->accept($this, $npath);
            $npath = MathUtil::mul($npath, $stmt);
        }

        $this->metrics[$callable->getId()] = $npath;
    }

    /**
     * This method calculates the NPath Complexity of a conditional-statement,
     * the meassured value is then returned as a string.
     *
     * <code>
     * <expr1> ? <expr2> : <expr3>
     *
     * -- NP(?) = NP(<expr1>) + NP(<expr2>) + NP(<expr3>) + 2 --
     * </code>
     *
     * @param  \PDepend\Source\AST\ASTNode
     * @param  string                      $data
     * @return string
     * @since  0.9.12
     */
    public function visitConditionalExpression($node, $data)
    {
        // Calculate the complexity of the condition
        $parent = $node->getParent()->getChild(0);
        $npath = $this->sumComplexity($parent);
        
        // New PHP 5.3 ifsetor-operator $x ?: $y
        if (count($node->getChildren()) === 1) {
            $npath = MathUtil::mul($npath, '2');
        }

        // The complexity of each child has no minimum
        foreach ($node->getChildren() as $child) {
            $cn = $this->sumComplexity($child);
            $npath = MathUtil::add($npath, $cn);
        }

        // Add 2 for the branching per the NPath spec
        $npath = MathUtil::add($npath, '2');
        
        return MathUtil::mul($npath, $data);
    }

    /**
     * This method calculates the NPath Complexity of a do-while-statement, the
     * meassured value is then returned as a string.
     *
     * <code>
     * do
     *   <do-range>
     * while (<expr>)
     * S;
     *
     * -- NP(do) = NP(<do-range>) + NP(<expr>) + 1 --
     * </code>
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param string                      $data The previously calculated npath value.
     *
     * @return string
     * @since  0.9.12
     */
    public function visitDoWhileStatement($node, $data)
    {
        $stmt = $node->getChild(0)->accept($this, 1);
        $expr = $this->sumComplexity($node->getChild(1));

        $npath = MathUtil::add($expr, $stmt);
        $npath = MathUtil::add($npath, '1');

        return MathUtil::mul($npath, $data);
    }

    /**
     * This method calculates the NPath Complexity of an elseif-statement, the
     * meassured value is then returned as a string.
     *
     * <code>
     * elseif (<expr>)
     *   <elseif-range>
     * S;
     *
     * -- NP(elseif) = NP(<elseif-range>) + NP(<expr>) + 1 --
     *
     *
     * elseif (<expr>)
     *   <elseif-range>
     * else
     *   <else-range>
     * S;
     *
     * -- NP(if) = NP(<if-range>) + NP(<expr>) + NP(<else-range> --
     * </code>
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param string                      $data The previously calculated npath value.
     *
     * @return string
     * @since  0.9.12
     */
    public function visitElseIfStatement($node, $data)
    {
        $npath = $this->sumComplexity($node->getChild(0));
        foreach ($node->getChildren() as $child) {
            if ($child instanceof ASTStatement) {
                $expr  = $child->accept($this, 1);
                $npath = MathUtil::add($npath, $expr);
            }
        }

        if (!$node->hasElse()) {
            $npath = MathUtil::add($npath, '1');
        }

        return MathUtil::mul($npath, $data);
    }

    /**
     * This method calculates the NPath Complexity of a for-statement, the
     * meassured value is then returned as a string.
     *
     * <code>
     * for (<expr1>; <expr2>; <expr3>)
     *   <for-range>
     * S;
     *
     * -- NP(for) = NP(<for-range>) + NP(<expr1>) + NP(<expr2>) + NP(<expr3>) + 1 --
     * </code>
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param string                      $data The previously calculated npath value.
     *
     * @return string
     * @since  0.9.12
     */
    public function visitForStatement($node, $data)
    {
        $npath = '1';
        foreach ($node->getChildren() as $child) {
            if ($child instanceof ASTStatement) {
                $stmt  = $child->accept($this, 1);
                $npath = MathUtil::add($npath, $stmt);
            } elseif ($child instanceof ASTExpression) {
                $expr  = $this->sumComplexity($child);
                $npath = MathUtil::add($npath, $expr);
            }
        }

        return MathUtil::mul($npath, $data);
    }

    /**
     * This method calculates the NPath Complexity of a for-statement, the
     * meassured value is then returned as a string.
     *
     * <code>
     * fpreach (<expr>)
     *   <foreach-range>
     * S;
     *
     * -- NP(foreach) = NP(<foreach-range>) + NP(<expr>) + 1 --
     * </code>
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param string                      $data The previously calculated npath value.
     *
     * @return string
     * @since  0.9.12
     */
    public function visitForeachStatement($node, $data)
    {
        $npath = $this->sumComplexity($node->getChild(0));
        $npath = MathUtil::add($npath, '1');

        foreach ($node->getChildren() as $child) {
            if ($child instanceof ASTStatement) {
                $stmt  = $child->accept($this, 1);
                $npath = MathUtil::add($npath, $stmt);
            }
        }

        return MathUtil::mul($npath, $data);
    }

    /**
     * This method calculates the NPath Complexity of an if-statement, the
     * meassured value is then returned as a string.
     *
     * <code>
     * if (<expr>)
     *   <if-range>
     * S;
     *
     * -- NP(if) = NP(<if-range>) + NP(<expr>) + 1 --
     *
     *
     * if (<expr>)
     *   <if-range>
     * else
     *   <else-range>
     * S;
     *
     * -- NP(if) = NP(<if-range>) + NP(<expr>) + NP(<else-range> --
     * </code>
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param string                      $data The previously calculated npath value.
     *
     * @return string
     * @since  0.9.12
     */
    public function visitIfStatement($node, $data)
    {
        $npath = $this->sumComplexity($node->getChild(0));

        foreach ($node->getChildren() as $child) {
            if ($child instanceof ASTStatement) {
                $stmt  = $child->accept($this, 1);
                $npath = MathUtil::add($npath, $stmt);
            }
        }

        if (!$node->hasElse()) {
            $npath = MathUtil::add($npath, '1');
        }

        return MathUtil::mul($npath, $data);
    }

    /**
     * This method calculates the NPath Complexity of a return-statement, the
     * meassured value is then returned as a string.
     *
     * <code>
     * return <expr>;
     *
     * -- NP(return) = NP(<expr>) --
     * </code>
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param string                      $data The previously calculated npath value.
     *
     * @return string
     * @since  0.9.12
     */
    public function visitReturnStatement($node, $data)
    {
        if (($npath = $this->sumComplexity($node)) === '0') {
            return $data;
        }
        return MathUtil::mul($npath, $data);
    }

    /**
     * This method calculates the NPath Complexity of a switch-statement, the
     * meassured value is then returned as a string.
     *
     * <code>
     * switch (<expr>)
     *   <case-range1>
     *   <case-range2>
     *   ...
     *   <default-range>
     *
     * -- NP(switch) = NP(<expr>) + NP(<default-range>) +  NP(<case-range1>) ... --
     * </code>
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param string                      $data The previously calculated npath value.
     *
     * @return string
     * @since  0.9.12
     */
    public function visitSwitchStatement($node, $data)
    {
        $npath = $this->sumComplexity($node->getChild(0));
        foreach ($node->getChildren() as $child) {
            if ($child instanceof ASTSwitchLabel) {
                $label = $child->accept($this, 1);
                $npath = MathUtil::add($npath, $label);
            }
        }
        return MathUtil::mul($npath, $data);
    }

    /**
     * This method calculates the NPath Complexity of a try-catch-statement, the
     * meassured value is then returned as a string.
     *
     * <code>
     * try
     *   <try-range>
     * catch
     *   <catch-range>
     *
     * -- NP(try) = NP(<try-range>) + NP(<catch-range>) --
     *
     *
     * try
     *   <try-range>
     * catch
     *   <catch-range1>
     * catch
     *   <catch-range2>
     * ...
     *
     * -- NP(try) = NP(<try-range>) + NP(<catch-range1>) + NP(<catch-range2>) ... --
     * </code>
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param string                      $data The previously calculated npath value.
     *
     * @return string
     * @since  0.9.12
     */
    public function visitTryStatement($node, $data)
    {
        $npath = '0';
        foreach ($node->getChildren() as $child) {
            if ($child instanceof ASTStatement) {
                $stmt  = $child->accept($this, 1);
                $npath = MathUtil::add($npath, $stmt);
            }
        }
        return MathUtil::mul($npath, $data);
    }

    /**
     * This method calculates the NPath Complexity of a while-statement, the
     * meassured value is then returned as a string.
     *
     * <code>
     * while (<expr>)
     *   <while-range>
     * S;
     *
     * -- NP(while) = NP(<while-range>) + NP(<expr>) + 1 --
     * </code>
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param string                      $data The previously calculated npath value.
     *
     * @return string
     * @since  0.9.12
     */
    public function visitWhileStatement($node, $data)
    {
        $expr = $this->sumComplexity($node->getChild(0));
        $stmt = $node->getChild(1)->accept($this, 1);

        $npath = MathUtil::add($expr, $stmt);
        $npath = MathUtil::add($npath, '1');

        return MathUtil::mul($npath, $data);
    }

    /**
     * Calculates the expression sum of the given node.
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     *
     * @return string
     * @since  0.9.12
     * @todo   I don't like this method implementation, it should be possible to
     *       implement this method with more visitor behavior for the boolean
     *       and logical expressions.
     */
    public function sumComplexity($node)
    {
        $sum = '0';
        if ($node instanceof ASTConditionalExpression) {
            $sum = MathUtil::add($sum, $node->accept($this, 1));
        } elseif ($node instanceof ASTBooleanAndExpression
            || $node instanceof ASTBooleanOrExpression
            || $node instanceof ASTLogicalAndExpression
            || $node instanceof ASTLogicalOrExpression
            || $node instanceof ASTLogicalXorExpression
        ) {
            $sum = MathUtil::add($sum, '1');
        } else {
            foreach ($node->getChildren() as $child) {
                $expr = $this->sumComplexity($child);
                $sum  = MathUtil::add($sum, $expr);
            }
        }
        return $sum;
    }
}
<?php

/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2015, Matthias Mullie <pdepend@mullie.eu>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2015 Matthias Mullie. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer;

use PDepend\Metrics\AbstractCachingAnalyzer;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Source\AST\AbstractASTCallable;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\Tokenizer\Tokens;

/**
 * This class calculates the Halstead Complexity Measures for the project,
 * methods and functions.
 *
 * @copyright 2015 Matthias Mullie. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class HalsteadAnalyzer extends AbstractCachingAnalyzer implements AnalyzerNodeAware
{
    /**
     * Metrics provided by the analyzer implementation.
     */
    const M_HALSTEAD_LENGTH = 'hnt', // N = N1 + N2 (total operators + operands)
          M_HALSTEAD_VOCABULARY = 'hnd', // n = n1 + n2 (distinct operators + operands)
          M_HALSTEAD_VOLUME = 'hv', // V = N * log2(n)
          M_HALSTEAD_DIFFICULTY = 'hd', // D = (n1 / 2) * (N2 / n2)
          M_HALSTEAD_LEVEL = 'hl', // L = 1 / D
          M_HALSTEAD_EFFORT = 'he', // E = V * D
          M_HALSTEAD_TIME = 'ht', // T = E / 18
          M_HALSTEAD_BUGS = 'hb', // B = (E ** (2/3)) / 3000
          M_HALSTEAD_CONTENT = 'hi'; // I = (V / D)

    /**
     * Processes all {@link \PDepend\Source\AST\ASTNamespace} code nodes.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespaces
     * @return void
     */
    public function analyze($namespaces)
    {
        if ($this->metrics === null) {
            $this->loadCache();
            $this->fireStartAnalyzer();

            // Init node metrics
            $this->metrics = array();

            foreach ($namespaces as $namespace) {
                $namespace->accept($this);
            }

            $this->fireEndAnalyzer();
            $this->unloadCache();
        }
    }

    /**
     * This method will return an <b>array</b> with all generated basis metrics
     * for the given <b>$node</b> (n1, n2, N1, N2). If there are no metrics for
     * the requested node, this method will return an empty <b>array</b>.
     *
     * @param \PDepend\Source\AST\ASTArtifact $artifact
     * @return array
     */
    public function getNodeBasisMetrics(ASTArtifact $artifact)
    {
        if (isset($this->metrics[$artifact->getId()])) {
            return $this->metrics[$artifact->getId()];
        }

        return array();
    }

    /**
     * This method will return an <b>array</b> with all generated metric values
     * for the given <b>$node</b>. If there are no metrics for the requested
     * node, this method will return an empty <b>array</b>.
     *
     * @param \PDepend\Source\AST\ASTArtifact $artifact
     * @return array
     */
    public function getNodeMetrics(ASTArtifact $artifact)
    {
        $basis = $this->getNodeBasisMetrics($artifact);
        if ($basis) {
            return $this->calculateHalsteadMeasures($basis);
        }

        return array();
    }

    /**
     * Visits a function node.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     */
    public function visitFunction(ASTFunction $function)
    {
        $this->fireStartFunction($function);

        if (false === $this->restoreFromCache($function)) {
            $this->calculateHalsteadBasis($function);
        }

        $this->fireEndFunction($function);
    }

    /**
     * Visits a code interface object.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function visitInterface(ASTInterface $interface)
    {
        // Empty visit method, we don't want interface metrics
    }

    /**
     * Visits a method node.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function visitMethod(ASTMethod $method)
    {
        $this->fireStartMethod($method);

        if (false === $this->restoreFromCache($method)) {
            $this->calculateHalsteadBasis($method);
        }

        $this->fireEndMethod($method);
    }

    /**
     * @see http://www.scribd.com/doc/99533/Halstead-s-Operators-and-Operands-in-C-C-JAVA-by-Indranil-Nandy
     *
     * @param  \PDepend\Source\AST\AbstractASTCallable $callable
     * @return void
     */
    public function calculateHalsteadBasis(AbstractASTCallable $callable)
    {
        $operators = array();
        $operands = array();

        $skipUntil = null;

        $tokens = $callable->getTokens();
        foreach ($tokens as $i => $token) {
            /*
             * Some operations should be ignored, e.g. function declarations.
             * When we encounter a new function, we'll skip all tokens until we
             * find the closing token.
             */
            if ($skipUntil !== null) {
                if ($token->type === $skipUntil) {
                    $skipUntil = null;
                }

                continue;
            }

            switch ($token->type) {
                // A pair of parenthesis is considered a single operator.
                case Tokens::T_PARENTHESIS_CLOSE:
                case Tokens::T_CURLY_BRACE_CLOSE:
                case Tokens::T_SQUARED_BRACKET_CLOSE:
                case Tokens::T_ANGLE_BRACKET_CLOSE:
                    break;

                // A label is considered an operator if it is used as the target
                // of a GOTO statement.
                case Tokens::T_GOTO:
                    $operators[] = $token->image;
                    // Ignore next token as operand but count as operator instead.
                    $skipUntil = $tokens[$i + 1]->type;
                    $operators[] = $tokens[$i + 1]->image;
                    break;

                /*
                 * The following control structures case ...: for (...) if (...)
                 * switch (...) while(...) and try-catch (...) are treated in a
                 * special way. The colon and the parentheses are considered to
                 * be a part of the constructs. The case and the colon or the
                 * â€œfor (...)â€�, â€œif (...)â€�, â€œswitch (...)â€�, â€œwhile(...)â€�,
                 * â€œtry-catch( )â€� are counted together as one operator.
                 */
                // case Tokens::T_SWITCH: // not followed by ()
                // case Tokens::T_TRY: // not followed by ()
                // case Tokens::T_DO: // always comes with while, which accounts for () already
                case Tokens::T_IF:
                case Tokens::T_FOR:
                case Tokens::T_FOREACH:
                case Tokens::T_WHILE:
                case Tokens::T_CATCH:
                    $operators[] = $token->image;
                    /*
                     * These are always followed by parenthesis, which would add
                     * another operator (only opening parenthesis counts)
                     * so we'll have to skip that one.
                     */
                    $skipUntil = Tokens::T_PARENTHESIS_OPEN;
                    break;

                /*
                 * The ternary operator â€˜?â€™ followed by â€˜:â€™ is considered a
                 * single operator as it is equivalent to â€œif-elseâ€� construct.
                 */
                case Tokens::T_COLON:
                    /*
                     * Colon is used after keyword, where it counts as part of
                     * that operator, or in ternary operator, where it also
                     * counts as 1.
                     */
                    break;

                // The comments are considered neither an operator nor an operand.
                case Tokens::T_DOC_COMMENT:
                case Tokens::T_COMMENT:
                    break;

                /*
                 * `new` is considered same as the function call, mainly because
                 * it's equivalent to the function call.
                 */
                case Tokens::T_NEW:
                    break;

                /*
                 * Like T_IF & co, array(..) needs 3 tokens ("array", "(" and
                 * ")") for what's essentially just 1 operator.
                 */
                case Tokens::T_ARRAY:
                    break;

                /*
                 * Class::method or $object->method both only count as 1
                 * identifier, even though they consist of 3 tokens.
                 */
                case Tokens::T_OBJECT_OPERATOR:
                case Tokens::T_DOUBLE_COLON:
                    // Glue ->/:: and before & after parts together.
                    $image = array_pop($operands).$token->image.$tokens[$i + 1]->image;
                    $operands[] = $image;

                    // Skip next part (would be seen as operand)
                    $skipUntil = $tokens[$i + 1]->type;
                    break;

                // Ignore HEREDOC delimiters.
                case Tokens::T_START_HEREDOC:
                case Tokens::T_END_HEREDOC:
                    break;

                // Ignore PHP open & close tags and non-PHP content.
                case Tokens::T_OPEN_TAG:
                case Tokens::T_CLOSE_TAG:
                case Tokens::T_NO_PHP:
                    break;

                /*
                 * The function name is considered a single operator when it
                 * appears as calling a function, but when it appears in
                 * declarations or in function definitions it is not counted as
                 * operator.
                 * Default parameter assignments are not counted.
                 */
                case Tokens::T_FUNCTION:
                    // Because `)` could appear in default argument assignment
                    // (`$var = array()`), we need to skip until `{`, but that
                    // one should be included in operators.
                    $skipUntil = Tokens::T_CURLY_BRACE_OPEN;
                    $operators[] = '{';
                    break;

                /*
                 * When variables or constants appear in declaration they are
                 * not considered as operands, they are considered operands only
                 * when they appear with operators in expressions.
                 */
                case Tokens::T_VAR:
                case Tokens::T_CONST:
                    $skipUntil = Tokens::T_SEMICOLON;
                    break;
                case Tokens::T_STRING:
                    // `define` is T_STRING, just like any other identifier.
                    if ($token->image === 'define') {
                        // Undo all of "define", "(", name, ",", value, ")"
                        $skipUntil = Tokens::T_PARENTHESIS_CLOSE;
                    } else {
                        $operands[] = $token->image;
                    }
                    break;

                // Operands
                case Tokens::T_CONSTANT_ENCAPSED_STRING:
                case Tokens::T_VARIABLE:
                case Tokens::T_LNUMBER:
                case Tokens::T_DNUMBER:
                case Tokens::T_NUM_STRING:
                case Tokens::T_NULL:
                case Tokens::T_TRUE:
                case Tokens::T_FALSE:
                case Tokens::T_CLASS_FQN:
                case Tokens::T_LINE:
                case Tokens::T_METHOD_C:
                case Tokens::T_NS_C:
                case Tokens::T_DIR:
                case TOKENS::T_ENCAPSED_AND_WHITESPACE: // content of HEREDOC
                    $operands[] = $token->image;
                    break;

                // Everything else is an operator.
                default:
                    $operators[] = $token->image;
                    break;
            }
        }

        $this->metrics[$callable->getId()] = array(
            'n1' => count($operators),
            'n2' => count($operands),
            'N1' => count(array_unique($operators)),
            'N2' => count(array_unique($operands)),
        );
    }

    /**
     * Calculates Halstead measures from n1, n2, N1 & N2.
     *
     * @see http://www.verifysoft.com/en_halstead_metrics.html
     * @see http://www.grammatech.com/codesonar/workflow-features/halstead
     *
     * @param array $basis [n1, n2, N1, N2]
     * @return array
     */
    public function calculateHalsteadMeasures(array $basis)
    {
        $measures = array();
        $measures[self::M_HALSTEAD_LENGTH] = $basis['N1'] + $basis['N2'];
        $measures[self::M_HALSTEAD_VOCABULARY] = $basis['n1'] + $basis['n2'];
        $measures[self::M_HALSTEAD_VOLUME] =
            $measures[self::M_HALSTEAD_LENGTH] * log($measures[self::M_HALSTEAD_VOCABULARY], 2);
        $measures[self::M_HALSTEAD_DIFFICULTY] = ($basis['n1'] / 2) * ($basis['N1'] / ($basis['n2'] ?: 1));
        $measures[self::M_HALSTEAD_LEVEL] = 1 / ($measures[self::M_HALSTEAD_DIFFICULTY] ?: 1);
        $measures[self::M_HALSTEAD_EFFORT] =
            $measures[self::M_HALSTEAD_VOLUME] * $measures[self::M_HALSTEAD_DIFFICULTY];
        $measures[self::M_HALSTEAD_TIME] = $measures[self::M_HALSTEAD_EFFORT] / 18;
        $measures[self::M_HALSTEAD_BUGS] = pow($measures[self::M_HALSTEAD_EFFORT], (2/3)) / 3000;
        $measures[self::M_HALSTEAD_CONTENT] =
            $measures[self::M_HALSTEAD_VOLUME] / ($measures[self::M_HALSTEAD_DIFFICULTY] ?: 1);

        return $measures;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer;

use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTArtifactList;

/**
 * This analyzer implements several metrics that describe cohesion of classes
 * and namespaces.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class CohesionAnalyzer extends AbstractAnalyzer implements AnalyzerNodeAware
{
    /**
     * Metrics provided by the analyzer implementation.
     */
    const M_LCOM4  = 'lcom4';

    /**
     * Collected cohesion metrics for classes.
     *
     * @var array
     */
    private $nodeMetrics = array();

    /**
     * This method will return an <b>array</b> with all generated metric values
     * for the node with the given <b>$id</b> identifier. If there are no
     * metrics for the requested node, this method will return an empty <b>array</b>.
     *
     * <code>
     * array(
     *     'loc'    =>  42,
     *     'ncloc'  =>  17,
     *     'cc'     =>  12
     * )
     * </code>
     *
     * @param  \PDepend\Source\AST\ASTArtifact $artifact
     * @return array(string=>mixed)
     */
    public function getNodeMetrics(ASTArtifact $artifact)
    {
        if (isset($this->nodeMetrics[$artifact->getId()])) {
            return $this->nodeMetrics[$artifact->getId()];
        }
        return array();
    }

    /**
     * Processes all {@link \PDepend\Source\AST\ASTNamespace} code nodes.
     *
     * @param \PDepend\Source\AST\ASTNamespace[] $namespaces
     *
     * @return void
     */
    public function analyze($namespaces)
    {
        $this->fireStartAnalyzer();

        foreach ($namespaces as $namespace) {
            $namespace->accept($this);
        }

        $this->fireEndAnalyzer();
    }

    /*
    public function visitProperty(\PDepend\Source\AST\ASTProperty $property)
    {
        $this->fireStartProperty($property);
        echo ltrim($property->getName(), '$'), PHP_EOL;
        $this->fireEndProperty($property);
    }

    public function visitMethod(ASTMethod $method)
    {
        $this->fireStartMethod($method);

        $prefixes = $method->findChildrenOfType(
            'PDepend\\Source\\AST\\ASTMemberPrimaryPrefix'
        );
        foreach ($prefixes as $prefix) {
            $variable = $prefix->getChild(0);
            if ($variable instanceof \PDepend\Source\AST\ASTVariable
                && $variable->isThis()
            ) {
                echo "\$this->";
            } elseif ($variable instanceof \PDepend\Source\AST\ASTSelfReference) {
                echo "self::";
            } else {
                continue;
            }

            $next = $prefix->getChild(1);
            if ($next instanceof \PDepend\Source\AST\ASTMemberPrimaryPrefix) {
                $next = $next->getChild(0);
            }

            if ($next instanceof \PDepend\Source\AST\ASTPropertyPostfix) {
                echo $next->getImage(), PHP_EOL;
            } elseif ($next instanceof \PDepend\Source\AST\ASTMethodPostfix) {
                echo $next->getImage(), '()', PHP_EOL;
            }
        }

        $this->fireEndMethod($method);
    }
    */
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer;

use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Metrics\AnalyzerFilterAware;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Metrics\AnalyzerProjectAware;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTClass;

/**
 * This analyzer provides two project related inheritance metrics.
 *
 * <b>ANDC - Average Number of Derived Classes</b>: The average number of direct
 * subclasses of a class. This metric only covers classes in the analyzed system,
 * no library or environment classes are covered.
 *
 * <b>AHH - Average Hierarchy Height</b>: The computed average of all inheritance
 * trees within the analyzed system, external classes or interfaces are ignored.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class InheritanceAnalyzer extends AbstractAnalyzer implements
    AnalyzerNodeAware,
    AnalyzerFilterAware,
    AnalyzerProjectAware
{
    /**
     * Metrics provided by the analyzer implementation.
     */
    const M_AVERAGE_NUMBER_DERIVED_CLASSES = 'andc',
          M_AVERAGE_HIERARCHY_HEIGHT       = 'ahh',
          M_DEPTH_OF_INHERITANCE_TREE      = 'dit',
          M_NUMBER_OF_ADDED_METHODS        = 'noam',
          M_NUMBER_OF_OVERWRITTEN_METHODS  = 'noom',
          M_NUMBER_OF_DERIVED_CLASSES      = 'nocc',
          M_MAXIMUM_INHERITANCE_DEPTH      = 'maxDIT';

    /**
     * Contains the max inheritance depth for all root classes within the
     * analyzed system. The array size is equal to the number of analyzed root
     * classes.
     *
     * @var array(integer)
     */
    private $rootClasses = null;

    /**
     * The maximum depth of inheritance tree value within the analyzed source code.
     *
     * @var integer
     */
    private $maxDIT = 0;

    /**
     * The average number of derived classes.
     *
     * @var float
     */
    private $andc = 0;

    /**
     * The average hierarchy height.
     *
     * @var float
     */
    private $ahh = 0;

    /**
     * Total number of classes.
     *
     * @var integer
     */
    private $numberOfClasses = 0;

    /**
     * Total number of derived classes.
     *
     * @var integer
     */
    private $numberOfDerivedClasses = 0;

    /**
     * Metrics calculated for a single source node.
     *
     * @var array(string=>array)
     */
    private $nodeMetrics = null;

    /**
     * This method will return an <b>array</b> with all generated metric values
     * for the given <b>$node</b>. If there are no metrics for the requested
     * node, this method will return an empty <b>array</b>.
     *
     * @param  \PDepend\Source\AST\ASTArtifact $artifact
     * @return array(string=>mixed)
     */
    public function getNodeMetrics(ASTArtifact $artifact)
    {
        if (isset($this->nodeMetrics[$artifact->getId()])) {
            return $this->nodeMetrics[$artifact->getId()];
        }
        return array();
    }

    /**
     * Provides the project summary as an <b>array</b>.
     *
     * <code>
     * array(
     *     'andc'  =>  0.73,
     *     'ahh'   =>  0.56
     * )
     * </code>
     *
     * @return array(string=>mixed)
     */
    public function getProjectMetrics()
    {
        return array(
            self::M_AVERAGE_NUMBER_DERIVED_CLASSES  =>  $this->andc,
            self::M_AVERAGE_HIERARCHY_HEIGHT        =>  $this->ahh,
            self::M_MAXIMUM_INHERITANCE_DEPTH       =>  $this->maxDIT,
        );
    }

    /**
     * Processes all {@link \PDepend\Source\AST\ASTNamespace} code nodes.
     *
     * @param  \PDepend\Source\AST\ASTNamespace[] $namespaces
     * @return void
     */
    public function analyze($namespaces)
    {
        if ($this->nodeMetrics === null) {
            $this->nodeMetrics = array();

            $this->fireStartAnalyzer();
            $this->doAnalyze($namespaces);
            $this->fireEndAnalyzer();
        }
    }

    /**
     * Calculates several inheritance related metrics for the given source
     * namespaces.
     *
     * @param  \PDepend\Source\AST\ASTNamespace[] $namespaces
     * @return void
     * @since  0.9.10
     */
    private function doAnalyze($namespaces)
    {
        foreach ($namespaces as $namespace) {
            $namespace->accept($this);
        }

        if ($this->numberOfClasses > 0) {
            $this->andc = $this->numberOfDerivedClasses / $this->numberOfClasses;
        }
        if (($count = count($this->rootClasses)) > 0) {
            $this->ahh = array_sum($this->rootClasses) / $count;
        }
    }

    /**
     * Visits a class node.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     */
    public function visitClass(ASTClass $class)
    {
        if (!$class->isUserDefined()) {
            return;
        }

        $this->fireStartClass($class);

        $this->initNodeMetricsForClass($class);
        
        $this->calculateNumberOfDerivedClasses($class);
        $this->calculateNumberOfAddedAndOverwrittenMethods($class);
        $this->calculateDepthOfInheritanceTree($class);

        $this->fireEndClass($class);
    }

    /**
     * Calculates the number of derived classes.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     * @since  0.9.5
     */
    private function calculateNumberOfDerivedClasses(ASTClass $class)
    {
        $id = $class->getId();
        if (isset($this->derivedClasses[$id]) === false) {
            $this->derivedClasses[$id] = 0;
        }

        $parentClass = $class->getParentClass();
        if ($parentClass !== null && $parentClass->isUserDefined()) {
            $id = $parentClass->getId();

            ++$this->numberOfDerivedClasses;
            ++$this->nodeMetrics[$id][self::M_NUMBER_OF_DERIVED_CLASSES];
        }
    }

    /**
     * Calculates the maximum HIT for the given class.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     * @since  0.9.10
     */
    private function calculateDepthOfInheritanceTree(ASTClass $class)
    {
        $dit  = 0;
        $id = $class->getId();
        $root = $class->getId();

        foreach ($class->getParentClasses() as $parent) {
            if (!$parent->isUserDefined()) {
                ++$dit;
            }
            ++$dit;
            $root = $parent->getId();
        }
        
        // Collect max dit value
        $this->maxDIT = max($this->maxDIT, $dit);

        if (empty($this->rootClasses[$root]) || $this->rootClasses[$root] < $dit) {
            $this->rootClasses[$root] = $dit;
        }
        $this->nodeMetrics[$id][self::M_DEPTH_OF_INHERITANCE_TREE] = $dit;
    }

    /**
     * Calculates two metrics. The number of added methods and the number of
     * overwritten methods.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     * @since  0.9.10
     */
    private function calculateNumberOfAddedAndOverwrittenMethods(ASTClass $class)
    {
        $parentClass = $class->getParentClass();
        if ($parentClass === null) {
            return;
        }

        $parentMethodNames = array();
        foreach ($parentClass->getAllMethods() as $method) {
            $parentMethodNames[$method->getName()] = $method->isAbstract();
        }

        $numberOfAddedMethods       = 0;
        $numberOfOverwrittenMethods = 0;

        foreach ($class->getAllMethods() as $method) {
            if ($method->getParent() !== $class) {
                continue;
            }
            
            if (isset($parentMethodNames[$method->getName()])) {
                if (!$parentMethodNames[$method->getName()]) {
                    ++$numberOfOverwrittenMethods;
                }
            } else {
                ++$numberOfAddedMethods;
            }
        }

        $id = $class->getId();

        $this->nodeMetrics[$id][self::M_NUMBER_OF_ADDED_METHODS] = $numberOfAddedMethods;
        $this->nodeMetrics[$id][self::M_NUMBER_OF_OVERWRITTEN_METHODS] = $numberOfOverwrittenMethods;
    }

    /**
     * Initializes a empty metric container for the given class node.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     * @since  0.9.10
     */
    private function initNodeMetricsForClass(ASTClass $class)
    {
        $id = $class->getId();
        if (isset($this->nodeMetrics[$id])) {
            return;
        }

        ++$this->numberOfClasses;

        $this->nodeMetrics[$id] = array(
            self::M_DEPTH_OF_INHERITANCE_TREE     => 0,
            self::M_NUMBER_OF_ADDED_METHODS       => 0,
            self::M_NUMBER_OF_DERIVED_CLASSES     => 0,
            self::M_NUMBER_OF_OVERWRITTEN_METHODS => 0
        );

        foreach ($class->getParentClasses() as $parent) {
            $this->initNodeMetricsForClass($parent);
        }
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer;

use PDepend\Metrics\AbstractCachingAnalyzer;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Metrics\AnalyzerProjectAware;
use PDepend\Source\AST\AbstractASTCallable;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;

/**
 * This class calculates the Cyclomatic Complexity Number(CCN) for the project,
 * methods and functions.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class CyclomaticComplexityAnalyzer extends AbstractCachingAnalyzer implements AnalyzerNodeAware, AnalyzerProjectAware
{
    /**
     * Metrics provided by the analyzer implementation.
     */
    const M_CYCLOMATIC_COMPLEXITY_1 = 'ccn',
          M_CYCLOMATIC_COMPLEXITY_2 = 'ccn2';

    /**
     * The project Cyclomatic Complexity Number.
     *
     * @var integer
     */
    private $ccn = 0;

    /**
     * Extended Cyclomatic Complexity Number(CCN2) for the project.
     *
     * @var integer
     */
    private $ccn2 = 0;

    /**
     * Processes all {@link \PDepend\Source\AST\ASTNamespace} code nodes.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespaces
     * @return void
     */
    public function analyze($namespaces)
    {
        if ($this->metrics === null) {
            $this->loadCache();
            $this->fireStartAnalyzer();

            // Init node metrics
            $this->metrics = array();

            foreach ($namespaces as $namespace) {
                $namespace->accept($this);
            }

            $this->fireEndAnalyzer();
            $this->unloadCache();
        }
    }

    /**
     * Returns the cyclomatic complexity for the given <b>$node</b> instance.
     *
     * @param  \PDepend\Source\AST\ASTArtifact $node
     * @return integer
     */
    public function getCcn(ASTArtifact $node)
    {
        $metrics = $this->getNodeMetrics($node);
        if (isset($metrics[self::M_CYCLOMATIC_COMPLEXITY_1])) {
            return $metrics[self::M_CYCLOMATIC_COMPLEXITY_1];
        }
        return 0;
    }

    /**
     * Returns the extended cyclomatic complexity for the given <b>$node</b>
     * instance.
     *
     * @param  \PDepend\Source\AST\ASTArtifact $node
     * @return integer
     */
    public function getCcn2(ASTArtifact $node)
    {
        $metrics = $this->getNodeMetrics($node);
        if (isset($metrics[self::M_CYCLOMATIC_COMPLEXITY_2])) {
            return $metrics[self::M_CYCLOMATIC_COMPLEXITY_2];
        }
        return 0;
    }

    /**
     * This method will return an <b>array</b> with all generated metric values
     * for the given <b>$node</b>. If there are no metrics for the requested
     * node, this method will return an empty <b>array</b>.
     *
     * @param  \PDepend\Source\AST\ASTArtifact $artifact
     * @return array
     */
    public function getNodeMetrics(ASTArtifact $artifact)
    {
        if (isset($this->metrics[$artifact->getId()])) {
            return $this->metrics[$artifact->getId()];
        }
        return array();
    }

    /**
     * Provides the project summary metrics as an <b>array</b>.
     *
     * @return array
     */
    public function getProjectMetrics()
    {
        return array(
            self::M_CYCLOMATIC_COMPLEXITY_1  =>  $this->ccn,
            self::M_CYCLOMATIC_COMPLEXITY_2  =>  $this->ccn2
        );
    }

    /**
     * Visits a function node.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     */
    public function visitFunction(ASTFunction $function)
    {
        $this->fireStartFunction($function);

        if (false === $this->restoreFromCache($function)) {
            $this->calculateComplexity($function);
        }
        $this->updateProjectMetrics($function->getId());

        $this->fireEndFunction($function);
    }

    /**
     * Visits a code interface object.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function visitInterface(ASTInterface $interface)
    {
        // Empty visit method, we don't want interface metrics
    }

    /**
     * Visits a method node.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function visitMethod(ASTMethod $method)
    {
        $this->fireStartMethod($method);

        if (false === $this->restoreFromCache($method)) {
            $this->calculateComplexity($method);
        }
        $this->updateProjectMetrics($method->getId());

        $this->fireEndMethod($method);
    }

    /**
     * Visits methods, functions or closures and calculated their complexity.
     *
     * @param  \PDepend\Source\AST\AbstractASTCallable $callable
     * @return void
     * @since  0.9.8
     */
    public function calculateComplexity(AbstractASTCallable $callable)
    {
        $data = array(
            self::M_CYCLOMATIC_COMPLEXITY_1 => 1,
            self::M_CYCLOMATIC_COMPLEXITY_2 => 1
        );

        foreach ($callable->getChildren() as $child) {
            $data = $child->accept($this, $data);
        }

        $this->metrics[$callable->getId()] = $data;
    }

    /**
     * Stores the complexity of a node and updates the corresponding project
     * values.
     *
     * @param string $nodeId Identifier of the analyzed item.
     *
     * @return void
     * @since  1.0.0
     */
    private function updateProjectMetrics($nodeId)
    {
        $this->ccn  += $this->metrics[$nodeId][self::M_CYCLOMATIC_COMPLEXITY_1];
        $this->ccn2 += $this->metrics[$nodeId][self::M_CYCLOMATIC_COMPLEXITY_2];
    }

    /**
     * Visits a boolean AND-expression.
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param array(string=>integer)      $data The previously calculated ccn values.
     *
     * @return array(string=>integer)
     * @since  0.9.8
     */
    public function visitBooleanAndExpression($node, $data)
    {
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_2];
        return $this->visit($node, $data);
    }

    /**
     * Visits a boolean OR-expression.
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param array(string=>integer)      $data The previously calculated ccn values.
     *
     * @return array(string=>integer)
     * @since  0.9.8
     */
    public function visitBooleanOrExpression($node, $data)
    {
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_2];
        return $this->visit($node, $data);
    }

    /**
     * Visits a switch label.
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param array(string=>integer)      $data The previously calculated ccn values.
     *
     * @return array(string=>integer)
     * @since  0.9.8
     */
    public function visitSwitchLabel($node, $data)
    {
        if (!$node->isDefault()) {
            ++$data[self::M_CYCLOMATIC_COMPLEXITY_1];
            ++$data[self::M_CYCLOMATIC_COMPLEXITY_2];
        }
        return $this->visit($node, $data);
    }

    /**
     * Visits a catch statement.
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param array(string=>integer)      $data The previously calculated ccn values.
     *
     * @return array(string=>integer)
     * @since  0.9.8
     */
    public function visitCatchStatement($node, $data)
    {
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_1];
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_2];

        return $this->visit($node, $data);
    }

    /**
     * Visits an elseif statement.
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param array(string=>integer)      $data The previously calculated ccn values.
     *
     * @return array(string=>integer)
     * @since  0.9.8
     */
    public function visitElseIfStatement($node, $data)
    {
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_1];
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_2];

        return $this->visit($node, $data);
    }

    /**
     * Visits a for statement.
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param array(string=>integer)      $data The previously calculated ccn values.
     *
     * @return array(string=>integer)
     * @since  0.9.8
     */
    public function visitForStatement($node, $data)
    {
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_1];
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_2];

        return $this->visit($node, $data);
    }

    /**
     * Visits a foreach statement.
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param array(string=>integer)      $data The previously calculated ccn values.
     *
     * @return array(string=>integer)
     * @since  0.9.8
     */
    public function visitForeachStatement($node, $data)
    {
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_1];
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_2];

        return $this->visit($node, $data);
    }

    /**
     * Visits an if statement.
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param array(string=>integer)      $data The previously calculated ccn values.
     *
     * @return array(string=>integer)
     * @since  0.9.8
     */
    public function visitIfStatement($node, $data)
    {
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_1];
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_2];

        return $this->visit($node, $data);
    }

    /**
     * Visits a logical AND expression.
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param array(string=>integer)      $data The previously calculated ccn values.
     *
     * @return array(string=>integer)
     * @since  0.9.8
     */
    public function visitLogicalAndExpression($node, $data)
    {
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_2];
        return $this->visit($node, $data);
    }

    /**
     * Visits a logical OR expression.
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param array(string=>integer)      $data The previously calculated ccn values.
     *
     * @return array(string=>integer)
     * @since  0.9.8
     */
    public function visitLogicalOrExpression($node, $data)
    {
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_2];
        return $this->visit($node, $data);
    }

    /**
     * Visits a ternary operator.
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param array(string=>integer)      $data The previously calculated ccn values.
     *
     * @return array(string=>integer)
     * @since  0.9.8
     */
    public function visitConditionalExpression($node, $data)
    {
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_1];
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_2];

        return $this->visit($node, $data);
    }

    /**
     * Visits a while-statement.
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param array(string=>integer)      $data The previously calculated ccn values.
     *
     * @return array(string=>integer)
     * @since  0.9.8
     */
    public function visitWhileStatement($node, $data)
    {
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_1];
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_2];

        return $this->visit($node, $data);
    }

    /**
     * Visits a do/while-statement.
     *
     * @param \PDepend\Source\AST\ASTNode $node The currently visited node.
     * @param array(string=>integer)      $data The previously calculated ccn values.
     *
     * @return array(string=>integer)
     * @since  0.9.12
     */
    public function visitDoWhileStatement($node, $data)
    {
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_1];
        ++$data[self::M_CYCLOMATIC_COMPLEXITY_2];

        return $this->visit($node, $data);
    }
}
<?php

/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2015, Matthias Mullie <pdepend@mullie.eu>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2015 Matthias Mullie. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer;

use PDepend\Metrics\AbstractCachingAnalyzer;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Source\AST\AbstractASTCallable;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;

/**
 * This class calculates the Halstead Complexity Measures for the project,
 * methods and functions.
 *
 * @copyright 2015 Matthias Mullie. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class MaintainabilityIndexAnalyzer extends AbstractCachingAnalyzer implements AnalyzerNodeAware
{
    /**
     * Metrics provided by the analyzer implementation.
     */
    const M_MAINTAINABILITY_INDEX = 'mi';

    /**
     * @var AbstractCachingAnalyzer[]
     */
    private $analyzers = array();

    /**
     * Maintainability index is a combination of cyclomatic complexity,
     * halstead volume & lines of code, all of which we already have analyzers
     * for.
     *
     * @param array $options
     */
    public function __construct(array $options = array())
    {
        parent::__construct($options);

        $this->analyzers['ccn'] = new CyclomaticComplexityAnalyzer();
        $this->analyzers['halstead'] = new HalsteadAnalyzer();
        $this->analyzers['loc'] = new NodeLocAnalyzer();
    }

    /**
     * Processes all {@link \PDepend\Source\AST\ASTNamespace} code nodes.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespaces
     * @return void
     */
    public function analyze($namespaces)
    {
        // Run CCN, Halstead & LOC analyzers first
        foreach ($this->analyzers as $analyzer) {
            $analyzer->setCache($this->getCache());
            $analyzer->analyze($namespaces);
        }

        if ($this->metrics === null) {
            $this->loadCache();
            $this->fireStartAnalyzer();

            // Init node metrics
            $this->metrics = array();

            foreach ($namespaces as $namespace) {
                $namespace->accept($this);
            }

            $this->fireEndAnalyzer();
            $this->unloadCache();
        }
    }

    /**
     * This method will return an <b>array</b> with all generated metric values
     * for the given <b>$node</b>. If there are no metrics for the requested
     * node, this method will return an empty <b>array</b>.
     *
     * @param \PDepend\Source\AST\ASTArtifact $artifact
     * @return array
     */
    public function getNodeMetrics(ASTArtifact $artifact)
    {
        if (isset($this->metrics[$artifact->getId()])) {
            return $this->metrics[$artifact->getId()];
        }

        return array();
    }

    /**
     * Visits a function node.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     */
    public function visitFunction(ASTFunction $function)
    {
        $this->fireStartFunction($function);

        if (false === $this->restoreFromCache($function)) {
            $this->calculateMaintainabilityIndex($function);
        }

        $this->fireEndFunction($function);
    }

    /**
     * Visits a code interface object.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function visitInterface(ASTInterface $interface)
    {
        // Empty visit method, we don't want interface metrics
    }

    /**
     * Visits a method node.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function visitMethod(ASTMethod $method)
    {
        $this->fireStartMethod($method);

        if (false === $this->restoreFromCache($method)) {
            $this->calculateMaintainabilityIndex($method);
        }

        $this->fireEndMethod($method);
    }

    /**
     * @see http://blogs.msdn.com/b/codeanalysis/archive/2007/11/20/maintainability-index-range-and-meaning.aspx
     *
     * @param  \PDepend\Source\AST\AbstractASTCallable $callable
     * @return void
     */
    public function calculateMaintainabilityIndex(AbstractASTCallable $callable)
    {
        $cyclomaticComplexity = $this->analyzers['ccn']->getCcn2($callable);

        $halstead = $this->analyzers['halstead']->getNodeMetrics($callable);
        $halsteadVolume = $halstead[HalsteadAnalyzer::M_HALSTEAD_VOLUME];

        $loc = $this->analyzers['loc']->getNodeMetrics($callable);
        $eloc = $loc[NodeLocAnalyzer::M_EXECUTABLE_LINES_OF_CODE];

        $maintainabilityIndex = 171 - 5.2 * log($halsteadVolume) - 0.23 * $cyclomaticComplexity - 16.2 * log($eloc);
        $maintainabilityIndex = min(100, max(0, $maintainabilityIndex * 100 / 171));
        $this->metrics[$callable->getId()] = array(self::M_MAINTAINABILITY_INDEX => $maintainabilityIndex);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer;

use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Metrics\AnalyzerFilterAware;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Metrics\AnalyzerProjectAware;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;

/**
 * This analyzer collects different count metrics for code artifacts like
 * classes, methods, functions or namespaces.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class NodeCountAnalyzer extends AbstractAnalyzer implements AnalyzerFilterAware, AnalyzerNodeAware, AnalyzerProjectAware
{
    /**
     * Metrics provided by the analyzer implementation.
     */
    const M_NUMBER_OF_PACKAGES   = 'nop',
          M_NUMBER_OF_CLASSES    = 'noc',
          M_NUMBER_OF_INTERFACES = 'noi',
          M_NUMBER_OF_METHODS    = 'nom',
          M_NUMBER_OF_FUNCTIONS  = 'nof';

    /**
     * Number Of Packages.
     *
     * @var integer
     */
    private $nop = 0;

    /**
     * Number Of Classes.
     *
     * @var integer
     */
    private $noc = 0;

    /**
     * Number Of Interfaces.
     *
     * @var integer
     */
    private $noi = 0;

    /**
     * Number Of Methods.
     *
     * @var integer
     */
    private $nom = 0;

    /**
     * Number Of Functions.
     *
     * @var integer
     */
    private $nof = 0;

    /**
     * Collected node metrics
     *
     * @var array(string=>array)
     */
    private $nodeMetrics = null;

    /**
     * This method will return an <b>array</b> with all generated metric values
     * for the given <b>$node</b> instance. If there are no metrics for the
     * requested node, this method will return an empty <b>array</b>.
     *
     * <code>
     * array(
     *     'noc'  =>  23,
     *     'nom'  =>  17,
     *     'nof'  =>  42
     * )
     * </code>
     *
     * @param  \PDepend\Source\AST\ASTArtifact $artifact
     * @return array(string=>mixed)
     */
    public function getNodeMetrics(ASTArtifact $artifact)
    {
        $metrics = array();
        if (isset($this->nodeMetrics[$artifact->getId()])) {
            $metrics = $this->nodeMetrics[$artifact->getId()];
        }
        return $metrics;
    }

    /**
     * Provides the project summary as an <b>array</b>.
     *
     * <code>
     * array(
     *     'nop'  =>  23,
     *     'noc'  =>  17,
     *     'noi'  =>  23,
     *     'nom'  =>  42,
     *     'nof'  =>  17
     * )
     * </code>
     *
     * @return array(string=>mixed)
     */
    public function getProjectMetrics()
    {
        return array(
            self::M_NUMBER_OF_PACKAGES    =>  $this->nop,
            self::M_NUMBER_OF_CLASSES     =>  $this->noc,
            self::M_NUMBER_OF_INTERFACES  =>  $this->noi,
            self::M_NUMBER_OF_METHODS     =>  $this->nom,
            self::M_NUMBER_OF_FUNCTIONS   =>  $this->nof
        );
    }

    /**
     * Processes all {@link \PDepend\Source\AST\ASTNamespace} code nodes.
     *
     * @param  \PDepend\Source\AST\ASTNamespace[] $namespaces
     * @return void
     */
    public function analyze($namespaces)
    {
        // Check for previous run
        if ($this->nodeMetrics === null) {
            $this->fireStartAnalyzer();

            $this->nodeMetrics = array();

            foreach ($namespaces as $namespace) {
                $namespace->accept($this);
            }

            $this->fireEndAnalyzer();
        }
    }

    /**
     * Visits a class node.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     */
    public function visitClass(ASTClass $class)
    {
        if (false === $class->isUserDefined()) {
            return;
        }

        $this->fireStartClass($class);

        // Update global class count
        ++$this->noc;

        $id = $class->getNamespace()->getId();
        ++$this->nodeMetrics[$id][self::M_NUMBER_OF_CLASSES];

        $this->nodeMetrics[$class->getId()] = array(
            self::M_NUMBER_OF_METHODS  =>  0
        );

        foreach ($class->getMethods() as $method) {
            $method->accept($this);
        }

        $this->fireEndClass($class);
    }

    /**
     * Visits a function node.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     */
    public function visitFunction(ASTFunction $function)
    {
        $this->fireStartFunction($function);

        // Update global function count
        ++$this->nof;

        $id = $function->getNamespace()->getId();
        ++$this->nodeMetrics[$id][self::M_NUMBER_OF_FUNCTIONS];

        $this->fireEndFunction($function);
    }

    /**
     * Visits a code interface object.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function visitInterface(ASTInterface $interface)
    {
        if (false === $interface->isUserDefined()) {
            return;
        }

        $this->fireStartInterface($interface);

        // Update global class count
        ++$this->noi;

        $id = $interface->getNamespace()->getId();
        ++$this->nodeMetrics[$id][self::M_NUMBER_OF_INTERFACES];

        $this->nodeMetrics[$interface->getId()] = array(
            self::M_NUMBER_OF_METHODS  =>  0
        );

        foreach ($interface->getMethods() as $method) {
            $method->accept($this);
        }

        $this->fireEndInterface($interface);
    }

    /**
     * Visits a method node.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function visitMethod(ASTMethod $method)
    {
        $this->fireStartMethod($method);

        // Update global method count
        ++$this->nom;

        $parent = $method->getParent();

        // Update parent class or interface
        $parentId = $parent->getId();
        ++$this->nodeMetrics[$parentId][self::M_NUMBER_OF_METHODS];

        $id = $parent->getNamespace()->getId();
        ++$this->nodeMetrics[$id][self::M_NUMBER_OF_METHODS];

        $this->fireEndMethod($method);
    }

    /**
     * Visits a namespace node.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespace
     * @return void
     */
    public function visitNamespace(ASTNamespace $namespace)
    {
        $this->fireStartNamespace($namespace);

        ++$this->nop;

        $this->nodeMetrics[$namespace->getId()] = array(
            self::M_NUMBER_OF_CLASSES     =>  0,
            self::M_NUMBER_OF_INTERFACES  =>  0,
            self::M_NUMBER_OF_METHODS     =>  0,
            self::M_NUMBER_OF_FUNCTIONS   =>  0
        );


        foreach ($namespace->getClasses() as $class) {
            $class->accept($this);
        }
        foreach ($namespace->getInterfaces() as $interface) {
            $interface->accept($this);
        }
        foreach ($namespace->getFunctions() as $function) {
            $function->accept($this);
        }

        $this->fireEndNamespace($namespace);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer;

use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Metrics\AggregateAnalyzer;
use PDepend\Metrics\AnalyzerFilterAware;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Source\AST\AbstractASTType;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTProperty;
use PDepend\Source\AST\ASTTrait;

/**
 * Generates some class level based metrics. This analyzer is based on the
 * metrics specified in the following document.
 *
 * http://www.aivosto.com/project/help/pm-oo-misc.html
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class ClassLevelAnalyzer extends AbstractAnalyzer implements AggregateAnalyzer, AnalyzerFilterAware, AnalyzerNodeAware
{
    /**
     * Metrics provided by the analyzer implementation.
     */
    const M_IMPLEMENTED_INTERFACES       = 'impl',
          M_CLASS_INTERFACE_SIZE         = 'cis',
          M_CLASS_SIZE                   = 'csz',
          M_NUMBER_OF_PUBLIC_METHODS     = 'npm',
          M_PROPERTIES                   = 'vars',
          M_PROPERTIES_INHERIT           = 'varsi',
          M_PROPERTIES_NON_PRIVATE       = 'varsnp',
          M_WEIGHTED_METHODS             = 'wmc',
          M_WEIGHTED_METHODS_INHERIT     = 'wmci',
          M_WEIGHTED_METHODS_NON_PRIVATE = 'wmcnp';

    /**
     * Hash with all calculated node metrics.
     *
     * <code>
     * array(
     *     '0375e305-885a-4e91-8b5c-e25bda005438'  =>  array(
     *         'loc'    =>  42,
     *         'ncloc'  =>  17,
     *         'cc'     =>  12
     *     ),
     *     'e60c22f0-1a63-4c40-893e-ed3b35b84d0b'  =>  array(
     *         'loc'    =>  42,
     *         'ncloc'  =>  17,
     *         'cc'     =>  12
     *     )
     * )
     * </code>
     *
     * @var array(string=>array)
     */
    private $nodeMetrics = null;

    /**
     * The internal used cyclomatic complexity analyzer.
     *
     * @var \PDepend\Metrics\Analyzer\CyclomaticComplexityAnalyzer
     */
    private $cyclomaticAnalyzer = null;

    /**
     * Processes all {@link \PDepend\Source\AST\ASTNamespace} code nodes.
     *
     * @param  \PDepend\Source\AST\ASTNamespace[] $namespaces
     * @return void
     */
    public function analyze($namespaces)
    {
        if ($this->nodeMetrics === null) {
            // First check for the require cc analyzer
            if ($this->cyclomaticAnalyzer === null) {
                throw new \RuntimeException('Missing required CC analyzer.');
            }

            $this->fireStartAnalyzer();

            $this->cyclomaticAnalyzer->analyze($namespaces);

            // Init node metrics
            $this->nodeMetrics = array();

            // Visit all nodes
            foreach ($namespaces as $namespace) {
                $namespace->accept($this);
            }

            $this->fireEndAnalyzer();
        }
    }

    /**
     * This method must return an <b>array</b> of class names for required
     * analyzers.
     *
     * @return array(string)
     */
    public function getRequiredAnalyzers()
    {
        return array('PDepend\\Metrics\\Analyzer\\CyclomaticComplexityAnalyzer');
    }

    /**
     * Adds a required sub analyzer.
     *
     * @param  \PDepend\Metrics\Analyzer $analyzer The sub analyzer instance.
     * @return void
     */
    public function addAnalyzer(\PDepend\Metrics\Analyzer $analyzer)
    {
        if ($analyzer instanceof \PDepend\Metrics\Analyzer\CyclomaticComplexityAnalyzer) {
            $this->cyclomaticAnalyzer = $analyzer;
        } else {
            throw new \InvalidArgumentException('CC Analyzer required.');
        }
    }

    /**
     * This method will return an <b>array</b> with all generated metric values
     * for the given <b>$node</b>. If there are no metrics for the requested
     * node, this method will return an empty <b>array</b>.
     *
     * @param  \PDepend\Source\AST\ASTArtifact $artifact
     * @return array(string=>mixed)
     */
    public function getNodeMetrics(ASTArtifact $artifact)
    {
        $metrics = array();
        if (isset($this->nodeMetrics[$artifact->getId()])) {
            $metrics = $this->nodeMetrics[$artifact->getId()];
        }
        return $metrics;
    }

    /**
     * Visits a class node.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     */
    public function visitClass(ASTClass $class)
    {
        $this->fireStartClass($class);

        $impl  = $class->getInterfaces()->count();
        $varsi = $this->calculateVarsi($class);
        $wmci  = $this->calculateWmciForClass($class);

        $this->nodeMetrics[$class->getId()] = array(
            self::M_IMPLEMENTED_INTERFACES       => $impl,
            self::M_CLASS_INTERFACE_SIZE         => 0,
            self::M_CLASS_SIZE                   => 0,
            self::M_NUMBER_OF_PUBLIC_METHODS     => 0,
            self::M_PROPERTIES                   => 0,
            self::M_PROPERTIES_INHERIT           => $varsi,
            self::M_PROPERTIES_NON_PRIVATE       => 0,
            self::M_WEIGHTED_METHODS             => 0,
            self::M_WEIGHTED_METHODS_INHERIT     => $wmci,
            self::M_WEIGHTED_METHODS_NON_PRIVATE => 0
        );

        foreach ($class->getProperties() as $property) {
            $property->accept($this);
        }
        foreach ($class->getMethods() as $method) {
            $method->accept($this);
        }

        $this->fireEndClass($class);
    }

    /**
     * Visits a code interface object.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function visitInterface(ASTInterface $interface)
    {
        // Empty visit method, we don't want interface metrics
    }

    /**
     * Visits a trait node.
     *
     * @param  \PDepend\Source\AST\ASTTrait $trait
     * @return void
     * @since  1.0.0
     */
    public function visitTrait(ASTTrait $trait)
    {
        $this->fireStartTrait($trait);

        $wmci = $this->calculateWmciForTrait($trait);

        $this->nodeMetrics[$trait->getId()] = array(
            self::M_IMPLEMENTED_INTERFACES       => 0,
            self::M_CLASS_INTERFACE_SIZE         => 0,
            self::M_CLASS_SIZE                   => 0,
            self::M_NUMBER_OF_PUBLIC_METHODS     => 0,
            self::M_PROPERTIES                   => 0,
            self::M_PROPERTIES_INHERIT           => 0,
            self::M_PROPERTIES_NON_PRIVATE       => 0,
            self::M_WEIGHTED_METHODS             => 0,
            self::M_WEIGHTED_METHODS_INHERIT     => $wmci,
            self::M_WEIGHTED_METHODS_NON_PRIVATE => 0
        );

        foreach ($trait->getProperties() as $property) {
            $property->accept($this);
        }
        foreach ($trait->getMethods() as $method) {
            $method->accept($this);
        }

        $this->fireEndTrait($trait);
    }

    /**
     * Visits a method node.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function visitMethod(ASTMethod $method)
    {
        $this->fireStartMethod($method);

        $id = $method->getParent()->getId();

        $ccn = $this->cyclomaticAnalyzer->getCcn2($method);

        // Increment Weighted Methods Per Class(WMC) value
        $this->nodeMetrics[$id][self::M_WEIGHTED_METHODS] += $ccn;
        // Increment Class Size(CSZ) value
        ++$this->nodeMetrics[$id][self::M_CLASS_SIZE];

        // Increment Non Private values
        if ($method->isPublic()) {
            ++$this->nodeMetrics[$id][self::M_NUMBER_OF_PUBLIC_METHODS];
            // Increment Non Private WMC value
            $this->nodeMetrics[$id][self::M_WEIGHTED_METHODS_NON_PRIVATE] += $ccn;
            // Increment Class Interface Size(CIS) value
            ++$this->nodeMetrics[$id][self::M_CLASS_INTERFACE_SIZE];
        }

        $this->fireEndMethod($method);
    }

    /**
     * Visits a property node.
     *
     * @param  \PDepend\Source\AST\ASTProperty $property
     * @return void
     */
    public function visitProperty(ASTProperty $property)
    {
        $this->fireStartProperty($property);

        $id = $property->getDeclaringClass()->getId();

        // Increment VARS value
        ++$this->nodeMetrics[$id][self::M_PROPERTIES];
        // Increment Class Size(CSZ) value
        ++$this->nodeMetrics[$id][self::M_CLASS_SIZE];

        // Increment Non Private values
        if ($property->isPublic()) {
            // Increment Non Private VARS value
            ++$this->nodeMetrics[$id][self::M_PROPERTIES_NON_PRIVATE];
            // Increment Class Interface Size(CIS) value
            ++$this->nodeMetrics[$id][self::M_CLASS_INTERFACE_SIZE];
        }

        $this->fireEndProperty($property);
    }

    /**
     * Calculates the Variables Inheritance of a class metric, this method only
     * counts protected and public properties of parent classes.
     *
     * @param  \PDepend\Source\AST\ASTClass $class The context class instance.
     * @return integer
     */
    private function calculateVarsi(ASTClass $class)
    {
        // List of properties, this method only counts not overwritten properties
        $properties = array();
        // Collect all properties of the context class
        foreach ($class->getProperties() as $prop) {
            $properties[$prop->getName()] = true;
        }

        foreach ($class->getParentClasses() as $parent) {
            foreach ($parent->getProperties() as $prop) {
                if (!$prop->isPrivate() && !isset($properties[$prop->getName()])) {
                    $properties[$prop->getName()] = true;
                }
            }
        }
        return count($properties);
    }

    /**
     * Calculates the Weight Method Per Class metric, this method only counts
     * protected and public methods of parent classes.
     *
     * @param  \PDepend\Source\AST\ASTClass $class The context class instance.
     * @return integer
     */
    private function calculateWmciForClass(ASTClass $class)
    {
        $ccn = $this->calculateWmci($class);

        foreach ($class->getParentClasses() as $parent) {
            foreach ($parent->getMethods() as $method) {
                if ($method->isPrivate()) {
                    continue;
                }
                if (isset($ccn[($name = $method->getName())])) {
                    continue;
                }
                $ccn[$name] = $this->cyclomaticAnalyzer->getCcn2($method);
            }
        }

        return array_sum($ccn);
    }

    /**
     * Calculates the Weight Method Per Class metric for a trait.
     *
     * @param  \PDepend\Source\AST\ASTTrait $trait
     * @return integer
     * @since  1.0.6
     */
    private function calculateWmciForTrait(ASTTrait $trait)
    {
        return array_sum($this->calculateWmci($trait));
    }

    /**
     * Calculates the Weight Method Per Class metric.
     *
     * @param  \PDepend\Source\AST\AbstractASTType $type
     * @return integer[]
     * @since  1.0.6
     */
    private function calculateWmci(AbstractASTType $type)
    {
        $ccn = array();

        foreach ($type->getMethods() as $method) {
            $ccn[$method->getName()] = $this->cyclomaticAnalyzer->getCcn2($method);
        }

        return $ccn;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer;

use PDepend\Metrics\AbstractCachingAnalyzer;
use PDepend\Metrics\AnalyzerFilterAware;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Metrics\AnalyzerProjectAware;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTCompilationUnit;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\Tokenizer\Tokens;

/**
 * This analyzer collects different lines of code metrics.
 *
 * It collects the total Lines Of Code(<b>loc</b>), the None Comment Lines Of
 * Code(<b>ncloc</b>), the Comment Lines Of Code(<b>cloc</b>) and a approximated
 * Executable Lines Of Code(<b>eloc</b>) for files, classes, interfaces,
 * methods, properties and function.
 *
 * The current implementation has a limitation, that affects inline comments.
 * The following code will suppress one line of code.
 *
 * <code>
 * function foo() {
 *     foobar(); // Bad behaviour...
 * }
 * </code>
 *
 * The same rule applies to class methods. mapi, <b>PLEASE, FIX THIS ISSUE.</b>
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class NodeLocAnalyzer extends AbstractCachingAnalyzer implements
    AnalyzerNodeAware,
    AnalyzerFilterAware,
    AnalyzerProjectAware
{
    /**
     * Metrics provided by the analyzer implementation.
     */
    const M_LINES_OF_CODE             = 'loc',
          M_COMMENT_LINES_OF_CODE     = 'cloc',
          M_EXECUTABLE_LINES_OF_CODE  = 'eloc',
          M_LOGICAL_LINES_OF_CODE     = 'lloc',
          M_NON_COMMENT_LINES_OF_CODE = 'ncloc';

    /**
     * Collected project metrics.
     *
     * @var array(string=>integer)
     */
    private $projectMetrics = array(
        self::M_LINES_OF_CODE              =>  0,
        self::M_COMMENT_LINES_OF_CODE      =>  0,
        self::M_EXECUTABLE_LINES_OF_CODE   =>  0,
        self::M_LOGICAL_LINES_OF_CODE      =>  0,
        self::M_NON_COMMENT_LINES_OF_CODE  =>  0
    );

    /**
     * Executable lines of code in a class. The method calculation increases
     * this property with each method's ELOC value.
     *
     * @var   integer
     * @since 0.9.12
     */
    private $classExecutableLines = 0;

    /**
     * Logical lines of code in a class. The method calculation increases this
     * property with each method's LLOC value.
     *
     * @var   integer
     * @since 0.9.13
     */
    private $classLogicalLines = 0;

    /**
     * This method will return an <b>array</b> with all generated metric values
     * for the given <b>$node</b> instance. If there are no metrics for the
     * requested node, this method will return an empty <b>array</b>.
     *
     * <code>
     * array(
     *     'loc'    =>  23,
     *     'cloc'   =>  17,
     *     'eloc'   =>  17,
     *     'ncloc'  =>  42
     * )
     * </code>
     *
     * @param  \PDepend\Source\AST\ASTArtifact $artifact
     * @return array
     */
    public function getNodeMetrics(ASTArtifact $artifact)
    {
        $metrics = array();
        if (isset($this->metrics[$artifact->getId()])) {
            $metrics = $this->metrics[$artifact->getId()];
        }
        return $metrics;
    }

    /**
     * Provides the project summary as an <b>array</b>.
     *
     * <code>
     * array(
     *     'loc'    =>  23,
     *     'cloc'   =>  17,
     *     'ncloc'  =>  42
     * )
     * </code>
     *
     * @return array
     */
    public function getProjectMetrics()
    {
        return $this->projectMetrics;
    }

    /**
     * Processes all {@link \PDepend\Source\AST\ASTNamespace} code nodes.
     *
     * @param  \PDepend\Source\AST\ASTNamespace[] $namespaces
     * @return void
     */
    public function analyze($namespaces)
    {
        if ($this->metrics === null) {
            $this->loadCache();
            $this->fireStartAnalyzer();

            $this->metrics = array();
            foreach ($namespaces as $namespace) {
                $namespace->accept($this);
            }

            $this->fireEndAnalyzer();
            $this->unloadCache();
        }
    }

    /**
     * Visits a class node.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     */
    public function visitClass(ASTClass $class)
    {
        $this->fireStartClass($class);

        $class->getCompilationUnit()->accept($this);

        $this->classExecutableLines = 0;
        $this->classLogicalLines    = 0;

        foreach ($class->getMethods() as $method) {
            $method->accept($this);
        }

        if ($this->restoreFromCache($class)) {
            return $this->fireEndClass($class);
        }

        list($cloc) = $this->linesOfCode($class->getTokens(), true);

        $loc   = $class->getEndLine() - $class->getStartLine() + 1;
        $ncloc = $loc - $cloc;

        $this->metrics[$class->getId()] = array(
            self::M_LINES_OF_CODE              =>  $loc,
            self::M_COMMENT_LINES_OF_CODE      =>  $cloc,
            self::M_EXECUTABLE_LINES_OF_CODE   =>  $this->classExecutableLines,
            self::M_LOGICAL_LINES_OF_CODE      =>  $this->classLogicalLines,
            self::M_NON_COMMENT_LINES_OF_CODE  =>  $ncloc,
        );

        $this->fireEndClass($class);
    }

    /**
     * Visits a file node.
     *
     * @param  \PDepend\Source\AST\ASTCompilationUnit $compilationUnit
     * @return void
     */
    public function visitCompilationUnit(ASTCompilationUnit $compilationUnit)
    {
        // Skip for dummy files
        if ($compilationUnit->getFileName() === null) {
            return;
        }
        // Check for initial file
        $id = $compilationUnit->getId();
        if (isset($this->metrics[$id])) {
            return;
        }

        $this->fireStartFile($compilationUnit);

        if ($this->restoreFromCache($compilationUnit)) {
            $this->updateProjectMetrics($id);
            return $this->fireEndFile($compilationUnit);
        }

        list($cloc, $eloc, $lloc) = $this->linesOfCode($compilationUnit->getTokens());

        $loc   = $compilationUnit->getEndLine();
        $ncloc = $loc - $cloc;

        $this->metrics[$id] = array(
            self::M_LINES_OF_CODE              =>  $loc,
            self::M_COMMENT_LINES_OF_CODE      =>  $cloc,
            self::M_EXECUTABLE_LINES_OF_CODE   =>  $eloc,
            self::M_LOGICAL_LINES_OF_CODE      =>  $lloc,
            self::M_NON_COMMENT_LINES_OF_CODE  =>  $ncloc
        );

        $this->updateProjectMetrics($id);

        $this->fireEndFile($compilationUnit);
    }

    /**
     * Visits a function node.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     */
    public function visitFunction(ASTFunction $function)
    {
        $this->fireStartFunction($function);

        $function->getCompilationUnit()->accept($this);

        if ($this->restoreFromCache($function)) {
            return $this->fireEndFunction($function);
        }

        list($cloc, $eloc, $lloc) = $this->linesOfCode(
            $function->getTokens(),
            true
        );

        $loc   = $function->getEndLine() - $function->getStartLine() + 1;
        $ncloc = $loc - $cloc;

        $this->metrics[$function->getId()] = array(
            self::M_LINES_OF_CODE              =>  $loc,
            self::M_COMMENT_LINES_OF_CODE      =>  $cloc,
            self::M_EXECUTABLE_LINES_OF_CODE   =>  $eloc,
            self::M_LOGICAL_LINES_OF_CODE      =>  $lloc,
            self::M_NON_COMMENT_LINES_OF_CODE  =>  $ncloc
        );

        $this->fireEndFunction($function);
    }

    /**
     * Visits a code interface object.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function visitInterface(ASTInterface $interface)
    {
        $this->fireStartInterface($interface);

        $interface->getCompilationUnit()->accept($this);

        foreach ($interface->getMethods() as $method) {
            $method->accept($this);
        }

        if ($this->restoreFromCache($interface)) {
            return $this->fireEndInterface($interface);
        }

        list($cloc) = $this->linesOfCode($interface->getTokens(), true);

        $loc   = $interface->getEndLine() - $interface->getStartLine() + 1;
        $ncloc = $loc - $cloc;

        $this->metrics[$interface->getId()] = array(
            self::M_LINES_OF_CODE              =>  $loc,
            self::M_COMMENT_LINES_OF_CODE      =>  $cloc,
            self::M_EXECUTABLE_LINES_OF_CODE   =>  0,
            self::M_LOGICAL_LINES_OF_CODE      =>  0,
            self::M_NON_COMMENT_LINES_OF_CODE  =>  $ncloc
        );

        $this->fireEndInterface($interface);
    }

    /**
     * Visits a method node.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function visitMethod(ASTMethod $method)
    {
        $this->fireStartMethod($method);

        if ($this->restoreFromCache($method)) {
            return $this->fireEndMethod($method);
        }
        
        if ($method->isAbstract()) {
            $cloc = 0;
            $eloc = 0;
            $lloc = 0;
        } else {
            list($cloc, $eloc, $lloc) = $this->linesOfCode(
                $method->getTokens(),
                true
            );
        }
        $loc   = $method->getEndLine() - $method->getStartLine() + 1;
        $ncloc = $loc - $cloc;

        $this->metrics[$method->getId()] = array(
            self::M_LINES_OF_CODE              =>  $loc,
            self::M_COMMENT_LINES_OF_CODE      =>  $cloc,
            self::M_EXECUTABLE_LINES_OF_CODE   =>  $eloc,
            self::M_LOGICAL_LINES_OF_CODE      =>  $lloc,
            self::M_NON_COMMENT_LINES_OF_CODE  =>  $ncloc
        );

        $this->classExecutableLines += $eloc;
        $this->classLogicalLines    += $lloc;

        $this->fireEndMethod($method);
    }

    /**
     * Updates the project metrics based on the node metrics identifier by the
     * given <b>$id</b>.
     *
     * @param  string $id The unique identifier of a node.
     * @return void
     */
    private function updateProjectMetrics($id)
    {
        foreach ($this->metrics[$id] as $metric => $value) {
            $this->projectMetrics[$metric] += $value;
        }
    }

    /**
     * Counts the Comment Lines Of Code (CLOC) and a pseudo Executable Lines Of
     * Code (ELOC) values.
     *
     * ELOC = Non Whitespace Lines + Non Comment Lines
     *
     * <code>
     * array(
     *     0  =>  23,  // Comment Lines Of Code
     *     1  =>  42   // Executable Lines Of Code
     * )
     * </code>
     *
     * @param  array   $tokens The raw token stream.
     * @param  boolean $search Optional boolean flag, search start.
     * @return array
     */
    private function linesOfCode(array $tokens, $search = false)
    {
        $clines = array();
        $elines = array();
        $llines = 0;

        $count = count($tokens);
        if ($search === true) {
            for ($i = 0; $i < $count; ++$i) {
                $token = $tokens[$i];

                if ($token->type === Tokens::T_CURLY_BRACE_OPEN) {
                    break;
                }
            }
        } else {
            $i = 0;
        }

        for (; $i < $count; ++$i) {
            $token = $tokens[$i];

            if ($token->type === Tokens::T_COMMENT
                || $token->type === Tokens::T_DOC_COMMENT
            ) {
                $lines =& $clines;
            } else {
                $lines =& $elines;
            }

            switch ($token->type) {
                // These statement are terminated by a semicolon
                //case \PDepend\Source\Tokenizer\Tokens::T_RETURN:
                //case \PDepend\Source\Tokenizer\Tokens::T_THROW:
                case Tokens::T_IF:
                case Tokens::T_TRY:
                case Tokens::T_CASE:
                case Tokens::T_GOTO:
                case Tokens::T_CATCH:
                case Tokens::T_WHILE:
                case Tokens::T_ELSEIF:
                case Tokens::T_SWITCH:
                case Tokens::T_DEFAULT:
                case Tokens::T_FOREACH:
                case Tokens::T_FUNCTION:
                case Tokens::T_SEMICOLON:
                    ++$llines;
                    break;
                case Tokens::T_DO:
                case Tokens::T_FOR:
                    // Because statements at least require one semicolon
                    --$llines;
                    break;
            }

            if ($token->startLine === $token->endLine) {
                $lines[$token->startLine] = true;
            } else {
                for ($j = $token->startLine; $j <= $token->endLine; ++$j) {
                    $lines[$j] = true;
                }
            }
            unset($lines);
        }
        return array(count($clines), count($elines), $llines);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer;

use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Metrics\AnalyzerFilterAware;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Metrics\AnalyzerProjectAware;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;

/**
 * This analyzer calculates class/namespace hierarchy metrics.
 *
 * This analyzer expects that a node list filter is set, before it starts the
 * analyze process. This filter will suppress PHP internal and external library
 * stuff.
 *
 * This analyzer is based on the following metric set:
 * - http://www.aivosto.com/project/help/pm-oo-misc.html
 *
 * This analyzer is based on the following metric set:
 * - http://www.aivosto.com/project/help/pm-oo-misc.html
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class HierarchyAnalyzer extends AbstractAnalyzer implements AnalyzerFilterAware, AnalyzerNodeAware, AnalyzerProjectAware
{
    /**
     * Metrics provided by the analyzer implementation.
     */
    const M_NUMBER_OF_ABSTRACT_CLASSES = 'clsa',
          M_NUMBER_OF_CONCRETE_CLASSES = 'clsc',
          M_NUMBER_OF_ROOT_CLASSES     = 'roots',
          M_NUMBER_OF_LEAF_CLASSES     = 'leafs';

    /**
     * Number of all analyzed functions.
     *
     * @var integer
     */
    private $fcs = 0;

    /**
     * Number of all analyzer methods.
     *
     * @var integer
     */
    private $mts = 0;

    /**
     * Number of all analyzed classes.
     *
     * @var integer
     */
    private $cls = 0;

    /**
     * Number of all analyzed abstract classes.
     *
     * @var integer
     */
    private $clsa = 0;

    /**
     * Number of all analyzed interfaces.
     *
     * @var integer
     */
    private $interfs = 0;

    /**
     * Number of all root classes within the analyzed source code.
     *
     * @var array(string=>boolean)
     */
    private $roots = array();

    /**
     * Number of all none leaf classes within the analyzed source code
     *
     * @var array(string=>boolean)
     */
    private $noneLeafs = array();

    /**
     * Hash with all calculated node metrics.
     *
     * <code>
     * array(
     *     '0375e305-885a-4e91-8b5c-e25bda005438'  =>  array(
     *         'loc'    =>  42,
     *         'ncloc'  =>  17,
     *         'cc'     =>  12
     *     ),
     *     'e60c22f0-1a63-4c40-893e-ed3b35b84d0b'  =>  array(
     *         'loc'    =>  42,
     *         'ncloc'  =>  17,
     *         'cc'     =>  12
     *     )
     * )
     * </code>
     *
     * @var array(string=>array)
     */
    private $nodeMetrics = null;

    /**
     * Processes all {@link \PDepend\Source\AST\ASTNamespace} code nodes.
     *
     * @param  \PDepend\Source\AST\ASTNamespace[] $namespaces
     * @return void
     */
    public function analyze($namespaces)
    {
        if ($this->nodeMetrics === null) {
            $this->fireStartAnalyzer();

            // Init node metrics
            $this->nodeMetrics = array();

            // Visit all nodes
            foreach ($namespaces as $namespace) {
                $namespace->accept($this);
            }

            $this->fireEndAnalyzer();
        }
    }

    /**
     * Provides the project summary metrics as an <b>array</b>.
     *
     * @return array(string=>mixed)
     */
    public function getProjectMetrics()
    {
        // Count none leaf classes
        $noneLeafs = count($this->noneLeafs);

        return array(
            self::M_NUMBER_OF_ABSTRACT_CLASSES  =>  $this->clsa,
            self::M_NUMBER_OF_CONCRETE_CLASSES  =>  $this->cls - $this->clsa,
            self::M_NUMBER_OF_ROOT_CLASSES      =>  count($this->roots),
            self::M_NUMBER_OF_LEAF_CLASSES      =>  $this->cls - $noneLeafs,
        );
    }

    /**
     * This method will return an <b>array</b> with all generated metric values
     * for the given <b>$node</b> instance. If there are no metrics for the
     * requested node, this method will return an empty <b>array</b>.
     *
     * @param  \PDepend\Source\AST\ASTArtifact $artifact
     * @return array(string=>mixed)
     */
    public function getNodeMetrics(ASTArtifact $artifact)
    {
        if (isset($this->nodeMetrics[$artifact->getId()])) {
            return $this->nodeMetrics[$artifact->getId()];
        }
        return array();
    }

    /**
     * Calculates metrics for the given <b>$class</b> instance.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     */
    public function visitClass(ASTClass $class)
    {
        if (false === $class->isUserDefined()) {
            return;
        }

        $this->fireStartClass($class);

        ++$this->cls;

        if ($class->isAbstract()) {
            ++$this->clsa;
        }

        $parentClass = $class->getParentClass();
        if ($parentClass !== null) {
            if ($parentClass->getParentClass() === null) {
                $this->roots[$parentClass->getId()] = true;
            }
            $this->noneLeafs[$parentClass->getId()] = true;
        }

        // Store node metric
        $this->nodeMetrics[$class->getId()] = array();

        foreach ($class->getMethods() as $method) {
            $method->accept($this);
        }
        foreach ($class->getProperties() as $property) {
            $property->accept($this);
        }

        $this->fireEndClass($class);
    }

    /**
     * Calculates metrics for the given <b>$function</b> instance.
     *
     * @param  \PDepend\Source\AST\ASTFunction $function
     * @return void
     */
    public function visitFunction(ASTFunction $function)
    {
        $this->fireStartFunction($function);
        ++$this->fcs;
        $this->fireEndFunction($function);
    }

    /**
     * Calculates metrics for the given <b>$interface</b> instance.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function visitInterface(ASTInterface $interface)
    {
        $this->fireStartInterface($interface);

        ++$this->interfs;

        foreach ($interface->getMethods() as $method) {
            $method->accept($this);
        }

        $this->fireEndInterface($interface);
    }

    /**
     * Visits a method node.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function visitMethod(ASTMethod $method)
    {
        $this->fireStartMethod($method);
        ++$this->mts;
        $this->fireEndMethod($method);
    }

    /**
     * Calculates metrics for the given <b>$namespace</b> instance.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespace
     * @return void
     */
    public function visitNamespace(ASTNamespace $namespace)
    {
        $this->fireStartNamespace($namespace);

        foreach ($namespace->getTypes() as $type) {
            $type->accept($this);
        }

        foreach ($namespace->getFunctions() as $function) {
            $function->accept($this);
        }

        $this->fireEndNamespace($namespace);
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer;

use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Metrics\Analyzer\CodeRankAnalyzer\StrategyFactory;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTArtifactList;

/**
 * Calculates the code rank metric for classes and namespaces.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class CodeRankAnalyzer extends AbstractAnalyzer implements AnalyzerNodeAware
{
    /**
     * Metrics provided by the analyzer implementation.
     */
    const M_CODE_RANK         = 'cr',
          M_REVERSE_CODE_RANK = 'rcr';

    /**
     * The used damping factor.
     */
    const DAMPING_FACTOR = 0.85;

    /**
     * Number of loops for the code range calculation.
     */
    const ALGORITHM_LOOPS = 25;

    /**
     * Option key for the code rank mode.
     */
    const STRATEGY_OPTION = 'coderank-mode';

    /**
     * All found nodes.
     *
     * @var array(string=>array)
     */
    private $nodes = array();

    /**
     * List of node collect strategies.
     *
     * @var \PDepend\Metrics\Analyzer\CodeRankAnalyzer\CodeRankStrategyI[]
     */
    private $strategies = array();

    /**
     * Hash with all calculated node metrics.
     *
     * <code>
     * array(
     *     '0375e305-885a-4e91-8b5c-e25bda005438'  =>  array(
     *         'loc'    =>  42,
     *         'ncloc'  =>  17,
     *         'cc'     =>  12
     *     ),
     *     'e60c22f0-1a63-4c40-893e-ed3b35b84d0b'  =>  array(
     *         'loc'    =>  42,
     *         'ncloc'  =>  17,
     *         'cc'     =>  12
     *     )
     * )
     * </code>
     *
     * @var array(string=>array)
     */
    private $nodeMetrics = null;

    /**
     * Processes all {@link \PDepend\Source\AST\ASTNamespace} code nodes.
     *
     * @param \PDepend\Source\AST\ASTNamespace[] $namespaces
     * @return void
     */
    public function analyze($namespaces)
    {
        if ($this->nodeMetrics === null) {
            $this->fireStartAnalyzer();

            $factory = new StrategyFactory();
            if (isset($this->options[self::STRATEGY_OPTION])) {
                foreach ($this->options[self::STRATEGY_OPTION] as $identifier) {
                    $this->strategies[] = $factory->createStrategy($identifier);
                }
            } else {
                $this->strategies[] = $factory->createDefaultStrategy();
            }

            // Register all listeners
            foreach ($this->getVisitListeners() as $listener) {
                foreach ($this->strategies as $strategy) {
                    $strategy->addVisitListener($listener);
                }
            }

            foreach ($namespaces as $namespace) {
                // Traverse all strategies
                foreach ($this->strategies as $strategy) {
                    $namespace->accept($strategy);
                }
            }

            // Collect all nodes
            foreach ($this->strategies as $strategy) {
                $collected    = $strategy->getCollectedNodes();
                $this->nodes = array_merge_recursive($collected, $this->nodes);
            }

            // Init node metrics
            $this->nodeMetrics = array();

            // Calculate code rank metrics
            $this->buildCodeRankMetrics();

            $this->fireEndAnalyzer();
        }
    }

    /**
     * This method will return an <b>array</b> with all generated metric values
     * for the given <b>$node</b>. If there are no metrics for the requested
     * node, this method will return an empty <b>array</b>.
     *
     * @param  \PDepend\Source\AST\ASTArtifact $artifact
     * @return array(string=>mixed)
     */
    public function getNodeMetrics(ASTArtifact $artifact)
    {
        if (isset($this->nodeMetrics[$artifact->getId()])) {
            return $this->nodeMetrics[$artifact->getId()];
        }
        return array();
    }

    /**
     * Generates the forward and reverse code rank for the given <b>$nodes</b>.
     *
     * @return void
     */
    protected function buildCodeRankMetrics()
    {
        foreach (array_keys($this->nodes) as $id) {
            $this->nodeMetrics[$id] = array(
                self::M_CODE_RANK          =>  0,
                self::M_REVERSE_CODE_RANK  =>  0
            );
        }
        foreach ($this->computeCodeRank('out', 'in') as $id => $rank) {
            $this->nodeMetrics[$id][self::M_CODE_RANK] = $rank;
        }
        foreach ($this->computeCodeRank('in', 'out') as $id => $rank) {
            $this->nodeMetrics[$id][self::M_REVERSE_CODE_RANK] = $rank;
        }
    }

    /**
     * Calculates the code rank for the given <b>$nodes</b> set.
     *
     * @param string $id1 Identifier for the incoming edges.
     * @param string $id2 Identifier for the outgoing edges.
     *
     * @return array(string=>float)
     */
    protected function computeCodeRank($id1, $id2)
    {
        $dampingFactory = self::DAMPING_FACTOR;

        $ranks = array();

        foreach (array_keys($this->nodes) as $name) {
            $ranks[$name] = 1;
        }

        for ($i = 0; $i < self::ALGORITHM_LOOPS; $i++) {
            foreach ($this->nodes as $name => $info) {
                $rank = 0;
                foreach ($info[$id1] as $ref) {
                    $previousRank = $ranks[$ref];
                    $refCount     = count($this->nodes[$ref][$id2]);

                    $rank += ($previousRank / $refCount);
                }
                $ranks[$name] = ((1 - $dampingFactory)) + $dampingFactory * $rank;
            }
        }
        return $ranks;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics\Analyzer;

use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Source\AST\AbstractASTClassOrInterface;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;

/**
 * This visitor generates the metrics for the analyzed namespaces.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class DependencyAnalyzer extends AbstractAnalyzer
{
    /**
     * Metrics provided by the analyzer implementation.
     */
    const M_NUMBER_OF_CLASSES          = 'tc',
          M_NUMBER_OF_CONCRETE_CLASSES = 'cc',
          M_NUMBER_OF_ABSTRACT_CLASSES = 'ac',
          M_AFFERENT_COUPLING          = 'ca',
          M_EFFERENT_COUPLING          = 'ce',
          M_ABSTRACTION                = 'a',
          M_INSTABILITY                = 'i',
          M_DISTANCE                   = 'd';
    /**
     * Hash with all calculated node metrics.
     *
     * <code>
     * array(
     *     '0375e305-885a-4e91-8b5c-e25bda005438'  =>  array(
     *         'loc'    =>  42,
     *         'ncloc'  =>  17,
     *         'cc'     =>  12
     *     ),
     *     'e60c22f0-1a63-4c40-893e-ed3b35b84d0b'  =>  array(
     *         'loc'    =>  42,
     *         'ncloc'  =>  17,
     *         'cc'     =>  12
     *     )
     * )
     * </code>
     *
     * @var array(string=>array)
     */
    private $nodeMetrics = null;

    protected $nodeSet = array();

    private $efferentNodes = array();

    private $afferentNodes = array();

    /**
     * All collected cycles for the input code.
     *
     * <code>
     * array(
     *     <namespace-id> => array(
     *         \PDepend\Source\AST\ASTNamespace {},
     *         \PDepend\Source\AST\ASTNamespace {},
     *     ),
     *     <namespace-id> => array(
     *         \PDepend\Source\AST\ASTNamespace {},
     *         \PDepend\Source\AST\ASTNamespace {},
     *     ),
     * )
     * </code>
     *
     * @var array(string=>array)
     */
    private $collectedCycles = array();

    /**
     * Processes all {@link \PDepend\Source\AST\ASTNamespace} code nodes.
     *
     * @param  \PDepend\Source\AST\ASTNamespace[] $namespaces
     * @return void
     */
    public function analyze($namespaces)
    {
        if ($this->nodeMetrics === null) {
            $this->fireStartAnalyzer();

            $this->nodeMetrics = array();

            foreach ($namespaces as $namespace) {
                $namespace->accept($this);
            }

            $this->postProcess();

            $this->calculateAbstractness();
            $this->calculateInstability();
            $this->calculateDistance();

            $this->fireEndAnalyzer();
        }
    }

    /**
     * Returns the statistics for the requested node.
     *
     * @param  \PDepend\Source\AST\AbstractASTArtifact $node
     * @return array
     */
    public function getStats(AbstractASTArtifact $node)
    {
        $stats = array();
        if (isset($this->nodeMetrics[$node->getId()])) {
            $stats = $this->nodeMetrics[$node->getId()];
        }
        return $stats;
    }

    /**
     * Returns an array of all afferent nodes.
     *
     * @param  \PDepend\Source\AST\AbstractASTArtifact $node
     * @return \PDepend\Source\AST\AbstractASTArtifact[]
     */
    public function getAfferents(AbstractASTArtifact $node)
    {
        $afferents = array();
        if (isset($this->afferentNodes[$node->getId()])) {
            $afferents = $this->afferentNodes[$node->getId()];
        }
        ksort($afferents);

        return $afferents;
    }

    /**
     * Returns an array of all efferent nodes.
     *
     * @param  \PDepend\Source\AST\AbstractASTArtifact $node
     * @return \PDepend\Source\AST\AbstractASTArtifact[]
     */
    public function getEfferents(AbstractASTArtifact $node)
    {
        $efferents = array();
        if (isset($this->efferentNodes[$node->getId()])) {
            $efferents = $this->efferentNodes[$node->getId()];
        }
        ksort($efferents);

        return $efferents;
    }

    /**
     * Returns an array of nodes that build a cycle for the requested node or it
     * returns <b>null</b> if no cycle exists .
     *
     * @param  \PDepend\Source\AST\AbstractASTArtifact $node
     * @return \PDepend\Source\AST\AbstractASTArtifact[]
     */
    public function getCycle(AbstractASTArtifact $node)
    {
        if (array_key_exists($node->getId(), $this->collectedCycles)) {
            return $this->collectedCycles[$node->getId()];
        }

        $list = array();
        if ($this->collectCycle($list, $node)) {
            $this->collectedCycles[$node->getId()] = $list;
        } else {
            $this->collectedCycles[$node->getId()] = null;
        }

        return $this->collectedCycles[$node->getId()];
    }

    /**
     * Visits a method node.
     *
     * @param  \PDepend\Source\AST\ASTMethod $method
     * @return void
     */
    public function visitMethod(ASTMethod $method)
    {
        $this->fireStartMethod($method);

        $namespace = $method->getParent()->getNamespace();
        foreach ($method->getDependencies() as $dependency) {
            $this->collectDependencies($namespace, $dependency->getNamespace());
        }

        $this->fireEndMethod($method);
    }

    /**
     * Visits a namespace node.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespace
     * @return void
     */
    public function visitNamespace(ASTNamespace $namespace)
    {
        $this->fireStartNamespace($namespace);

        $this->initNamespaceMetric($namespace);

        $this->nodeSet[$namespace->getId()] = $namespace;

        foreach ($namespace->getTypes() as $type) {
            $type->accept($this);
        }

        $this->fireEndNamespace($namespace);
    }

    /**
     * Visits a class node.
     *
     * @param  \PDepend\Source\AST\ASTClass $class
     * @return void
     */
    public function visitClass(ASTClass $class)
    {
        $this->fireStartClass($class);
        $this->visitType($class);
        $this->fireEndClass($class);
    }

    /**
     * Visits an interface node.
     *
     * @param  \PDepend\Source\AST\ASTInterface $interface
     * @return void
     */
    public function visitInterface(ASTInterface $interface)
    {
        $this->fireStartInterface($interface);
        $this->visitType($interface);
        $this->fireEndInterface($interface);
    }

    /**
     * Generic visit method for classes and interfaces. Both visit methods
     * delegate calls to this method.
     *
     * @param  \PDepend\Source\AST\AbstractASTClassOrInterface $type
     * @return void
     */
    protected function visitType(AbstractASTClassOrInterface $type)
    {
        $id = $type->getNamespace()->getId();

        // Increment total classes count
        ++$this->nodeMetrics[$id][self::M_NUMBER_OF_CLASSES];

        // Check for abstract or concrete class
        if ($type->isAbstract()) {
            ++$this->nodeMetrics[$id][self::M_NUMBER_OF_ABSTRACT_CLASSES];
        } else {
            ++$this->nodeMetrics[$id][self::M_NUMBER_OF_CONCRETE_CLASSES];
        }

        
        foreach ($type->getDependencies() as $dependency) {
            $this->collectDependencies(
                $type->getNamespace(),
                $dependency->getNamespace()
            );
        }

        foreach ($type->getMethods() as $method) {
            $method->accept($this);
        }
    }

    /**
     * Collects the dependencies between the two given namespaces.
     *
     * @param \PDepend\Source\AST\ASTNamespace $namespaceA
     * @param \PDepend\Source\AST\ASTNamespace $namespaceB
     *
     * @return void
     */
    private function collectDependencies(ASTNamespace $namespaceA, ASTNamespace $namespaceB)
    {
        $idA = $namespaceA->getId();
        $idB = $namespaceB->getId();

        if ($idB === $idA) {
            return;
        }

        // Create a container for this dependency
        $this->initNamespaceMetric($namespaceB);

        if (!in_array($idB, $this->nodeMetrics[$idA][self::M_EFFERENT_COUPLING])) {
            $this->nodeMetrics[$idA][self::M_EFFERENT_COUPLING][] = $idB;
            $this->nodeMetrics[$idB][self::M_AFFERENT_COUPLING][] = $idA;
        }
    }

    /**
     * Initializes the node metric record for the given <b>$namespace</b>.
     *
     * @param  \PDepend\Source\AST\ASTNamespace $namespace
     * @return void
     */
    protected function initNamespaceMetric(ASTNamespace $namespace)
    {
        $id = $namespace->getId();

        if (!isset($this->nodeMetrics[$id])) {
            $this->nodeSet[$id] = $namespace;

            $this->nodeMetrics[$id] = array(
                self::M_NUMBER_OF_CLASSES           =>  0,
                self::M_NUMBER_OF_CONCRETE_CLASSES  =>  0,
                self::M_NUMBER_OF_ABSTRACT_CLASSES  =>  0,
                self::M_AFFERENT_COUPLING           =>  array(),
                self::M_EFFERENT_COUPLING           =>  array(),
                self::M_ABSTRACTION                 =>  0,
                self::M_INSTABILITY                 =>  0,
                self::M_DISTANCE                    =>  0
            );
        }
    }

    /**
     * Post processes all analyzed nodes.
     *
     * @return void
     */
    protected function postProcess()
    {
        foreach ($this->nodeMetrics as $id => $metrics) {
            $this->afferentNodes[$id] = array();
            foreach ($metrics[self::M_AFFERENT_COUPLING] as $caId) {
                $this->afferentNodes[$id][] = $this->nodeSet[$caId];
            }

            sort($this->afferentNodes[$id]);

            $this->efferentNodes[$id] = array();
            foreach ($metrics[self::M_EFFERENT_COUPLING] as $ceId) {
                $this->efferentNodes[$id][] = $this->nodeSet[$ceId];
            }

            sort($this->efferentNodes[$id]);

            $afferent = count($metrics[self::M_AFFERENT_COUPLING]);
            $efferent = count($metrics[self::M_EFFERENT_COUPLING]);

            $this->nodeMetrics[$id][self::M_AFFERENT_COUPLING] = $afferent;
            $this->nodeMetrics[$id][self::M_EFFERENT_COUPLING] = $efferent;
        }
    }

    /**
     * Calculates the abstractness for all analyzed nodes.
     *
     * @return void
     */
    protected function calculateAbstractness()
    {
        foreach ($this->nodeMetrics as $id => $metrics) {
            if ($metrics[self::M_NUMBER_OF_CLASSES] !== 0) {
                $this->nodeMetrics[$id][self::M_ABSTRACTION] = (
                    $metrics[self::M_NUMBER_OF_ABSTRACT_CLASSES] /
                    $metrics[self::M_NUMBER_OF_CLASSES]
                );
            }

        }
    }

    /**
     * Calculates the instability for all analyzed nodes.
     *
     * @return void
     */
    protected function calculateInstability()
    {
        foreach ($this->nodeMetrics as $id => $metrics) {
            // Count total incoming and outgoing dependencies
            $total = (
                $metrics[self::M_AFFERENT_COUPLING] +
                $metrics[self::M_EFFERENT_COUPLING]
            );

            if ($total !== 0) {
                $this->nodeMetrics[$id][self::M_INSTABILITY] = (
                    $metrics[self::M_EFFERENT_COUPLING] / $total
                );
            }
        }
    }

    /**
     * Calculates the distance to an optimal value.
     *
     * @return void
     */
    protected function calculateDistance()
    {
        foreach ($this->nodeMetrics as $id => $metrics) {
            $this->nodeMetrics[$id][self::M_DISTANCE] = abs(
                ($metrics[self::M_ABSTRACTION] + $metrics[self::M_INSTABILITY]) - 1
            );
        }
    }

    /**
     * Collects a single cycle that is reachable by this namespace. All namespaces
     * that are part of the cylce are stored in the given <b>$list</b> array.
     *
     * @param  \PDepend\Source\AST\ASTNamespace[] &$list
     * @param  \PDepend\Source\AST\ASTNamespace   $namespace
     * @return boolean If this method detects a cycle the return value is <b>true</b>
     *                 otherwise this method will return <b>false</b>.
     */
    protected function collectCycle(array &$list, ASTNamespace $namespace)
    {
        if (in_array($namespace, $list, true)) {
            $list[] = $namespace;
            return true;
        }

        $list[] = $namespace;

        foreach ($this->getEfferents($namespace) as $efferent) {
            if ($this->collectCycle($list, $efferent)) {
                return true;
            }
        }

        if (is_int($idx = array_search($namespace, $list, true))) {
            unset($list[$idx]);
        }
        return false;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */

namespace PDepend\Metrics;

use PDepend\Util\Cache\CacheDriver;

/**
 * Simple marker interface that is used to mark an analyzer as cache aware. This
 * means that the loading infrastructure code will inject an instance of
 * {@link \PDepend\Util\Cache\CacheDriver} into this analyzer.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */
interface AnalyzerCacheAware extends Analyzer
{
    /**
     * Setter method for the system wide used cache.
     *
     * @param  \PDepend\Util\Cache\CacheDriver $cache
     * @return void
     */
    public function setCache(CacheDriver $cache);
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.10
 */

namespace PDepend\Metrics;

/**
 * Filter iterator that only returns enabled {@link \PDepend\Metrics\Analyzer}
 * instances.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 0.9.10
 */
class AnalyzerIterator extends \FilterIterator
{
    /**
     * Constructs a new iterator instance.
     *
     * @param \PDepend\Metrics\Analyzer[] $analyzers
     */
    public function __construct(array $analyzers)
    {
        parent::__construct(new \ArrayIterator($analyzers));
    }

    /**
     * Returns <b>true</b> when the current analyzer instance is enabled.
     *
     * @return boolean
     */
    public function accept()
    {
        return $this->getInnerIterator()->current()->isEnabled();
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics;

use PDepend\Source\AST\ASTArtifactList;

/**
 * Base interface for all analyzer implementations.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface Analyzer
{
    /**
     * Constructs a new analyzer instance.
     *
     * @param array(string=>mixed) $options Global option array, every analyzer
     *                                      can extract the required options.
     */
    public function __construct(array $options = array());
    
    /**
     * Adds a listener to this analyzer.
     *
     * @param  \PDepend\Metrics\AnalyzerListener $listener The listener instance.
     * @return void
     */
    public function addAnalyzeListener(AnalyzerListener $listener);
    
    /**
     * Processes all {@link \PDepend\Source\AST\ASTNamespace} code nodes.
     *
     * @param  \PDepend\Source\AST\ASTNamespace[] $namespaces
     * @return void
     */
    public function analyze($namespaces);

    /**
     * An analyzer that is active must return <b>true</b> to recognized by
     * pdepend framework, while an analyzer that does not perform any action
     * for any reason should return <b>false</b>.
     *
     * @return boolean
     * @since  0.9.10
     */
    public function isEnabled();

    /**
     * Set global options
     *
     * @param array(string=>mixed) $options
     * @since 2.0.1
     */
    public function setOptions(array $options = array());
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics;

use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Creates Analyzer instances
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class AnalyzerFactory
{
    /**
     * @var \Symfony\Component\DependencyInjection\ContainerInterface
     */
    private $container;

    /**
     * Create a new Analyzer Factory
     *
     * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
     */
    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    /**
     * Create and configure all analyzers required for given set of loggers.
     *
     * @param  \PDepend\Report\ReportGenerator[] $generators
     * @return \PDepend\Metrics\Analyzer[]
     */
    public function createRequiredForGenerators(array $generators)
    {
        $analyzers = array();

        foreach ($generators as $logger) {
            foreach ($logger->getAcceptedAnalyzers() as $type) {
                $analyzers[$type] = $this->container->get($type);
            }
        }

        return $analyzers;
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics;

use PDepend\Source\ASTVisitor\AbstractASTVisitor;

/**
 * This abstract class provides a base implementation of an analyzer.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
abstract class AbstractAnalyzer extends AbstractASTVisitor implements Analyzer
{
    /**
     * Global options array.
     *
     * @var array(string=>mixed)
     */
    protected $options = array();

    /**
     * List or registered listeners.
     *
     * @var \PDepend\Metrics\AnalyzerListener[]
     */
    private $listeners = array();

    /**
     * Constructs a new analyzer instance.
     *
     * @param array(string=>mixed) $options Global option array, every analyzer
     *                                      can extract the required options.
     */
    public function __construct(array $options = array())
    {
        $this->options = $options;
    }

    /**
     * Set global options
     *
     * @param array(string=>mixed) $options Global option array, every analyzer
     *                                      can extract the required options.
     */
    public function setOptions(array $options = array())
    {
        $this->options = $options;
    }

    /**
     * Adds a listener to this analyzer.
     *
     * @param  \PDepend\Metrics\AnalyzerListener $listener The listener instance.
     * @return void
     */
    public function addAnalyzeListener(\PDepend\Metrics\AnalyzerListener $listener)
    {
        if (in_array($listener, $this->listeners, true) === false) {
            $this->listeners[] = $listener;
        }
    }

    /**
     * An analyzer that is active must return <b>true</b> to recognized by
     * pdepend framework, while an analyzer that does not perform any action
     * for any reason should return <b>false</b>.
     *
     * By default all analyzers are enabled. Overwrite this method to provide
     * state based disabling/enabling.
     *
     * @return boolean
     * @since  0.9.10
     */
    public function isEnabled()
    {
        return true;
    }

    /**
     * The analyzer implementation should call this method when it starts the
     * code processing. This method will send an analyzer start event to all
     * registered listeners.
     *
     * @return void
     */
    protected function fireStartAnalyzer()
    {
        foreach ($this->listeners as $listener) {
            $listener->startAnalyzer($this);
        }
    }

    /**
     * The analyzer implementation should call this method when it has finished
     * the code processing. This method will send an analyzer end event to all
     * registered listeners.
     *
     * @return void
     */
    protected function fireEndAnalyzer()
    {
        foreach ($this->listeners as $listener) {
            $listener->endAnalyzer($this);
        }
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics;

use PDepend\Source\ASTVisitor\ASTVisitListener;

/**
 * An implementation of this listener can be used to recieve informations about
 * the current metric analyzer.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface AnalyzerListener extends ASTVisitListener
{
    /**
     * This method is called when the analyzer starts code processing.
     *
     * @param  \PDepend\Metrics\Analyzer $analyzer The context analyzer instance.
     * @return void
     */
    public function startAnalyzer(Analyzer $analyzer);
    
    /**
     * This method is called when the analyzer has finished code processing.
     *
     * @param  \PDepend\Metrics\Analyzer $analyzer The context analyzer instance.
     * @return void
     */
    public function endAnalyzer(Analyzer $analyzer);
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics;

/**
 * This analyzer interface provides a specialized form that allows an analyzer
 * to aggregate metrics calculated by other analyzers.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface AggregateAnalyzer extends Analyzer
{
    /**
     * This method must return an <b>array</b> of class names for required
     * analyzers.
     *
     * @return array(string)
     */
    public function getRequiredAnalyzers();
    
    /**
     * Adds a required sub analyzer.
     *
     * @param  \PDepend\Metrics\Analyzer $analyzer The sub analyzer instance.
     * @return void
     */
    public function addAnalyzer(Analyzer $analyzer);
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics;

use PDepend\Source\AST\ASTArtifact;

/**
 * Marker interface that marks a result set as node metrics aware.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface AnalyzerNodeAware extends Analyzer
{
    /**
     * This method will return an <b>array</b> with all generated metric values
     * for the node with the given <b>$id</b> identifier. If there are no
     * metrics for the requested node, this method will return an empty <b>array</b>.
     *
     * <code>
     * array(
     *     'loc'    =>  42,
     *     'ncloc'  =>  17,
     *     'cc'     =>  12
     * )
     * </code>
     *
     * @param  \PDepend\Source\AST\ASTArtifact $artifact
     * @return array(string=>mixed)
     */
    public function getNodeMetrics(ASTArtifact $artifact);
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */

namespace PDepend\Metrics;

use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Util\Cache\CacheDriver;

/**
 * This abstract class provides an analyzer that provides the basic infrastructure
 * for caching.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @since 1.0.0
 */
abstract class AbstractCachingAnalyzer extends AbstractAnalyzer implements AnalyzerCacheAware
{
    /**
     * Collected node metrics
     *
     * @var array
     */
    protected $metrics = null;

    /**
     * Metrics restored from the cache. This property is only used temporary.
     *
     * @var array
     */
    private $metricsCached = array();

    /**
     * Injected cache driver.
     *
     * @var \PDepend\Util\Cache\CacheDriver
     */
    private $cache;

    /**
     * Setter method for the system wide used cache.
     *
     * @param  \PDepend\Util\Cache\CacheDriver $cache
     * @return void
     */
    public function setCache(CacheDriver $cache)
    {
        $this->cache = $cache;
    }

    /**
     * Getter method for the system wide used cache.
     *
     * @return \PDepend\Util\Cache\CacheDriver $cache
     */
    public function getCache()
    {
        return $this->cache;
    }

    /**
     * Tries to restore the metrics for a cached node. If this method has
     * restored the metrics it will return <b>TRUE</b>, otherwise the return
     * value will be <b>FALSE</b>.
     *
     * @param  \PDepend\Source\AST\AbstractASTArtifact $node
     * @return boolean
     */
    protected function restoreFromCache(AbstractASTArtifact $node)
    {
        $id = $node->getId();
        if ($node->isCached() && isset($this->metricsCached[$id])) {
            $this->metrics[$id] = $this->metricsCached[$id];
            return true;
        }
        return false;
    }

    /**
     * Initializes the previously calculated metrics from the cache.
     *
     * @return void
     */
    protected function loadCache()
    {
        $this->metricsCached = (array) $this->cache
            ->type('metrics')
            ->restore(get_class($this));
    }

    /**
     * Unloads the metrics cache and stores the current set of metrics in the
     * cache.
     *
     * @return void
     */
    protected function unloadCache()
    {
        $this->cache
            ->type('metrics')
            ->store(get_class($this), $this->metrics);

        $this->metricsCached = array();
    }
}
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Metrics;

/**
 * Simple marker interface that is used to mark an analyzer as namespace filter
 * aware. This means that a defined namespace filter for external dependencies
 * on namespaces an its classes and interfaces must be set before this analyzer
 * starts.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
interface AnalyzerFilterAware extends Analyzer
{
}
pdepend-2.5.0 (2017/01/19)
==========================

This release closes a parsing bug in PDepend 2.4.1, starts with the 
implementation of PHP 7.1 support and adds a new attribute for the 
fully-qualified-classname to the summary report.

- Fixed #282: Issue with grouped use statements when only a single 
  level namespace prefix was used. Fixed in commit #3e523f5.
- Implemented #294: Add support for PHP 7.1 optionals. Implemented in 
  commit #c5c53eb.
- Implemented #88: Fully qualified classname in summary report. 
  Implemented in commit #13e9cbc.

pdepend-2.4.1 (2017/01/11)
==========================

This release closes a bug within PDepend's parser when keywords are 
used as method or constant names in PHP 7.0

- Fixes an issue with methods or constants with keyword identifiers 
  called/accessed in PHP 7. Fixed in commit #8f07ac7.

pdepend-2.4.0 (2017/01/10)
==========================

This release implements language features like Anonymous Classes, 
Group use Declarations, Uniform Variable Syntax or Loosening Reserved 
Word Restrictions that were introduced with PHP 7.0, so that PDepend 
2.4 is now PHP 7.0 compatible.

- Fixed #281: PHP 7 - Anonymous Class - Internal parser state issues 
  Fixed in commit #00a61c6.
- Fixed #285: Parse the magic constant __TRAIT__ Fixed in commit 
  #b76e2b0.
- Fixed #210: Partial Class Namespace is Calculated Twice: in Global 
  and it's Own Namespace Fixed in commit #e81411f.
- Implemented #280: Refactor SymbolTable Implemented in commit 
  #1265259.
- Implemented #282: PHP 7 - Group use declarations Implemented in 
  commit #fd4aaca.
- Implemented #269: Unexpected token: :: (implicit object / method 
  usage) Implemented in commit #e611915.
- Implemented #204: Support for the ... operator in function calls 
  Implemented in commit #078e532.
- Implemented #290: Unexpected token: ARRAY (reserved keyword as a 
  class constant) Implemented in commit #d4bf7bb.

pdepend-2.3.2 (2016/11/23)
==========================

Bugfix release that closes a caching issue that was introduced in 
2.3.1.

- Fixed #276: Uncaught Error: Call to a member function type() on null 
  in Fixed in commit #48d8081.
- Allow list as method name under PHP 7 Fixed in commit #4968ed4.
- Fixed #277: serialize(): "comment" is returned from __sleep multiple 
  times in store in FileCacheDriver.php Fixed in commit #31cf053.

pdepend-2.3.1 (2016/11/23)
==========================



- Fixed #250: Updating ASTAnonymousClass to implement ASTNode, 
  retaining class behavior. Fixed in commit #2111906.

pdepend-2.3.0 (2016/11/22)
==========================

This release closes multiple bugs/issue and has merged several 
outstanding pull requests. Beside that it is now possible to pipe 
source through STDIN into pdepend.

- Fixed #263: Fix NPath calculations for the ternary operator. Fixed 
  in commit #df0e9c5.
- Fixed #260: Fix typos Fixed in commit #20b36c1.
- Fixed #259: DOMDocument file handling. Fixed in commit #fa2afc6.
- Fixed #247: Fix handling of use declarations with const and function 
  keywords. Fixed in commit #dc9128b.
- Fixed #240: Fix some typos from the website. Fixed in commit 
  #332672a.
- Fixed #249: Unexpected token: callable Fixed in commit #.
- Support for PHP's ** pow expression implemented. Implemented in 
  commit #bce6145.
- Implemented #262: Support stdin implemented. Implemented in commit 
  #3ef2328.
- Implemented #231: Apply the filter on files as well. Implemented in 
  commit #62d1406.

pdepend-2.2.6 (2016/10/04)
==========================

Bugfix release.

- Fixed #267: Fix UnexpectedTokenException on null coalesce operator 
  Fixed in commit #8e80aaa.

pdepend-2.2.4 (2016/03/10)
==========================

This releases closes a bug in PDepend's parsing code for PHP 7 return 
types, that caused a invalid state in the internal AST representation. 
This bug was issued in PHPMD's issue tracker first by user radmen.

- Cannot create new nodes, when internal state is frozen. #328 Fixed 
  in commit #ffe9957.

pdepend-2.2.3 (2016/02/22)
==========================

This release includes several pending pull requests from GitHub. 
Beside that this release adds support for complex expressions in 
property, constant and parameter declarations, introduced with PHP 
5.6.

- Fixed #226: Fixed division by zero issue. Fixed in commit #fb46614.
- Fixed #227: Fix support to files filters. Fixed in commit #4e150db.
- Fixed #230: Fix handling cygwin home folder location. Fixed in 
  commit #126c38a.
- Implemented #221: Add --quiet option. Implemented in commit 
  #9a710f7.
- Implemented #236: Switch to PSR-4 for autoloading Implemented in 
  commit #57b54bd.
- Implemented #238: Unexpected token errors for 5.6 "constant 
  expression" initializers. Implemented in commit #0087c94.

pdepend-2.2.2 (2015/10/16)
==========================

This release adds a new analyzer that can be used to visualize 
namespace dependencies.

- Implemented #221: Added line numbers to summary log. Implemented in 
  commit #a975553.
- Implemented #222: Calculate type dependencies. Implemented in commit 
  #8a924f6.

pdepend-2.2.1 (2015/09/24)
==========================

With this release we made a dependency downgrade, so that we can 
support more environments.

- Implemented #223: Minimum Symfony version downgraded to 2.3. 
  Implemented in commit #8601cc3.

pdepend-2.2.0 (2015/09/19)
==========================

This release contains beside several contributed additions and 
bugfixes better support for PHP 7 language constructs.

- Fixed #119: PDepend doesn't follow any symlinks to directories. 
  Fixed in commit #b80ae7e.
- Fixed #143: Truncated summary when analyzing ISO-8859-1 input. Fixed 
  in commit #d979462.
- Fixed #193: Cache conflict when executing pdepend in parallel. Fixed 
  in commit #a4e20ff.
- Fixed #197: Warning: DOMNode::cloneNode(): ID <id> already defined 
  in phar. Fixed in commit #2221f74.
- Fixed #201: ShellCheck warnings in scripts/compare.sh Fixed in 
  commit #.
- Fixed #209: PHP 5.6 constant syntax not supported. Fixed in commit 
  #1209b0e.
- Fixed #213: PHP 7: T_CHARACTER and T_BAD_CHARACTER are no longer 
  defined. Fixed in commit #1f5b051.
- Fixed #214: PHP 7: Return types not supported. Fixed in commit 
  #249932b.

pdepend-2.1.0 (2015/05/21)
==========================

This release introduces an analyzer for the Halstead metrics and the 
maintainability index, contributed by Matthias Mullie. Beside that we 
have closed several issues and bugs in PDepend's source code.

- Fixed #196: Fix Typo in phpDoc Fixed in commit #2b51fed.
- Fixed #200: Fix annotation-typo in AbstractPHPParser.php Fixed in 
  commit #776529d.
- Fixed #202: Support for variable arg list implemented Fixed in 
  commit #dff2547.
- Implemented #177: HHVM support Implemented in commit #48ee5d9.
- Implemented #185: Remove unused imports and order alphabetically 
  Implemented in commit #46d5fb.
- Implemented #198: Add analyzers for Halstead measures & 
  maintainability index Implemented in commit #3497862.

pdepend-2.0.6 (2015/03/02)
==========================

Concurrency issue in the file cache garbage collector fixed.

- Suppress exceptions when there are concurrency issues within the 
  garbage collector. Fixed in commit #3e31cc7.

pdepend-2.0.5 (2015/02/27)
==========================

This release just adds a simple garbage collector for PDepend's file 
cache

- Garbage collector for old cache files added. Implemented in commit 
  #56712b1.

pdepend-2.0.4 (2014/12/04)
==========================

This release closes some minor issues and incorporates several 
outstanding pull requests.

- Fixed #187: Unexpected token :?> with broken up switch statement 
  Fixed in commit #c12ee0e.
- Fixed #180: Unexpected token: <<, line: 5, col: 27 Fixed in commit 
  #4df5b9d.
- Fixed #179: Fixed display of duration longer than one hour Fixed in 
  commit #1288292.
- Fixed #176: Typo on website fixed. Fixed in commit #6a8e542.
- Fixed #175: Inconsistent indention in phpunit.dist.xml file fixed. 
  Fixed in commit #bc758e4.
- Fixed #174: Fix conflicting import: "Extension" is already in use in 
  the "PDepend\DependencyInjection" namespace. Fixed in commit 
  #e3e672b.
- Fixed #173: Fixing parsing True/False keywords in namespaces: Usage 
  of true and false keywords are allowed in namespace declarations in 
  PHP. Fixed in commit #d96e4e7.
- Fixed #170: invalid xml-report after parsing traits Fixed in commit 
  #1d1bec0.
- Fixed #167: Fix Invalid argument supplied for foreach() in 
  FileCacheDriver.php Fixed in commit #73d32f3.
- Fixed #165: Fix FileUtil::getUserHomeDir on Mac Fixed in commit 
  #4826c3f.
- Fixed #164: Empty yields raise Fatal error: When using empty yields 
  yield; the parser raises an fatal error. Fixed in commit #7ab0736.
- Fixed #163: File cache concurrency fix: Fixes concurrent run of 
  pdepend and phpmd. Fixed in commit #3955c07.
- Fixed #154: Invalid trait conflict errors: t is completely valid to 
  mix traits in PHP that have the same methods declared, as long as 
  only one of them is concrete (all the others must be abstract). 
  Fixed in commit #45ab1d3.
- Fixed #128: Problem when I use parent:: in trait Fixed in commit 
  #a73e6de.
- Implemented #177: HHVM support Implemented in commit #17da34b.

pdepend-2.0.3 (2014/10/08)
==========================

This is a bugfix release which closes some minor issues.

- Fixed #129: Windows+Composer install fails due to "path too long" 
  Fixed in commit #64f95c1.
- Fixed #172: Outdated news on the website
- Fixed #166: Added support for foreach with list statement (PHP 5.5) 
  Fixed in commit #a744af1.
- Fixed #171: The list usage in foreach loops reports an invalid token 
  Fixed in commit #a744af1.

pdepend-2.0.2 (2014/09/16)
==========================



- Fixed #160: include_once PDepend/Util/Coverage/CloverReport.php: 
  failed to open stream Fixed in commit #4dca605.
- Implemented #105: Support Java style array notations in doc comments 
  Implemented in commit #2ec5166.

pdepend-2.0.1 (2014/09/09)
==========================

Bug fix release which closes a issue within PDepend's C.R.A.P. index 
calculation.

- Handle code surrounded by @codeCoverageIgnore annotations correct. 
  Fixed in commit #3e67aa2.

pdepend-2.0.0 (2014/05/21)
==========================

New mayor release of PDepend.

- Fixed #126: Allow closure as array element Fixed in commit #b9775ac.
- Fixed #153: Support for new finally keyword implemented. Fixed in 
  commit #e536e7a.
- Fixed #144: pdepend --version gives me a wrong message.. Fixed in 
  commit #f6acea9.
- Implemented #113: Specify license, BSD license was missing in 
  composer.json file. Implemented in commit #3ba9c9e.
- Implemented #117: Adds composer autoload info Implemented in commit 
  #e624f8e.

pdepend-1.1.1 (2013/07/25)
==========================

Closes several PHP 5.4 issues.

- Fixed #116: Adding a fix for PHP 5.4 style arrays. Fixed in commit 
  #cbfddaa.
- Fixed #95: PHP 5.4 array syntax is not supported in property 
  initialization. Fixed in commit #f6ee217.
- Fixed #97: protected property PHP_Depend_Code_Method::$parent Fixed 
  in commit #87a1b5e.
- Fixed #104: Syntax errors reported when PHP 5.4 short array syntax 
  is used in method signatures or class variable definitions. Fixed in 
  commit #d731fa6.
- Fixed #103: Fix syntax error in composer.json example Fixed in 
  commit #e897a66.
- Implemented #101: Package name for chart svg Implemented in commit 
  #479aaa5.

pdepend-1.1.0 (2012/09/12)
==========================

This release closes a critical issue in the context of traits 
handling.

- Changed type of Node/Trait Fixed in commit #806eaab.
- Changed to PSR1 coding standard. Implemented in commit #.

pdepend-1.0.7 (2012/04/29)
==========================

This release closes a minor bug within the parsing code for doc 
comments..

- Fixed: DocComment is sometimes incorrectly set for functions Fixed 
  in commit #ac71753.

pdepend-1.0.6 (2012/04/22)
==========================

This release closes a bug with traits that were introduced with PHP 
5.4. This bug results in an E_FATAL when PHP_Depend performs coupling 
analysis on a trait.

- Fixed: E_FATAL when the coupling analyzer processes a trait. Fixed 
  in commit #ac71753.
- Added: Composer support Implemented in commit #3d98f02.

pdepend-1.0.5 (2012/04/05)
==========================

This release closes a bug introduced with the last release, which 
causes PHP_Depend not to flush it's metric cache when a file has 
changed.

- Fixed #27588643: PHP_Depend doesn't invalidate the cache. Fixed in 
  commit #99d5c13.

pdepend-1.0.4 (2012/02/25)
==========================

This release closes an issue introduced with the last release. It 
closes one more regression related to PHP's memory_limit and the 
Suhosin patch.

- Fixed fatal error due to bug in memory_limit modification code. 
  Fixed in commit #b869eff.

pdepend-1.0.3 (2012/02/25)
==========================

This release closes a minor issue in PHP_Depend's memory handling when 
it is run in a PHP environment that uses the Suhosin patch and the 
suhosin.memory_limit setting.

- Fixed #25450915: Alert disable memory_limit Fixed in commit 
  #0628e7d.

pdepend-1.0.2 (2012/02/15)
==========================

This release contains a huge improvement in PHP_Depend's memory usage. 
Due to some changes in the caching behavior we got a memory reduction 
of ~ 90%, measured against medium sized code bases like Symfony2 or 
FLOW3.

- Fixed #24732243: pdepend fails on 'const' Fixed in commit #4d6a687.
- Fixed #24975343: PHP_Depend doesn't handle nested list expressions. 
  Fixed in commit #d124ef0.
- Implemented #24702477: Huge memory footprint Implemented in commit 
  #75c9755.

pdepend-1.0.1 (2012/02/08)
==========================

This release fixes two bugs in PHP_Depend's parser, which resulted in 
uncatchable errors.

- Fixed #24635313: _parseOptionalExpression() returning null causes 
  exception Fixed in commit #97189b0.
- Fixed #24638569: pdepend crashes on vanilia drupal site Fixed in 
  commit #f20f40a.

pdepend-1.0.0 (2012/02/04)
==========================

Now that we have completed support for all the new language features 
introduced with PHP 5.4, we are ready to release version 1.0.0 of 
PHP_Depend. PHP_Depend can now handle traits, static closures, binary 
numbers, the callable type hint and the new short array syntax. Beside 
that, we have spent much effort in improving PHP_Depend's overall 
performance and we got an average speed gain of ~ 15% for processing 
major frameworks like Symfony2 or FLOW3, when PHP_Depend's file cache 
(default setup) is used. Additionally this release closes several 
minor issues in PHP_Depend.

- Fixed #18976391: PHP_Depend's file cache implementation does not 
  work with PHP 5.4. Fixed in commit #06ce51a.
- Fixed #18459091: PDepend task never ends, if there is an incorrect 
  inheritance Fixed in commit #13b5d12.
- Fixed #19875155: Implement static closures Fixed in commit #1e24a34.
- Implemented #8927307: Add support for traits Implemented in commit 
  #84f612e.
- Implemented #19874825: Implement the short array syntax introduced 
  with PHP 5.4 Implemented in commit #338bca2.
- Implemented #9069837: Implement expression lists. Implemented in 
  commit #bbb06c7.
- Implemented #21435399: Implement PHP 5.4 variable method names 
  Implemented in commit #911b6ec.
- Implemented #21408469: Implement PHP 5.4 binary number format 
  Implemented in commit #e3bccf1.
- Implemented #21339411: Implement PHP 5.4 callable type hint 
  Implemented in commit #ee5caa6.
- Implemented #21271399: Deprecate the --phpunit-xml log option 
  Implemented in commit #658c25c.
- Implemented #19817309: Implement PHP 5.4 array dereferencing 
  Implemented in commit #6dba831.

pdepend-0.10.9 (2012/01/25)
===========================

This release fixes a small issue in PHP_Depend's parser, which results 
in an exception when heredoc was used as property or constant 
initializer.

- Fixed #23951621: PHP_Depend fails on Heredocs and Nowdocs in 
  property declaration. Fixed in commit #373c478.

pdepend-0.10.8 (2012/01/24)
===========================

This release closes an issue in PHP_Depend's parser that produces 
invalid package names when the source file contains a statement before 
the class or interface doc comment.

- Fixed #23905939: Package gets lost when prefixed with control 
  structure Fixed in commit #b62bed7.

pdepend-0.10.7 (2011/12/06)
===========================

This release closes a critical bug in PHP_Depend's parser which 
results in an E_FATAL. This can happen when a control structure does 
not contain a body or termination token.

- E_FATAL when a control structure like if, for or foreach does not 
  contain a body or a termination symbol. Fixed in commit #b367a41.

pdepend-0.10.6 (2011/08/21)
===========================

This release closes a critical bug in PHP_Depend's parser that 
produced false positiv error messages for classes named like 'True', 
'False' or 'Null'

- Fixed #17264279: Unexpected token: True, line: 348, col: 49, 
  file:... Fixed in commit #5ac3e55.

pdepend-0.10.5 (2011/05/20)
===========================

This release closes two minor bugs in PHP_Depend. One incompatibility 
with PHP 5.2.x versions and one bug related to PHP_Depend's log 
behavior when PHP_Depend analyzes unstructured source code. This 
release was published on May the 20th 2011.

- Fixed #13255437: PHP 5.2 Compatibility Issues. Fixed in commit 
  #8d4a095.
- Fixed #13405179: PHP Depend report is not generated if all files do 
  not contain a class nor a function. Fixed in commit #554ade1.

pdepend-0.10.4 (2011/04/09)
===========================

This release contains an improvement in PHP_Depend's memory 
consumption. We have optimized the internal data structures in such a 
way that the memory footprint was reduced by ~30%. These values were 
measured for currently popular frameworks with a medium to large sized 
code base. The tests were run under ubuntu with PHP 5.2.17 and PHP 
5.3.6.

pdepend-0.10.3 (2011/03/02)
===========================

This release closes a critial bug in PHP_Depend's analyzer locator 
code that prevents PHP_Depend from running on windows. This release 
was published on March the 02th 2011.

- Fixed #10659085: Analyzer locator code does not work on windows. 
  Fixed in commit #0101798.

pdepend-0.10.2 (2011/02/28)
===========================

This release of PHP_Depend closes two bugs. One related to the start 
and end line properties of object property nodes in the syntax tree. 
The second fix closes a bug in PHP_Depend's implementation of the WMCi 
metric. Beside these two fixes this release implements three minor 
features, one design issue in the syntax tree api and the other two 
other features are related to the new metrics CE, CA, CBO and NPM. 
Additionally we have restructured PHP_Depend's directory structure 
from a custom, freestyle format to a directory layout that is similar 
to maven's convention. With this change we have fixed several issues 
and workarounds in PHP_Depend's build process.

- Fixed #9936901: WMCi calculation is incorrect for overwritten 
  methods. Fixed in commit #69d079a.
- Fixed #8927377: Invalid Start/End Line/Column for object property 
  access. Fixed in commit #fc57264.
- Implemented #9069393: Replace optional NULL argument of setPackage() 
  with separate method. Implemented in commit #1282cdb.
- Implemented #9069871: Implement efferent- and afferent-coupling for 
  classes. Implemented in commit #07537c2.
- Implemented #9997915: Implement Number of Public Methods metric. 
  Implemented in commit #2dd3ebf.

pdepend-0.10.1 (2011/02/06)
===========================

- Fixed #9634613: Notice: Undefined property $___temp___. Fixed in 
  commit #5fb6900.

pdepend-0.10.0 (2011/02/05)
===========================

This version only contains a small bugfix compared to the last release 
canditate. Version 0.10.0 of PHP_Depend was released on February the 
05th 2011. The key feature for this release is the overall performance 
of PHP_Depend. Therefore we have implemented a new caching layer that 
reuses already calculated analyzes-results much more efficient than 
older versions of PHP_Depend. With these modifications we have 
achieved a performance gain of 100% and more for consecutive 
analysis-runs. This final release only fixes a small bug in 
PHP_Depend's analyzer class locator that has caused some issues when 
PHP_Depend was executed as an external dependency that uses a \*.phar 
archive as distribution format.

- Fixed #9623949: Also find analyzers in phar archives in the current 
  include_path. Fixed in commit #f53dca9.
- Fixed #113: PHP fatal error when an unserialized object graph none 
  NodeI instances. Fixed in commit #c0f4384.
- Fixed #164: Faulty implementation of the --ignore path filter fixed. 
  Now this filter only works on the local part of a file or directory 
  name and not on the complete path. Fixed in commit #f75275e.
- Fixed #176: Calculation of CIS metric is incorrect. Fixed in commit 
  #1193f4a.
- Fixed #182: Clone is a valid function, method and type name in older 
  php versions. Fixed with git commit Fixed in commit #b18bf37.
- Fixed #189: Invalid Start/End Line/Column for object method 
  invocation. Fixed in commit #c6cc9dd.
- Fixed #191: New implementation of --ignore only accepts relative 
  paths. Fixed in commit #38e6b52.
- Fixed #163: Alternative syntax end tokens can terminate with closing 
  PHP-tag.
- Fixed #181: No log generated when parsing Typo3 extension 
  "t3extplorer" (Unexpected token ASCII 39). Indirectly fixed in this 
  release.
- Implemented #130: Simplify PHP_Depend's ASTCompoundVariable and skip 
  nested ASTCompoundExpression node instance.
- Implemented #131: Add new method isThis() to PHP_Depend's 
  ASTVariable class.
- Implemented #132: Housekeeping: Cleanup the PHP_Depend_Input package 
  test code.
- Implemented #139: Implement Post-/Pre- Increment/Decrement.
- Implemented #143: Support PHP's alternative control structure 
  syntax.
- Implemented #146: Implement PHP's declare-statement.
- Implemented #148: Implement cast expressions.
- Implemented #170: Rename FunctionNameParserImpl into 
  FunctionNameParserAllVersions. Task scope changed and complete 
  refactoring done. Parser moved into a version specific parser class.
- Implemented #178: Provide configuration option for the cache 
  directory. Implemented in commit #00ed8ec.

{
    "name": "pdepend/pdepend",
    "description": "Official version of pdepend to be handled with Composer",
    "license": "BSD-3-Clause",
    "require": {
        "php": ">=5.3.7",
        "symfony/dependency-injection": "^2.3.0|^3",
        "symfony/filesystem": "^2.3.0|^3",
        "symfony/config": "^2.3.0|^3"
    },
    "require-dev": {
        "phpunit/phpunit": "^4.4.0,<4.8",
        "squizlabs/php_codesniffer": "^2.0.0"
    },
    "bin": ["src/bin/pdepend"],
    "autoload": {
        "psr-4": {"PDepend\\": "src/main/php/PDepend"}
    }
}
Copyright (c) 2008-2017, Manuel Pichler <mapi@pdepend.org>.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

  * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in
    the documentation and/or other materials provided with the
    distribution.

  * Neither the name of Manuel Pichler nor the names of his
    contributors may be used to endorse or promote products derived
    from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
#!/bin/sh

PHP_BIN=${2:-"php"}

rm -rf ~/.pdepend/*
$PHP_BIN "$(which pdepend)" --jdepend-xml=/tmp/jdpa0.xml --summary-xml=/tmp/suma0.xml "$1"
$PHP_BIN "$(which pdepend)" --jdepend-xml=/tmp/jdpa1.xml --summary-xml=/tmp/suma1.xml "$1"
$PHP_BIN src/bin/pdepend --jdepend-xml=/tmp/jdpb0.xml --summary-xml=/tmp/sumb0.xml "$1"
$PHP_BIN src/bin/pdepend --jdepend-xml=/tmp/jdpb1.xml --summary-xml=/tmp/sumb1.xml "$1"

meld /tmp/suma0.xml /tmp/sumb0.xml /tmp/sumb1.xml

meld /tmp/jdpa0.xml /tmp/jdpb0.xml /tmp/jdpb1.xml
<?php
$url = 'https://raw.githubusercontent.com/php/php-src/master/Zend/zend_language_scanner.l';
$file = basename($url);

if (isset($argv[1]) && is_numeric($argv[1])) {
    $argv[2] = $argv[1];
    unset($argv[1]);
}

if (isset($argv[1])) {
    if (false === file_exists($argv[1])) {
        fwrite(STDERR, "The given zend_language_scanner.l does not exist.\n");
        fwrite(STDERR, "Usage:\n~ \$ php-keywords.php <path/to/zend_language_scanner.l> [<phpversion>]\n");
        exit(23);
    } else {
        $file = $argv[1];
    }
} else if (false === file_exists($file) || time() - filemtime($file) > 7200) {
    shell_exec(sprintf("wget -c '%s'", $url));
    touch($file);
}

$data = file_get_contents($file);

$regexp = '(
    \s+<ST_IN_SCRIPTING>"([a-z_]+)"\s*\{
        \s+RETURN_TOKEN\(([A-Z_]+)\);
    \s+\}
)xi';

if (0 === preg_match_all($regexp, $data, $matches)) {
    fwrite(STDERR, "No matches found :-(\nUsage:\n~ \$ php-keywords.php <path/to/zend_language_scanner.l>\n");
    exit(42);
}

$tokens = [];
foreach ($matches[1] as $i => $keyword) {
    $tokens[$matches[2][$i]] = $keyword;
}

ksort($tokens);

$valid = [
    'class' => [
        'T_NULL',
        'T_TRUE',
        'T_FALSE',
        'T_STRING',
    ],
    'constant' => [
        'T_NULL',
        'T_SELF',
        'T_TRUE',
        'T_FALSE',
        'T_STRING',
        'T_PARENT',
    ],
    'function' => [
        'T_NULL',
        'T_SELF',
        'T_TRUE',
        'T_FALSE',
        'T_STRING',
        'T_PARENT',
    ],
    'namespace' => [
        'T_NULL',
        'T_SELF',
        'T_TRUE',
        'T_FALSE',
        'T_STRING',
        'T_PARENT',
    ],
];

foreach ($tokens as $constant => $image) {
    $valid = test('class', '<?php class %s {}', $image, $constant, $valid);
    $valid = test('constant', '<?php class X { const %s = 42; }', $image, $constant, $valid);
    $valid = test('function', '<?php class X { public function %s() {} }', $image, $constant, $valid);
    $valid = test('namespace', '<?php namespace My\%s { class X { } }', $image, $constant, $valid);
}

$methodCode = dump('class', $valid);
$methodCode .= dump('constant', $valid);
$methodCode .= dump('function', $valid);
$methodCode .= dump('namespace', $valid);

function test($type, $code, $image, $constant, array &$valid)
{
    $file = tempnam(sys_get_temp_dir(), 'php-keyword_');

    file_put_contents($file, sprintf($code, $image));
    exec(sprintf("%s -l '%s'", PHP_BINARY, $file), $output, $retval);

    if (0 === $retval) {
        $valid[$type][] = $constant;
    }

    unlink($file);

    return $valid;
}

function dump($type, array $valid)
{
    $code = sprintf('
    /**
     * Tests if the give token is a valid %s name in the supported PHP
     * version.
     *
     * @param integer $tokenType
     * @return boolean
     */
    protected function is%sName($tokenType)
    {
        switch ($tokenType) {
%s
                return true;
        }
        return false;
    }
    ',
        $type,
        ucfirst($type),
        join(
            "\n",
            array_map(
                function ($token) {
                    return sprintf('            case Tokens::%s:', $token);
                },
                $valid[$type]
            )
        )
    );

    echo $code;
    return $code;
}

if (false === isset($argv[2])) {
    exit(0);
}

$parserFile = sprintf(__DIR__ . '/../src/main/php/PDepend/Source/Language/PHP/PHPParserVersion%s.php', $argv[2]);
if (false === file_exists($parserFile)) {
    fwrite(STDERR, "The given parser version does not exist.\n");
    exit(42);
}

$parserCode = file_get_contents($parserFile);

preg_match(
    '(\s+/\* Keyword test methods {{{ \*/\s*([^\s].*[^\s])\s*/\* }}} Keyword test methods \*/)sU',
    $parserCode,
    $match
);

$parserCode = str_replace(
    $match[0],
    str_replace(
        $match[1],
        trim($methodCode),
        $match[0]
    ),
    $parserCode
);

echo $parserCode;
file_put_contents($parserFile, $parserCode);
#!/usr/bin/env php
<?php
/**
 * This file is part of PDepend.
 *
 * PHP Version 5
 *
 * Copyright (c) 2008-2017, Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend;

/**
 * Utility class that we use to recalculate the cache hash/version.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */
class CacheVersionUpdater
{
    /**
     * The source directory.
     *
     * @var string
     */
    private $rootDirectory = null;

    /**
     * The source sub directories that we will process.
     *
     * @var array(string)
     */
    private $localPaths = array(
        '/Source',
        '/Metrics',
    );

    /**
     * The target file, where this script will persist the new cache version.
     *
     * @var string
     */
    private $targetFile = '/Util/Cache/CacheDriver.php';

    /**
     * Regular expression used to replace a previous cache version.
     *
     * @var string
     */
    private $targetRegexp = '(@version:[a-f0-9]{32}:@)';

    /**
     * Constructs a new cache version updater instance.
     */
    public function __construct()
    {
        $this->rootDirectory = realpath(dirname(__FILE__) . '/../src/main/php/PDepend');
    }

    /**
     * Processes all source files and generates a combined version for all files.
     * The it replaces the old version key within the project source with the
     * newly calculated value.
     *
     * @return void
     */
    public function run()
    {
        $checksum = '';

        foreach ($this->localPaths as $localPath) {
            $path = $this->rootDirectory . $localPath;
            foreach ($this->readFiles($path) as $file) {
                $checksum = $this->hash($file, $checksum);
            }
        }

        $file = $this->rootDirectory . $this->targetFile;

        $code = file_get_contents($file);
        $code = preg_replace($this->targetRegexp, "@version:{$checksum}:@", $code);
        file_put_contents($file, $code);
    }

    /**
     * Generates a hash value for the given <b>$path</b> in combination with a
     * previous calculated <b>$checksum</b>.
     *
     * @param string $path Path to the current context file.
     * @param string $checksum Hash/Checksum for all previously parsed files.
     * @return string
     */
    protected function hash($path, $checksum)
    {
        return md5($checksum . md5_file($path));
    }

    /**
     * Reads all files below the given <b>$path</b>.
     *
     * @param string $path The parent directory or a file.
     * @return array(string)
     */
    protected function readFiles($path)
    {
        if ($this->accept($path)) {
            return array($path);
        }
        $files = array();
        foreach ($this->createFileIterator($path) as $file) {
            if ($this->accept($file)) {
                $files[] = (string) $file;
            }
        }
        return $files;
    }

    /**
     * Does the given path represent a file that has the expected file extension?
     *
     * @param string $path Path to a file or directory.
     * @return boolean
     */
    protected function accept($path)
    {
        return (is_file($path) && '.php' === substr($path, -4, 4));
    }

    /**
     * Creates an iterator with all files below the given directory.
     *
     * @param string $path Path to a directory.
     * @return \Iterator
     */
    protected function createFileIterator($path)
    {
        return new \RecursiveIteratorIterator(
            new \RecursiveDirectoryIterator($path)
        );
    }

    /**
     * The main method starts the cache version updater.
     *
     * @param array $args Cli arguments.
     * @return void
     */
    public static function main(array $args)
    {
        $updater = new CacheVersionUpdater();
        $updater->run();
    }
}

CacheVersionUpdater::main($_SERVER['argv']);
project.dir       =
project.uri       = pdepend.org
project.name      = pdepend
project.version   = 2.5.0
project.stability = stable

project.pear.uri = pear.example.com

vendor.dir.includes = symfony/**/*,composer/**/*,autoload.php
vendor.dir.excludes = symfony/**/Tests/**/*

codesniffer.standard = PSR2

codesniffer.fail.on.violation = true

project.scm.uri = github.com/${project.name}/${project.name}/commit

phpunit.package.name = phpunit-old
<?php

// autoload.php @generated by Composer

require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInite734a91eed98c612a4345af43a64a59e::getLoader();
7[¶t0Ëæ¤N`£[ËÏ¼¥©“Ç}è“´G¨«,æf-7<by¯·öEœ¾«¼¢äŒíõZ0¦ÔŽ0”S   GBMB