SAND-framework/build/bin/phpmd.phar

86299 lines
2.7 MiB
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env php
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
/**
* 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(); ?>
ŠÂ vendor/pdepend/pdepend/README.mdH1Ðk_HöÃ;ú¶vendor/pdepend/pdepend/LICENSEò1Ðk_òm¼Œ¶#vendor/pdepend/pdepend/CHANGELOG.md q1Ðk_ qZ$vendor/pdepend/pdepend/composer.json´1Ðk_´WK!<21>%vendor/pdepend/pdepend/phpcs.xml.dist£1Ðk_£Õñ赶'vendor/pdepend/pdepend/build.propertiesÜ1Ðk_ÜQ™½ä¶&vendor/pdepend/pdepend/src/bin/pdepend 1Ðk_ 055M¶*vendor/pdepend/pdepend/src/bin/pdepend.batƒ1Ðk_ƒ]hæ¶*vendor/pdepend/pdepend/src/bin/pdepend.php`
1Ðk_`
a1ÕɶOvendor/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/TreeBuilder.phpÙ 1Ðk_Ù …Ъö¶Tvendor/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/ExtensionManager.phpW 1Ðk_W Mvendor/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/Extension.php•1Ðk_•¯èóD¶Qvendor/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/Configuration.phpè1Ðk_èìKTvendor/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/PdependExtension.phpô1Ðk_ôT7>n¶`vendor/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/Compiler/ProcessListenerPass.phpö
1Ðk_ö
Á>ƶDvendor/pdepend/pdepend/src/main/php/PDepend/DbusUI/ResultPrinter.phpM1Ðk_M*óWÖ¶;vendor/pdepend/pdepend/src/main/php/PDepend/Application.php¢1Ðk_¢YFqù¶=vendor/pdepend/pdepend/src/main/php/PDepend/TextUI/Runner.phpÿ%1Ðk_ÿ%•£n…¶>vendor/pdepend/pdepend/src/main/php/PDepend/TextUI/Command.php'K1Ðk_'KøhÚ¶Dvendor/pdepend/pdepend/src/main/php/PDepend/TextUI/ResultPrinter.phpŽ1Ðk_Ž¡3MIvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerNodeAware.php˜
1Ðk_˜
Ü«Äí¶Pvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/NodeLocAnalyzer.php:1Ðk_:´W÷ŶRvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CrapIndexAnalyzer.phpÊ1Ðk_Ê:ó÷¶cvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/CodeRankStrategyI.php 1Ðk_ |Ô||¶evendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/InheritanceStrategy.php1Ðk_ÁÓaض`vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/MethodStrategy.php˜1Ðk_˜ŠnfZ¶avendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/StrategyFactory.php1Ðk_(T÷bvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/PropertyStrategy.phpÅ1Ðk_Åc‰ˆ]vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CyclomaticComplexityAnalyzer.phpx61Ðk_x6/âv¶Qvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CohesionAnalyzer.phpæ1Ðk_泊&M¶Qvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CouplingAnalyzer.phpÈ21Ðk_È2êx7¶]vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/MaintainabilityIndexAnalyzer.phpæ1Ðk_溩ÅM¶Rvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/NodeCountAnalyzer.php8#1Ðk_8#*~Rvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/HierarchyAnalyzer.php™#1Ðk_™#LÖ*Svendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/DependencyAnalyzer.phpØ:1Ðk_Ø:°vXvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/NPathComplexityAnalyzer.php?D1Ðk_?DF<><Xvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/ClassDependencyAnalyzer.php¸(1Ðk_¸(¼‰$í¶Svendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/ClassLevelAnalyzer.php841Ðk_84Ì„¢Qvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/HalsteadAnalyzer.php“;1Ðk_“;'ªxTvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/InheritanceAnalyzer.phpÕ*1Ðk_Õ*á¦Qvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer.php†1Ðk_†½pã¶Ovendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AbstractCachingAnalyzer.phpõ1Ðk_õæ|ÜF¶Gvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerFactory.phpÖ 1Ðk_Ö ©Ivendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AggregateAnalyzer.php
1Ðk_
$â_-¶Hvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AbstractAnalyzer.php|1Ðk_|}//¶@vendor/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer.php 1Ðk_ ˜¹z¶Jvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerCacheAware.phpê 1Ðk_ê ëF»¸Hvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerIterator.phpZ
1Ðk_Z
RåªF¶Kvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerFilterAware.phpÿ1Ðk_ÿï•—Lvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerProjectAware.phpø 1Ðk_ø ¹Ñx߶Hvendor/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerListener.phpª
1Ðk_ª
ÌÕEŒ¶Gvendor/pdepend/pdepend/src/main/php/PDepend/Report/Overview/pyramid.svg¸x1Ðk_¸xÝ`'Gvendor/pdepend/pdepend/src/main/php/PDepend/Report/Overview/Pyramid.phpô*1Ðk_ô*Ü´­þ¶Ivendor/pdepend/pdepend/src/main/php/PDepend/Report/FileAwareGenerator.phpë1Ðk_ë’ý)ê¶Fvendor/pdepend/pdepend/src/main/php/PDepend/Report/ReportGenerator.php_ 1Ðk__ ÿIBvendor/pdepend/pdepend/src/main/php/PDepend/Report/Summary/Xml.phpº51Ðk_º5Om<4F>Kvendor/pdepend/pdepend/src/main/php/PDepend/Report/NoLogOutputException.php
1Ðk_
H<>ð¶Mvendor/pdepend/pdepend/src/main/php/PDepend/Report/ReportGeneratorFactory.php‡1Ðk_‡û½6;¶Ivendor/pdepend/pdepend/src/main/php/PDepend/Report/CodeAwareGenerator.phpL 1Ðk_L ÷«_0¶Dvendor/pdepend/pdepend/src/main/php/PDepend/Report/Jdepend/Chart.php³1Ðk_³%EgBvendor/pdepend/pdepend/src/main/php/PDepend/Report/Jdepend/Xml.php¿,1Ðk_¿,Dvendor/pdepend/pdepend/src/main/php/PDepend/Report/Jdepend/chart.svgv[1Ðk_v[ò!®m¶Gvendor/pdepend/pdepend/src/main/php/PDepend/Report/Dependencies/Xml.php*1Ðk_*uYZ¾¶@vendor/pdepend/pdepend/src/main/php/PDepend/Util/Workarounds.php& 1Ðk_& §®‹Jvendor/pdepend/pdepend/src/main/php/PDepend/Util/ConfigurationInstance.php¶
1Ðk_¶
ˆ©@›¶=vendor/pdepend/pdepend/src/main/php/PDepend/Util/FileUtil.phpd 1Ðk_d <00>Ùo¶Avendor/pdepend/pdepend/src/main/php/PDepend/Util/ImageConvert.php!1Ðk_!JÅæ¶>vendor/pdepend/pdepend/src/main/php/PDepend/Util/IdBuilder.phpn1Ðk_nm'¡¶Dvendor/pdepend/pdepend/src/main/php/PDepend/Util/Coverage/Report.phpB 1Ðk_B í!åÓ¶Evendor/pdepend/pdepend/src/main/php/PDepend/Util/Coverage/Factory.phpÎ 1Ðk_Î Éö„¶Jvendor/pdepend/pdepend/src/main/php/PDepend/Util/Coverage/CloverReport.php1Ðk_V}þj¶9vendor/pdepend/pdepend/src/main/php/PDepend/Util/Type.phpá:1Ðk_á:ƤÚu¶=vendor/pdepend/pdepend/src/main/php/PDepend/Util/MathUtil.phpµ 1Ðk_µ ÔÚAQvendor/pdepend/pdepend/src/main/php/PDepend/Util/Cache/Driver/FileCacheDriver.phpd%1Ðk_d%üe(¶Svendor/pdepend/pdepend/src/main/php/PDepend/Util/Cache/Driver/MemoryCacheDriver.php‰1Ðk_‰ìjQ`vendor/pdepend/pdepend/src/main/php/PDepend/Util/Cache/Driver/File/FileCacheGarbageCollector.phpŽ1Ðk_Ž¶©0
Yvendor/pdepend/pdepend/src/main/php/PDepend/Util/Cache/Driver/File/FileCacheDirectory.php1Ðk_¨_ѯ¶Gvendor/pdepend/pdepend/src/main/php/PDepend/Util/Cache/CacheFactory.phpu1Ðk_u¸Ì²A¶Fvendor/pdepend/pdepend/src/main/php/PDepend/Util/Cache/CacheDriver.phpÎ1Ðk_ÎÒ>‚¶Bvendor/pdepend/pdepend/src/main/php/PDepend/Util/Configuration.php(1Ðk_([hÑj¶8vendor/pdepend/pdepend/src/main/php/PDepend/Util/Log.phpÑ 1Ðk_Ñ ºÆ"w¶=vendor/pdepend/pdepend/src/main/php/PDepend/Util/Utf8Util.phpb
1Ðk_b
Ó¼ï¶?vendor/pdepend/pdepend/src/main/php/PDepend/ProcessListener.phpZ1Ðk_Z’õÆ„¶6vendor/pdepend/pdepend/src/main/php/PDepend/Engine.phpdO1Ðk_dO>«ì©¶Evendor/pdepend/pdepend/src/main/php/PDepend/Input/ExtensionFilter.phpú 1Ðk_ú UAÕí¶>vendor/pdepend/pdepend/src/main/php/PDepend/Input/Iterator.phpJ1Ðk_J7õdN¶<vendor/pdepend/pdepend/src/main/php/PDepend/Input/Filter.php9 1Ðk_9 íÿT¯¶Evendor/pdepend/pdepend/src/main/php/PDepend/Input/CompositeFilter.php= 1Ðk_=
Š#Gvendor/pdepend/pdepend/src/main/php/PDepend/Input/ExcludePathFilter.php1Ðk_ü Mvendor/pdepend/pdepend/src/main/php/PDepend/Source/Builder/BuilderContext.phpÆ1Ðk_Æ9ñò1¶Fvendor/pdepend/pdepend/src/main/php/PDepend/Source/Builder/Builder.phpî1Ðk_îã*u‡¶bvendor/pdepend/pdepend/src/main/php/PDepend/Source/Builder/BuilderContext/GlobalBuilderContext.php1Ðk_4þq¶Lvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTScopeStatement.phpU
1Ðk_U
Ø¥FS¶Nvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTDoWhileStatement.phpm
1Ðk_m
6aa.¶Lvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassReference.phpß 1Ðk_ß Ü^¡1¶Ovendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTRequireExpression.phpõ 1Ðk_õ þ}ˆQvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTMemberPrimaryPrefix.phpx 1Ðk_x po³¶Qvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTBooleanOrExpression.php-
1Ðk_-
Evendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTForInit.phpÁ
1Ðk_Á
Ì4 Gvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTNamespace.php#1Ðk_# ¯N¶Jvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTNode.phpË01Ðk_Ë0&#¢[¶Rvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTAllocationExpression.phpá
1Ðk_á
Bwت¶Rvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTAssignmentExpression.php
1Ðk_
gZÃ5¶Mvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFormalParameter.php$1Ðk_$ÓòWvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTStaticVariableDeclaration.php„ 1Ðk_„ [oÀOvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitUseStatement.php_1Ðk__×D~W¶Lvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLabelStatement.phpR
1Ðk_R
h èf¶Lvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCastExpression.php1Ðk_jPɾ¶Mvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPropertyPostfix.phpö
1Ðk_ö
˜í‹Ö¶Nvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTArtifact.phpì1Ðk_ì‹£€¶Mvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTElseIfStatement.php½ 1Ðk_½ ¥k¶Kvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTGotoStatement.phpO
1Ðk_O
i+R<¶Svendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConditionalExpression.php“
1Ðk_“
<5F>ζEvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLiteral.php=
1Ðk_=
Ðhz¶Evendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTComment.phpç 1Ðk_ç ߧ©†¶Wvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitAdaptationPrecedence.phpI
1Ðk_I
§É<¶Cvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTValue.phpG 1Ðk_G ºn·¶Lvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTExitExpression.phph
1Ðk_h
¬gfIvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTSwitchLabel.phpØ 1Ðk_Ø ïqÆx¶Nvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCompoundVariable.php¡
1Ðk_¡
í¾Rvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTInstanceOfExpression.phpd
1Ðk_d
 yâ¶Cvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClass.php™1Ðk_™¦°i¬¶Jvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTForStatement.phpJ
1Ðk_J
,<2C>¯Ä¶_vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassOrInterfaceReferenceIterator.php‰ 1Ðk_‰ xiœ¶Rvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitAdaptationAlias.phpž1Ðk_ž<:^<5E>Lvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTWhileStatement.phpK
1Ðk_K
#%AT¶Mvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIndexExpression.phpf1Ðk_fTQvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLogicalOrExpression.phph
1Ðk_h
Ú/l/¶Wvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassOrInterfaceReference.php1Ðk_ùæ%߶Mvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPrintExpression.phpx
1Ðk_x
àX¼Ð¶Nvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFieldDeclaration.phpì1Ðk_ì÷}¶Mvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTStaticReference.phpÇ 1Ðk_Ç >Jê¶Gvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTInterface.phpn1Ðk_nòJvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTypeCallable.phpø
1Ðk_ø
1̶Fvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFunction.phpŽ1Ðk_ŽÝ_4ŶTvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPreDecrementExpression.phpH
1Ðk_H
V¹Zç¶Hvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTExpression.phpI
1Ðk_I
Ô¶Jvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArrayElement.php<68>1Ðk_<6B>ÆÍd¶Fvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCallable.phpt1Ðk_tåß}@vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/State.php¤ 1Ðk_¤ µƒ:U¶Lvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCatchStatement.php0
1Ðk_0
$67ζOvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIncludeExpression.phpõ 1Ðk_õ J üé¶Rvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArrayIndexExpression.phpí
1Ðk_í
¤É¶Pvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConstantDefinition.phpÛ1Ðk_ÛKV®¶Mvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCloneExpression.phpj
1Ðk_j
Ș¶Mvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTGlobalStatement.phpU
1Ðk_U
ö«kA¶Nvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFinallyStatement.php
1Ðk_
•?ܶMvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassFqnPostfix.phpê
1Ðk_ê
Þj\ë¶Fvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTVariable.php£ 1Ðk_£ Õ…é¶Hvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTInvocation.phpd1Ðk_dBY'l¶Lvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTUnsetStatement.phpR
1Ðk_R
½”¶Lvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTAnonymousClass.php"1Ðk_"$ïɶFvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifact.phpB
1Ðk_B
¹á¶Nvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTForeachStatement.phpV
1Ðk_V
_yœ¶Mvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTReturnStatement.php~ 1Ðk_~ žl»è¶^vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCompilationUnitNotFoundException.phpg
1Ðk_g
–º¡ü¶Gvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTypeArray.php% 1Ðk_% ÝÀcDvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTMethod.phps1Ðk_süÛph¶Mvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCompilationUnit.phpÂ&1Ðk_Â&A¿Àç¶Gvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArguments.php÷
1Ðk_÷
{"¶Svendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTStringIndexExpression.php<68>
1Ðk_<6B>
2|[©¶Dvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTString.phpÏ 1Ðk_Ï <00>§jû¶Tvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPreIncrementExpression.phpH
1Ðk_H
¯«0Ô¶Kvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTEchoStatement.phpd
1Ðk_d
e=<1F>Jvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTType.php”81Ðk_”8ðN±Ì¶Vvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTClassOrInterface.phpþ+1Ðk_þ+›Ð¼œ¶Gvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTStatement.phpI
1Ðk_I
ãvZ<¶Pvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTVariableDeclarator.php1Ðk_Ì<¸Nvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTDeclareStatement.php¥1Ðk_¥ÍntMvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitAdaptation.php,
1Ðk_,
ýWNvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTCallable.php$91Ðk_$9õy Lvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTYieldStatement.phph 1Ðk_h šBkvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassOrInterfaceRecursiveInheritanceException.phpˆ
1Ðk_ˆ
éýè°¶Mvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFunctionPostfix.phpÈ
1Ðk_È
cd0¶Mvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConstantPostfix.phpX
1Ðk_X
;0ž°¶Gvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTForUpdate.phpU 1Ðk_U ¥œ¤p¶Cvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArray.phpv 1Ðk_v tÔ4[vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitMethodCollisionException.phpÿ1Ðk_ÿ ð€V¶Hvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTScalarType.php. 1Ðk_. 4` Ovendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPostfixExpression.php3
1Ðk_3
£¶Lvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTEvalExpression.phph
1Ðk_h
„ªã¶Gvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTParameter.php$+1Ðk_$+Û (m¶Nvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTVariableVariable.phpé
1Ðk_é
G—΀¶Fvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConstant.php
1Ðk_
½¶¼r¶Jvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList.php•1Ðk_•Ì<>ä'¶Qvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTShiftLeftExpression.phpD 1Ðk_D =Ü¢¶Lvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTBreakStatement.php 1Ðk_ þ5Nœ¶Rvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLogicalAndExpression.phpk
1Ðk_k
òœ³¬¶Jvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTryStatement.phpL
1Ðk_L
Þyñê¶Rvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTBooleanAndExpression.php0
1Ðk_0
Bvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTNode.phpÚ1Ðk_Ú³fŸFvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTProperty.phpå&1Ðk_å&¸ý"<22>Lvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitReference.phpà 1Ðk_à ²W¶Lvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTListExpression.phpS
1Ðk_S
¦f Ö¶Bvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTType.php” 1Ðk_” ø½'”¶Ivendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIfStatement.phpL 1Ðk_L üŽ£³¶Pvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConstantDeclarator.phpc1Ðk_c<51>Pvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCompoundExpression.phpÚ
1Ðk_Ú
&ÚÅݶHvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIdentifier.phpx
1Ðk_x
BÇâ¶]vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList/NullArtifactFilter.php 1Ðk_ lÅ>4¶Yvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList/ArtifactFilter.php<68> 1Ðk_<6B> ú©É_¶`vendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList/PackageArtifactFilter.php 1Ðk_ ~éôk¶cvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList/CollectionArtifactFilter.phpº1Ðk_ºÈË\<5C>Kvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTMethodPostfix.phpá
1Ðk_á
¸`VK¶Mvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTParentReference.phpµ1Ðk_µ ¡uk¶Ovendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTContinueStatement.php; 1Ðk_; ©2Ùæ¶Lvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTThrowStatement.phpR
1Ðk_R
Å4ƒ¶Evendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTHeredoc.php­ 1Ðk_­ W fd¶Evendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClosure.phpu1Ðk_usþ7Kvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTSelfReference.phpý1Ðk_ýì‚¥=¶Mvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIssetExpression.php*
1Ðk_*
Ó„Nvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFormalParameters.php÷ 1Ðk_÷ £Ñ¶Rvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLogicalXorExpression.phpk
1Ðk_k
Þf¶Jvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTypeIterable.php. 1Ðk_. £ìЕ¶Cvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTrait.php 1Ðk_ WUÿž¶Mvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTUnaryExpression.phpÛ
1Ðk_Û
R×Y[¶Rvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTShiftRightExpression.phpG 1Ðk_G ðãq¶Cvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTScope.phpI
1Ðk_I
„,‡w¶Mvendor/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTSwitchStatement.php3
1Ðk_3
b‰sn¶Vvendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion55.phpÎ
1Ðk_Î
ÛBüg¶Uvendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/AbstractPHPParser.php˜_1Ðk_˜_x¾±m¶Vvendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion74.phpA1Ðk_A!BPh¶Vvendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion70.phpøE1Ðk_øEqß%x¶Vvendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion53.php1Ðk_I*]жNvendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPBuilder.php1Ðk_¬ÓVvendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion56.php<1Ðk_<C&¶Tvendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserGeneric.phpq1Ðk_qwC„¶Xvendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPTokenizerInternal.php,|1Ðk_,|>:Þ˜¶Vvendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion71.phps1Ðk_sRmpˆVvendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion73.php1Ðk_Öx<C396>Vvendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion72.php1Ðk_Ï <0C>Ò¶Vvendor/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion54.php±!1Ðk_±!A ò¶Lvendor/pdepend/pdepend/src/main/php/PDepend/Source/ASTVisitor/ASTVisitor.phpq1Ðk_qËüH¶Rvendor/pdepend/pdepend/src/main/php/PDepend/Source/ASTVisitor/ASTVisitListener.phpí1Ðk_í¯ªZvendor/pdepend/pdepend/src/main/php/PDepend/Source/ASTVisitor/AbstractASTVisitListener.php³1Ðk_³NpÚ<70>Tvendor/pdepend/pdepend/src/main/php/PDepend/Source/ASTVisitor/AbstractASTVisitor.php¾61Ðk_¾6»³;Jvendor/pdepend/pdepend/src/main/php/PDepend/Source/Tokenizer/Tokenizer.php÷1Ðk_÷õÑÛFvendor/pdepend/pdepend/src/main/php/PDepend/Source/Tokenizer/Token.php 1Ðk_ ¥Î©2¶Gvendor/pdepend/pdepend/src/main/php/PDepend/Source/Tokenizer/Tokens.php;1Ðk_;/&b7¶Nvendor/pdepend/pdepend/src/main/php/PDepend/Source/Tokenizer/FullTokenizer.php² 1Ðk_² $­¥¶Svendor/pdepend/pdepend/src/main/php/PDepend/Source/Parser/InvalidStateException.phpG 1Ðk_G 6Zr¶Uvendor/pdepend/pdepend/src/main/php/PDepend/Source/Parser/TokenStreamEndException.php5
1Ðk_5
j¡>¶Tvendor/pdepend/pdepend/src/main/php/PDepend/Source/Parser/NoActiveScopeException.php®1Ðk_®ƒÖ[¤¶Mvendor/pdepend/pdepend/src/main/php/PDepend/Source/Parser/ParserException.phpW1Ðk_W–‘ÛͶVvendor/pdepend/pdepend/src/main/php/PDepend/Source/Parser/UnexpectedTokenException.phpŸ
1Ðk_Ÿ
<00>Ų¶Ivendor/pdepend/pdepend/src/main/php/PDepend/Source/Parser/SymbolTable.php/1Ðk_/ÿ!½€¶Svendor/pdepend/pdepend/src/main/php/PDepend/Source/Parser/MissingValueException.phpH 1Ðk_H Z5H¶Hvendor/pdepend/pdepend/src/main/php/PDepend/Source/Parser/TokenStack.php{1Ðk_{ (Á%¶Lvendor/pdepend/pdepend/src/main/php/PDepend/Source/Parser/TokenException.phpd1Ðk_d„§•¸¶6vendor/pdepend/pdepend/src/main/resources/services.xmlq1Ðk_qtBvendor/pdepend/pdepend/src/main/resources/schema/configuration.xsdQ1Ðk_Q3V扶"vendor/composer/autoload_files.phpð1Ðk_ð—É¿@¶#vendor/composer/autoload_static.php!1Ðk_!¦™<C2A6>Ž¶vendor/composer/LICENSE.1Ðk_. Õ!vendor/composer/autoload_real.php¬ 1Ðk_¬ •¶À¶!vendor/composer/autoload_psr4.phpÏ1Ðk_Ïë ”Y¶vendor/composer/ClassLoader.php¡41Ðk_¡4Þs…|¶vendor/composer/installed.json31Ðk_3ëËéÖ¶(vendor/composer/xdebug-handler/README.mdK31Ðk_K3Ïuˆ¶&vendor/composer/xdebug-handler/LICENSE)1Ðk_)#Ô;^¶+vendor/composer/xdebug-handler/CHANGELOG.mdÙ1Ðk_Ù'¶,vendor/composer/xdebug-handler/composer.json1Ðk_ÍÅN¦¶4vendor/composer/xdebug-handler/src/XdebugHandler.phpµD1Ðk_µD<{C¶0vendor/composer/xdebug-handler/src/PhpConfig.php51Ðk_5j$õ£¶-vendor/composer/xdebug-handler/src/Status.php1Ðk_«±fë¶.vendor/composer/xdebug-handler/src/Process.phpš1Ðk_šq;¡†¶%vendor/composer/autoload_classmap.phpD1Ðk_D`'vendor/composer/autoload_namespaces.phpÉ1Ðk_ÉA‡Þ¢¶vendor/symfony/config/README.md~1Ðk_~<> ¡¶5vendor/symfony/config/ConfigCacheFactoryInterface.phpÁ1Ðk_Á&é +¶,vendor/symfony/config/ConfigCacheFactory.php1Ðk_q<>“Ô¶4vendor/symfony/config/Definition/ReferenceDumper.php"1Ðk_"@Þ¹y¶;vendor/symfony/config/Definition/ConfigurationInterface.phpe1Ðk_e–¶1vendor/symfony/config/Definition/VariableNode.php; 1Ðk_; Â>Rζ2vendor/symfony/config/Definition/NodeInterface.phpý 1Ðk_ý ý'YV¶0vendor/symfony/config/Definition/BooleanNode.phpm1Ðk_mdµt<C2B5>;vendor/symfony/config/Definition/Builder/NodeDefinition.php!1Ðk_!h<>—†¶@vendor/symfony/config/Definition/Builder/NodeParentInterface.php¿1Ðk_¿YîÇÓ¶@vendor/symfony/config/Definition/Builder/ArrayNodeDefinition.phpŽ51Ðk_Ž5bè*S¶Bvendor/symfony/config/Definition/Builder/BooleanNodeDefinition.php1Ðk_Ñ’¶Bvendor/symfony/config/Definition/Builder/NumericNodeDefinition.php1Ðk_Sìá>vendor/symfony/config/Definition/Builder/ValidationBuilder.phpÊ1Ðk_Ê «8vendor/symfony/config/Definition/Builder/ExprBuilder.php1Ðk_ÕÚº¶8vendor/symfony/config/Definition/Builder/TreeBuilder.php<68>1Ðk_<6B>VÈhU¶9vendor/symfony/config/Definition/Builder/MergeBuilder.php41Ðk_4Ž¥ĶBvendor/symfony/config/Definition/Builder/IntegerNodeDefinition.php1Ðk_'nÚ­Avendor/symfony/config/Definition/Builder/NormalizationBuilder.php1Ðk_— ƒ8vendor/symfony/config/Definition/Builder/NodeBuilder.phpÀ1Ðk_ÀçL˜?vendor/symfony/config/Definition/Builder/EnumNodeDefinition.phpÎ1Ðk_ΤUŠ¶@vendor/symfony/config/Definition/Builder/FloatNodeDefinition.phpù1Ðk_ùt£p¶Avendor/symfony/config/Definition/Builder/ScalarNodeDefinition.phpÞ1Ðk_ÞÏYÜ÷¶Cvendor/symfony/config/Definition/Builder/VariableNodeDefinition.php€1Ðk_€S2·¶Jvendor/symfony/config/Definition/Builder/ParentNodeDefinitionInterface.phpY1Ðk_YEäW&¶.vendor/symfony/config/Definition/ArrayNode.php„*1Ðk_„*xY׶.vendor/symfony/config/Definition/Processor.php) 1Ðk_) ö&Ú¶>vendor/symfony/config/Definition/Dumper/XmlReferenceDumper.php,'1Ðk_,'^~ý¶?vendor/symfony/config/Definition/Dumper/YamlReferenceDumper.php 1Ðk_ ìS….vendor/symfony/config/Definition/FloatNode.phpS1Ðk_S!^|>¶-vendor/symfony/config/Definition/EnumNode.php½1Ðk_½§<>VŶ8vendor/symfony/config/Definition/PrototypedArrayNode.phpF01Ðk_F0'Ýv0vendor/symfony/config/Definition/IntegerNode.phpÌ1Ðk_Ìí(O²¶0vendor/symfony/config/Definition/NumericNode.phpÍ1Ðk_͉©<ç¶/vendor/symfony/config/Definition/ScalarNode.phpì1Ðk_윥ݶ-vendor/symfony/config/Definition/BaseNode.php¸1Ðk_¸¥à©g¶Jvendor/symfony/config/Definition/Exception/ForbiddenOverwriteException.phpQ1Ðk_Q¨:2&¶Ivendor/symfony/config/Definition/Exception/InvalidDefinitionException.phpÚ1Ðk_Ú]F4ç¶Dvendor/symfony/config/Definition/Exception/DuplicateKeyException.phpE1Ðk_Eø|÷Lvendor/symfony/config/Definition/Exception/InvalidConfigurationException.phpR1Ðk_Rh'Nñ¶Cvendor/symfony/config/Definition/Exception/InvalidTypeException.phpí1Ðk_í¾Ä@¶8vendor/symfony/config/Definition/Exception/Exception.phpË1Ðk_˹po:¶@vendor/symfony/config/Definition/Exception/UnsetKeyException.php1Ðk_þ¤½¿¶;vendor/symfony/config/Definition/PrototypeNodeInterface.phpw1Ðk_wÿ€;vendor/symfony/config/ResourceCheckerConfigCacheFactory.php+1Ðk_+ï?¶vendor/symfony/config/LICENSE)1Ðk_)NUN½¶@vendor/symfony/config/Resource/SelfCheckingResourceInterface.phpB1Ðk_BÑ飶>vendor/symfony/config/Resource/SelfCheckingResourceChecker.phpâ1Ðk_âÿ¬8vendor/symfony/config/Resource/FileExistenceResource.phpL1Ðk_LMÊœµ¶/vendor/symfony/config/Resource/FileResource.phpô1Ðk_ôêi,¶=vendor/symfony/config/Resource/BCResourceInterfaceChecker.phpŽ1Ðk_Ži˜»þ¶4vendor/symfony/config/Resource/DirectoryResource.phpì
1Ðk_ì
h~#­¶4vendor/symfony/config/Resource/ResourceInterface.php?1Ðk_?àÛ¶%vendor/symfony/config/FileLocator.phpQ 1Ðk_Q Ä’Ò¶"vendor/symfony/config/CHANGELOG.md 1Ðk_ =Ð"Ó¶#vendor/symfony/config/composer.jsonß1Ðk_ßÖ»îM¶.vendor/symfony/config/FileLocatorInterface.php{1Ðk_{Këý¶/vendor/symfony/config/Loader/LoaderResolver.php91Ðk_9x ²+vendor/symfony/config/Loader/FileLoader.phpè1Ðk_èB^H¶8vendor/symfony/config/Loader/LoaderResolverInterface.php1Ðk_!ŠKĶ1vendor/symfony/config/Loader/DelegatingLoader.phpä1Ðk_äù¤ãl¶0vendor/symfony/config/Loader/LoaderInterface.phpN1Ðk_N7
<EFBFBD>'vendor/symfony/config/Loader/Loader.php11Ðk_1<00>Ùc—¶'vendor/symfony/config/Util/XmlUtils.phpv 1Ðk_v žd΀¶2vendor/symfony/config/ResourceCheckerInterface.php1Ðk_œR%vendor/symfony/config/ConfigCache.phpÜ1Ðk_Ü8áfn¶&vendor/symfony/config/phpunit.xml.distt1Ðk_tNr-׶4vendor/symfony/config/ResourceCheckerConfigCache.php71Ðk_7;vendor/symfony/config/Exception/FileLoaderLoadException.phpì 1Ðk_ì Ù™Žâ¶Nvendor/symfony/config/Exception/FileLoaderImportCircularReferenceException.phpC1Ðk_CWׯø¶.vendor/symfony/config/ConfigCacheInterface.php01Ðk_0ú ed¶#vendor/symfony/filesystem/README.mdø1Ðk_øÑîoý¶(vendor/symfony/filesystem/Filesystem.phpíe1Ðk_íe<FÚʶ!vendor/symfony/filesystem/LICENSE)1Ðk_)NUN½¶)vendor/symfony/filesystem/LockHandler.phpo 1Ðk_o åÊÞ¶&vendor/symfony/filesystem/CHANGELOG.mdç1Ðk_çY„¤¶'vendor/symfony/filesystem/composer.json)1Ðk_)?•Z¶*vendor/symfony/filesystem/phpunit.xml.distE1Ðk_E$8•¶<vendor/symfony/filesystem/Exception/IOExceptionInterface.php¡1Ðk_¡k/’ï¶:vendor/symfony/filesystem/Exception/ExceptionInterface.php½1Ðk_½ 3vendor/symfony/filesystem/Exception/IOException.phpª1Ðk_ªÑ„A¶=vendor/symfony/filesystem/Exception/FileNotFoundException.php·1Ðk_·þ0z¶-vendor/symfony/dependency-injection/README.mdN1Ðk_NôÊùD¶8vendor/symfony/dependency-injection/SimpleXMLElement.php1Ðk_©'¶^¶Vvendor/symfony/dependency-injection/LazyProxy/Instantiator/RealServiceInstantiator.phpo1Ðk_o$$ñTvendor/symfony/dependency-injection/LazyProxy/Instantiator/InstantiatorInterface.php1Ðk_O8Fvendor/symfony/dependency-injection/LazyProxy/PhpDumper/NullDumper.php´1Ðk_´F#+Û¶Kvendor/symfony/dependency-injection/LazyProxy/PhpDumper/DumperInterface.phpÃ1Ðk_ÃZXÓ¶;vendor/symfony/dependency-injection/DefinitionDecorator.phpš1Ðk_šÝ5ï¶@vendor/symfony/dependency-injection/TaggedContainerInterface.phpÏ1Ðk_Ï¡ºŽ¶-vendor/symfony/dependency-injection/Scope.phpI1Ðk_I4¯…h¶1vendor/symfony/dependency-injection/Container.phpL1Ðk_LamŸ¶6vendor/symfony/dependency-injection/ScopeInterface.php1Ðk_`ƒð·¶8vendor/symfony/dependency-injection/ContainerBuilder.php1Ðk_ ·³¿¶+vendor/symfony/dependency-injection/LICENSE)1Ðk_)NUN½¶:vendor/symfony/dependency-injection/ExpressionLanguage.phpÅ1Ðk_Åõ¡îð¶1vendor/symfony/dependency-injection/Reference.phpj1Ðk_j¬Çt!¶Hvendor/symfony/dependency-injection/IntrospectableContainerInterface.php†1Ðk_†0vendor/symfony/dependency-injection/CHANGELOG.mdû1Ðk_û:vendor/symfony/dependency-injection/ContainerInterface.php~1Ðk_~wð|1vendor/symfony/dependency-injection/composer.json1Ðk_ëtû¶8vendor/symfony/dependency-injection/Dumper/PhpDumper.phpöÚ1Ðk_öÚÆ•8vendor/symfony/dependency-injection/Dumper/XmlDumper.phpQ31Ðk_Q3þÉÊ\¶5vendor/symfony/dependency-injection/Dumper/Dumper.phpš1Ðk_š2†gU¶9vendor/symfony/dependency-injection/Dumper/YamlDumper.php/+1Ðk_/+j1|T¶=vendor/symfony/dependency-injection/Dumper/GraphvizDumper.phpž'1Ðk_ž'4/ã¶>vendor/symfony/dependency-injection/Dumper/DumperInterface.php¿1Ðk_¿‡0€ô¶0vendor/symfony/dependency-injection/Variable.phpÉ1Ðk_É­¬<C2AD>ò¶<vendor/symfony/dependency-injection/Loader/PhpFileLoader.phpè1Ðk_èk<><vendor/symfony/dependency-injection/Loader/XmlFileLoader.phpÍV1Ðk_ÍV\<5C>9vendor/symfony/dependency-injection/Loader/FileLoader.phpr1Ðk_r2·gë¶>vendor/symfony/dependency-injection/Loader/DirectoryLoader.php_1Ðk__€æ ¶Ovendor/symfony/dependency-injection/Loader/schema/dic/services/services-1.0.xsd 1Ðk_ ªw<vendor/symfony/dependency-injection/Loader/IniFileLoader.php™1Ðk_™æ·M9¶<vendor/symfony/dependency-injection/Loader/ClosureLoader.php01Ðk_09¥¶=vendor/symfony/dependency-injection/Loader/YamlFileLoader.phpäC1Ðk_äC'¼óm¶Gvendor/symfony/dependency-injection/ParameterBag/FrozenParameterBag.php=1Ðk_=#Á•¶¶Avendor/symfony/dependency-injection/ParameterBag/ParameterBag.phpÏ1Ðk_Ï…õ}2¶Jvendor/symfony/dependency-injection/ParameterBag/ParameterBagInterface.phpO
1Ðk_O
ˆÅÕ~¶2vendor/symfony/dependency-injection/Definition.phpÙW1Ðk_ÙWH4vendor/symfony/dependency-injection/phpunit.xml.dist<73>1Ðk_<6B>Œø*N¶Kvendor/symfony/dependency-injection/Extension/PrependExtensionInterface.php1Ðk_’úð¶Dvendor/symfony/dependency-injection/Extension/ExtensionInterface.php"1Ðk_",œžt¶;vendor/symfony/dependency-injection/Extension/Extension.php® 1Ðk_® áø΋¶Qvendor/symfony/dependency-injection/Extension/ConfigurationExtensionInterface.phpB1Ðk_B¢ñHô¶;vendor/symfony/dependency-injection/ContainerAwareTrait.phpW1Ðk_W Vj¶1vendor/symfony/dependency-injection/Parameter.php¿1Ðk_¿”+›â¶Bvendor/symfony/dependency-injection/ExpressionLanguageProvider.php(1Ðk_(¦¹ Fvendor/symfony/dependency-injection/Compiler/CompilerPassInterface.phpœ1Ðk_œBüÎ_¶Evendor/symfony/dependency-injection/Compiler/DecoratorServicePass.phpê 1Ðk_ê á<>ø¶Mvendor/symfony/dependency-injection/Compiler/ResolveInvalidReferencesPass.phpn 1Ðk_n Qvendor/symfony/dependency-injection/Compiler/ResolveParameterPlaceHoldersPass.phpï 1Ðk_ï <00>nš¶Jvendor/symfony/dependency-injection/Compiler/ServiceReferenceGraphNode.phpü1Ðk_üÉOŠ¿¶Mvendor/symfony/dependency-injection/Compiler/InlineServiceDefinitionsPass.phpÌ1Ðk_Ì2Áæø¶;vendor/symfony/dependency-injection/Compiler/PassConfig.phpH1Ðk_H+†<>Þ¶Fvendor/symfony/dependency-injection/Compiler/ExtensionCompilerPass.php|1Ðk_|¨ÂƶLvendor/symfony/dependency-injection/Compiler/RemoveUnusedDefinitionsPass.php§
1Ðk_§
Ñ•ÑŶPvendor/symfony/dependency-injection/Compiler/MergeExtensionConfigurationPass.php| 1Ðk_| ›‚¶Nvendor/symfony/dependency-injection/Compiler/RemoveAbstractDefinitionsPass.phpõ1Ðk_õp¤Q„¶Kvendor/symfony/dependency-injection/Compiler/CheckReferenceValidityPass.phpÍ1Ðk_ÍîÜÑä¶Ivendor/symfony/dependency-injection/Compiler/RemovePrivateAliasesPass.phpÃ1Ðk_Ãæ<>Ovendor/symfony/dependency-injection/Compiler/ResolveReferencesToAliasesPass.phpŽ1Ðk_ŽX1žJ¶Ovendor/symfony/dependency-injection/Compiler/ResolveDefinitionTemplatesPass.php>"1Ðk_>"øì·}¶Jvendor/symfony/dependency-injection/Compiler/ServiceReferenceGraphEdge.phpÂ1Ðk_Âe]vendor/symfony/dependency-injection/Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php61Ðk_6~"í©¶Avendor/symfony/dependency-injection/Compiler/LoggingFormatter.php¾1Ðk_¾kŠS9vendor/symfony/dependency-injection/Compiler/Compiler.php‰ 1Ðk_‰ ]¸@l¶=vendor/symfony/dependency-injection/Compiler/AutowirePass.php--1Ðk_--ˆ6m̶=vendor/symfony/dependency-injection/Compiler/RepeatedPass.phpŽ1Ðk_ŽÊ$î¶Svendor/symfony/dependency-injection/Compiler/ReplaceAliasByActualDefinitionPass.php$1Ðk_$sl⵶Hvendor/symfony/dependency-injection/Compiler/RepeatablePassInterface.phpK1Ðk_K7ÄÇ߶Mvendor/symfony/dependency-injection/Compiler/AnalyzeServiceReferencesPass.php•1Ðk_•úRý¶Lvendor/symfony/dependency-injection/Compiler/CheckDefinitionValidityPass.php±1Ðk_±òQLvendor/symfony/dependency-injection/Compiler/CheckCircularReferencesPass.php• 1Ðk_• Tî2¼¶Fvendor/symfony/dependency-injection/Compiler/ServiceReferenceGraph.php 1Ðk_ Evendor/symfony/dependency-injection/Compiler/AutoAliasServicePass.phpX1Ðk_XÓTðd¶-vendor/symfony/dependency-injection/Alias.phpz1Ðk_zà/àe¶Uvendor/symfony/dependency-injection/Exception/ParameterCircularReferenceException.php 1Ðk_ ÓqB@vendor/symfony/dependency-injection/Exception/LogicException.php¼1Ðk_¼l.à¶Jvendor/symfony/dependency-injection/Exception/ServiceNotFoundException.php¾1Ðk_¾Ó<>©¶Dvendor/symfony/dependency-injection/Exception/ExceptionInterface.php1Ðk_³ÚQvendor/symfony/dependency-injection/Exception/ScopeWideningInjectionException.php—1Ðk_—¼£úz¶Hvendor/symfony/dependency-injection/Exception/BadMethodCallException.phpÔ1Ðk_Ô
Oö,¶Hvendor/symfony/dependency-injection/Exception/InactiveScopeException.phpî1Ðk_îI_çý¶Qvendor/symfony/dependency-injection/Exception/ScopeCrossingInjectionException.php¥1Ðk_¥= Ô¶Fvendor/symfony/dependency-injection/Exception/OutOfBoundsException.phpÎ1Ðk_Ι{­Œ¶Lvendor/symfony/dependency-injection/Exception/ParameterNotFoundException.php¨
1Ðk_¨
<00>lßî¶Jvendor/symfony/dependency-injection/Exception/InvalidArgumentException.php1Ðk_ÏßSvendor/symfony/dependency-injection/Exception/ServiceCircularReferenceException.phpó1Ðk_ó‚ø]ý¶Bvendor/symfony/dependency-injection/Exception/RuntimeException.phpû1Ðk_ûè
+?vendor/symfony/dependency-injection/ContainerAwareInterface.phpN1Ðk_NÇÊGX¶Dvendor/symfony/dependency-injection/ResettableContainerInterface.phpÇ1Ðk_Ç  µF¶6vendor/symfony/dependency-injection/ContainerAware.php!1Ðk_!þÓk¶'vendor/symfony/polyfill-ctype/README.md`1Ðk_`<6A>%vendor/symfony/polyfill-ctype/LICENSE)1Ðk_)´`e0¶'vendor/symfony/polyfill-ctype/Ctype.php}1Ðk_}\Šè°¶+vendor/symfony/polyfill-ctype/composer.jsonÜ1Ðk_ÜBç?0¶+vendor/symfony/polyfill-ctype/bootstrap.phpî1Ðk_î-¾ªž¶vendor/autoload.php²1Ðk_²ðsrc/main/php/PHPMD/PHPMD.phpª1Ðk_ªÊS»î¶%src/main/php/PHPMD/RuleSetFactory.phpZE1Ðk_ZE´p}"¶5src/main/php/PHPMD/RuleClassFileNotFoundException.phpÎ1Ðk_Îeäm'¶src/main/php/PHPMD/Rule.php|1Ðk_|w»Ðm¶*src/main/php/PHPMD/Writer/StreamWriter.php1Ðk_©‹É‰¶$src/main/php/PHPMD/RuleViolation.php;1Ðk_;tùú;¶&src/main/php/PHPMD/ProcessingError.php 1Ðk_ v$K-¶'src/main/php/PHPMD/AbstractRenderer.phpC1Ðk_Clc©¶src/main/php/PHPMD/Report.php 1Ðk_ ç€ä0src/main/php/PHPMD/Node/AbstractCallableNode.php<68>1Ðk_<6B>ÉÄŸ¶%src/main/php/PHPMD/Node/ClassNode.php¹1Ðk_¹=û4´%src/main/php/PHPMD/Node/TraitNode.phpx1Ðk_xlfŽ¶&src/main/php/PHPMD/Node/Annotation.php1Ðk_<00>LÙ®¶'src/main/php/PHPMD/Node/Annotations.phpÉ1Ðk_ÉYe¾©¶&src/main/php/PHPMD/Node/MethodNode.phpµ1Ðk_µAd•Û¶(src/main/php/PHPMD/Node/AbstractNode.php½1Ðk_½ ­=<3D>(src/main/php/PHPMD/Node/FunctionNode.php01Ðk_0¼P_U¶)src/main/php/PHPMD/Node/InterfaceNode.phpˆ1Ðk_ˆçå8¶#src/main/php/PHPMD/Node/ASTNode.phpf
1Ðk_f
–¨Õ¶,src/main/php/PHPMD/Node/AbstractTypeNode.php¥
1Ðk_¥
͇­¶0src/main/php/PHPMD/TextUI/CommandLineOptions.php¿=1Ðk_¿=gw¶l¶%src/main/php/PHPMD/TextUI/Command.php#1Ðk_#v£•¶,src/main/php/PHPMD/Renderer/JSONRenderer.phpN1Ðk_NKöÈ`¶,src/main/php/PHPMD/Renderer/HTMLRenderer.php-I1Ðk_-IUõ^¡¶+src/main/php/PHPMD/Renderer/XMLRenderer.phpÀ1Ðk_À=,c,src/main/php/PHPMD/Renderer/TextRenderer.php91Ðk_9ˆ1T¥¶,src/main/php/PHPMD/Renderer/AnsiRenderer.php½1Ðk_½$°ƒ<C2B0>1src/main/php/PHPMD/RuleClassNotFoundException.phpÂ1Ðk_‡%src/main/php/PHPMD/Parser.php€1Ðk_€ªL&ö#src/main/php/PHPMD/AbstractNode.php¼1Ðk_¼tf /src/main/php/PHPMD/RuleSetNotFoundException.php¼1Ðk_¼V²"¶src/main/php/PHPMD/RuleSet.phpÞ1Ðk_Þ_‡ßù¶$src/main/php/PHPMD/ParserFactory.php 1Ðk_ ŸQ#src/main/php/PHPMD/AbstractRule.php_)1Ðk__)¡cA¾¶%src/main/php/PHPMD/AbstractWriter.php1Ðk_ü%BÚ¶&src/main/php/PHPMD/Utility/Strings.phpÎ1Ðk_Îߧ”—¶?src/main/php/PHPMD/Exception/RuleClassFileNotFoundException.phpë1Ðk_ëÏSÖB¶;src/main/php/PHPMD/Exception/RuleClassNotFoundException.php¥1Ðk_¥Ùýœ¶9src/main/php/PHPMD/Exception/RuleSetNotFoundException.phpã1Ðk_ãW:Õ¶1src/main/php/PHPMD/Rule/AbstractLocalVariable.php§"1Ðk_§"z[~߶6src/main/php/PHPMD/Rule/Design/WeightedMethodCount.php 1Ðk_ “àv3¶,src/main/php/PHPMD/Rule/Design/LongClass.phpv1Ðk_v胕,¶1src/main/php/PHPMD/Rule/Design/ExitExpression.phpØ1Ðk_Ø3®l˶4src/main/php/PHPMD/Rule/Design/LongParameterList.php¼1Ðk_¼¥$[¶5src/main/php/PHPMD/Rule/Design/DepthOfInheritance.php{1Ðk_{•"uÚ¶1src/main/php/PHPMD/Rule/Design/TooManyMethods.php»1Ðk_»ë-src/main/php/PHPMD/Rule/Design/LongMethod.php<68>1Ðk_<6B>ŒÒ̘¶8src/main/php/PHPMD/Rule/Design/CountInLoopExpression.php-1Ðk_-<00>0src/main/php/PHPMD/Rule/Design/TooManyFields.phpz1Ðk_zû¶9src/main/php/PHPMD/Rule/Design/CouplingBetweenObjects.php"1Ðk_"9>¶7src/main/php/PHPMD/Rule/Design/TooManyPublicMethods.phpÿ1Ðk_ÿývê^¶0src/main/php/PHPMD/Rule/Design/GotoStatement.php1Ðk_Ñ1c 2src/main/php/PHPMD/Rule/Design/EmptyCatchBlock.phpÃ1Ðk_Ãò~eݶ:src/main/php/PHPMD/Rule/Design/DevelopmentCodeFragment.php® 1Ðk_® NÝU¶2src/main/php/PHPMD/Rule/Design/NpathComplexity.php½1Ðk_½à D3src/main/php/PHPMD/Rule/Design/NumberOfChildren.phpg1Ðk_gÆe¨¶1src/main/php/PHPMD/Rule/Design/EvalExpression.phpÙ1Ðk_Ùõ"ûó¶;src/main/php/PHPMD/Rule/CleanCode/IfStatementAssignment.php'1Ðk_'‰Æ¶4src/main/php/PHPMD/Rule/CleanCode/ElseExpression.php 1Ðk_ jÔ£s¶9src/main/php/PHPMD/Rule/CleanCode/BooleanArgumentFlag.phpÕ1Ðk_Õµ¾ë¶2src/main/php/PHPMD/Rule/CleanCode/StaticAccess.phpA 1Ðk_A ‹¨ â¶3src/main/php/PHPMD/Rule/CleanCode/MissingImport.php¹1Ðk_¹Çù¬<C3B9>8src/main/php/PHPMD/Rule/CleanCode/DuplicatedArrayKey.phpq1Ðk_q|Al7src/main/php/PHPMD/Rule/CleanCode/UndefinedVariable.php&1Ðk_&ë0w%¶:src/main/php/PHPMD/Rule/CleanCode/ErrorControlOperator.php«1Ðk_«=žuÛ¶/src/main/php/PHPMD/Rule/UnusedLocalVariable.phpo!1Ðk_o!¢Ÿ»‹¶)src/main/php/PHPMD/Rule/FunctionAware.php1Ðk_<00>äŘ'src/main/php/PHPMD/Rule/MethodAware.phpt1Ðk_tãI1¶*src/main/php/PHPMD/Rule/InterfaceAware.phpz1Ðk_zÌvȶFsrc/main/php/PHPMD/Rule/Naming/ConstructorWithNameAsEnclosingClass.php1Ðk_+kŸ—¶1src/main/php/PHPMD/Rule/Naming/ShortClassName.phpþ1Ðk_þÛ´é7src/main/php/PHPMD/Rule/Naming/BooleanGetMethodName.php 1Ðk_ =SÌ'¶0src/main/php/PHPMD/Rule/Naming/ShortVariable.phpß1Ðk_ßYS²S¶<src/main/php/PHPMD/Rule/Naming/ConstantNamingConventions.phpl1Ðk_lƒw!m¶/src/main/php/PHPMD/Rule/Naming/LongVariable.php|1Ðk_|Æ$¬@¶0src/main/php/PHPMD/Rule/Naming/LongClassName.phpÌ1Ðk_ÌÄv2src/main/php/PHPMD/Rule/Naming/ShortMethodName.phpœ1Ðk_œ³¶0src/main/php/PHPMD/Rule/ExcessivePublicCount.phpÄ1Ðk_Ä"?#<23>/src/main/php/PHPMD/Rule/UnusedPrivateMethod.phpe1Ðk_ehxd¶1src/main/php/PHPMD/Rule/UnusedFormalParameter.php²1Ðk_²!¹õ™¶.src/main/php/PHPMD/Rule/UnusedPrivateField.phpž1Ðk_ži鶲¶?src/main/php/PHPMD/Rule/Controversial/CamelCaseVariableName.php+ 1Ðk_+ âñ"¶?src/main/php/PHPMD/Rule/Controversial/CamelCasePropertyName.php‡1Ðk_‡ïOè¶=src/main/php/PHPMD/Rule/Controversial/CamelCaseMethodName.phpñ1Ðk_ñVˆƶ@src/main/php/PHPMD/Rule/Controversial/CamelCaseParameterName.php¿1Ðk_¿4e ë¶<src/main/php/PHPMD/Rule/Controversial/CamelCaseClassName.phpD1Ðk_D`ßÒ¶6src/main/php/PHPMD/Rule/Controversial/Superglobals.phph1Ðk_hü-<2D>¹¶0src/main/php/PHPMD/Rule/CyclomaticComplexity.php<68>1Ðk_<6B>¥Ž²E¶&src/main/php/PHPMD/Rule/ClassAware.php|1Ðk_|TjØ*src/main/resources/rulesets/unusedcode.xml] 1Ðk_] à^¥¶)src/main/resources/rulesets/cleancode.xmlŠ1Ðk_Š
S&¿¶&src/main/resources/rulesets/design.xml#1Ðk_#¨¹Ìð¶(src/main/resources/rulesets/codesize.xml¶91Ðk_¶9A&src/main/resources/rulesets/naming.xml÷71Ðk_÷7*C·¶-src/main/resources/rulesets/controversial.xmlh1Ðk_h¤ßÝ
PHP Depend
=======
[![Build Status](https://travis-ci.org/pdepend/pdepend.svg?branch=master)](https://travis-ci.org/pdepend/pdepend)
[![Packagist](https://img.shields.io/packagist/dt/pdepend/pdepend.svg)](https://github.com/pdepend/pdepend)
[![codecov.io](https://codecov.io/gh/pdepend/pdepend/branch/master/graphs/badge.svg?branch=master)](https://codecov.io/github/pdepend/pdepend?branch=master)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/pdepend/pdepend/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/pdepend/pdepend/?branch=master)
[![Chat to us on Gitter](https://badges.gitter.im/pdepend/community.svg)](https://gitter.im/pdepend/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
## [Documentation](https://pdepend.org/)
## PHP Depend for enterprise
Available as part of the Tidelift Subscription.
The maintainers of ``PHP Depend`` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-pdepend-pdepend?utm_source=packagist-pdepend-pdepend&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
BSD 3-Clause License
Copyright (c) 2008, Manuel Pichler
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pdepend-2.8.0 (2020/05/25)
==========================
- Added [\#458](https://github.com/pdepend/pdepend/pull/458) Support trait insteadof overrides. (Issue [\#367](https://github.com/pdepend/pdepend/issues/367) and [\#320](https://github.com/pdepend/pdepend/issues/320) )
- Added [\#466](https://github.com/pdepend/pdepend/pull/466) Allow to configure file cache ttl in configuration file. (Issue [\#465](https://github.com/pdepend/pdepend/issues/465))
- Added [\#487](https://github.com/pdepend/pdepend/pull/484) Support arrow functions return type hints.
- Fixed [\#467](https://github.com/pdepend/pdepend/pull/467) Use the HOME env variable also for Windows. (Issue [\#447](https://github.com/pdepend/pdepend/issue/447) )
- Fixed [\#475](https://github.com/pdepend/pdepend/pull/475) Fixed [\#474](https://github.com/pdepend/pdepend/issues/474) typed property visibility
- Fixed [\#476](https://github.com/pdepend/pdepend/pull/476) Fixed [\#473](https://github.com/pdepend/pdepend/issues/473) handle skipped variable in destructuring array
- Fixed [\#478](https://github.com/pdepend/pdepend/pull/478) Fixed [\#472](https://github.com/pdepend/pdepend/issues/472) Use the current token instead of the first inner one to determine the class start.
- Fixed [\#483](https://github.com/pdepend/pdepend/pull/483) Fixed bool flip in parseEscapedAstLiteralString()
- Fixed [\#479](https://github.com/pdepend/pdepend/pull/479) Fixed [\#299](https://github.com/pdepend/pdepend/issues/299) Class constant expression declaration.
- Changed: Tidelift language ( [\#460](https://github.com/pdepend/pdepend/pull/460), [\#461](https://github.com/pdepend/pdepend/pull/461) and [\#462](https://github.com/pdepend/pdepend/pull/462) )
- Changed: Interal cleanup with refactoring and adding missing PHPDoc ( [\#477](https://github.com/pdepend/pdepend/pull/477), [\#484](https://github.com/pdepend/pdepend/pull/484) and [\#485](https://github.com/pdepend/pdepend/pull/485) )
pdepend-2.7.1 (2020/02/12)
==========================
- Fixed [\#453](https://github.com/pdepend/pdepend/pull/453) Support for typed properties (nullable, array, FQN, scalar)
- Fixed [\#446](https://github.com/pdepend/pdepend/pull/446) Suppress E_NOTICE thrown by unserialize()
pdepend-2.7.0 (2020/01/24)
==========================
- Added [\#362](https://github.com/pdepend/pdepend/pull/362) Support for php:// stream wrappers
- Added [\#427](https://github.com/pdepend/pdepend/pull/427) PHP 7.4 features support
pdepend-2.6.1 (2019/12/21)
==========================
- Added [\#398](https://github.com/pdepend/pdepend/pull/398) Support for Symfony 5
- Fixed [\#299](https://github.com/pdepend/pdepend/pull/299) Array concatenation in constant declaration
pdepend-2.6.0 (2019/12/16)
==========================
- Added [\#383](https://github.com/pdepend/pdepend/pull/383) Support of PHP 7.1 syntax
- Fixed [\#386](https://github.com/pdepend/pdepend/pull/386) PHP 7 and parsing some return types
- Fixed [\#381](https://github.com/pdepend/pdepend/pull/381) Unexpected token error with invokable
- Fixed [\#365](https://github.com/pdepend/pdepend/pull/365) unable to call method on newly created and invoked class
- Removed not needed files from the export used by composer
pdepend-2.5.2 (2017/12/13)
==========================
This release contains a single bugfix for missing command options.
- Fix for GH355: Unknown option --jdepend-chart [\#356](https://github.com/pdepend/pdepend/pull/356) ([manuelpichler](https://github.com/manuelpichler))
pdepend-2.5.1 (2017/12/06)
==========================
This release contains many bugfixes, enables Scrutinizer and adds code coverage integration. HHVM support was dropped. Full support for missing language features for PHP <= 7.1 were added.
- Support for "yield from" in PHP 7.0 [\#350](https://github.com/pdepend/pdepend/pull/350) ([emirb](https://github.com/emirb))
- Support for constant visibility in interfaces in PHP 7.1 [\#349](https://github.com/pdepend/pdepend/pull/349) ([KacerCZ](https://github.com/KacerCZ))
- Support catch of multiple exception types in PHP 7.1 [\#348](https://github.com/pdepend/pdepend/pull/348) ([KacerCZ](https://github.com/KacerCZ))
- Added support for PHP 7.1 types - iterable and void [\#342](https://github.com/pdepend/pdepend/pull/342) ([KacerCZ](https://github.com/KacerCZ))
- Add Symfony 4 support [\#340](https://github.com/pdepend/pdepend/pull/340) ([surikman](https://github.com/surikman))
- Fix Scrutinizer config [\#336](https://github.com/pdepend/pdepend/pull/336) ([emirb](https://github.com/emirb))
- Fixed PHPUnit warnings [\#333](https://github.com/pdepend/pdepend/pull/333) ([KacerCZ](https://github.com/KacerCZ))
- Codecov explicit coverage file [\#332](https://github.com/pdepend/pdepend/pull/332) ([emirb](https://github.com/emirb))
- Add codecov.io integration [\#331](https://github.com/pdepend/pdepend/pull/331) ([emirb](https://github.com/emirb))
- Use uniqid\(\) in AbstractASTArtifact::getId\(\) instead of microtime\(\) [\#330](https://github.com/pdepend/pdepend/pull/330) ([KacerCZ](https://github.com/KacerCZ))
- Fix Iterator so it will not return directories [\#329](https://github.com/pdepend/pdepend/pull/329) ([KacerCZ](https://github.com/KacerCZ))
- Fix tests on Windows [\#328](https://github.com/pdepend/pdepend/pull/328) ([KacerCZ](https://github.com/KacerCZ))
- PHP 7.2 fixes [\#326](https://github.com/pdepend/pdepend/pull/326) ([emirb](https://github.com/emirb))
- Capitalize XML word [\#325](https://github.com/pdepend/pdepend/pull/325) ([bocharsky-bw](https://github.com/bocharsky-bw))
- Fix typo [\#321](https://github.com/pdepend/pdepend/pull/321) ([ravage84](https://github.com/ravage84))
- Fixes \#193 regression [\#319](https://github.com/pdepend/pdepend/pull/319) ([mdeboer](https://github.com/mdeboer))
- Remove running of PHP 5.3 build since dropped by Travis. [\#316](https://github.com/pdepend/pdepend/pull/316) ([niconoe-](https://github.com/niconoe-))
- Fix issue \#297 adding support for constant visibility into the parser for PHP 7.1 [\#314](https://github.com/pdepend/pdepend/pull/314) ([mmucklo](https://github.com/mmucklo))
- Remove references to HHVM [\#309](https://github.com/pdepend/pdepend/pull/309) ([ravage84](https://github.com/ravage84))
- fix count\(\): Parameter must be an array or an object that implements ... [\#303](https://github.com/pdepend/pdepend/pull/303) ([remicollet](https://github.com/remicollet))
- "a xml" -\> "an xml" [\#300](https://github.com/pdepend/pdepend/pull/300) ([bocharsky-bw](https://github.com/bocharsky-bw))
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",
"type": "library",
"require": {
"php": ">=5.3.7",
"symfony/dependency-injection": "^2.3.0|^3|^4|^5",
"symfony/filesystem": "^2.3.0|^3|^4|^5",
"symfony/config": "^2.3.0|^3|^4|^5"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35|^5.7",
"squizlabs/php_codesniffer": "^2.0.0",
"gregwar/rst": "^1.0",
"easy-doc/easy-doc": "0.0.0 || ^1.2.3"
},
"bin": ["src/bin/pdepend"],
"autoload": {
"psr-4": {"PDepend\\": "src/main/php/PDepend"}
},
"scripts": {
"test": "phpunit",
"cs-check": "phpcs -p --standard=PSR2 --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 ./src/main/php ./src/test/php",
"cs-fix": "phpcbf -p --standard=PSR2 --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 ./src/main/php ./src/test/php",
"build-website": "easy-doc build src/site/config.php --verbose"
},
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
}
}
<?xml version="1.0"?>
<ruleset name="PHP_Depend">
<description>Coding standard for PDepend.</description>
<file>scripts</file>
<file>src</file>
<!-- Website content -->
<exclude-pattern>src/site/</exclude-pattern>
<!-- Files for unit tests -->
<exclude-pattern>src/test/resources/</exclude-pattern>
<arg name="colors"/>
<arg value="np"/>
<rule ref="PSR2"/>
</ruleset>
project.dir =
project.uri = pdepend.org
project.name = pdepend
project.version = 2.8.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-4.8.36
phpunit.enabled = false
#!/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());
<?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\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder as BaseTreeBuilder;
/**
* This is the class that embed the Symfony TreeBuilder and its root node.
*/
class TreeBuilder
{
/**
* @var NodeDefinition|ArrayNodeDefinition
*/
protected $rootNode;
/**
* @var BaseTreeBuilder
*/
protected $treeBuilder;
/**
* TreeBuilder constructor.
*
* @param string $name
*/
public function __construct($name = 'pdepend')
{
if (method_exists('Symfony\\Component\\Config\\Definition\\Builder\\TreeBuilder', 'root')) {
// Symfony < 5
$this->treeBuilder = new BaseTreeBuilder();
$this->rootNode = $this->treeBuilder->root($name);
return;
}
// Symfony 5+
$this->treeBuilder = new BaseTreeBuilder($name);
$this->rootNode = $this->treeBuilder->getRootNode();
}
/**
* Get the root node of the built tree.
*
* @return ArrayNodeDefinition|NodeDefinition
*/
public function getRootNode()
{
return $this->rootNode;
}
/**
* Get the base Symfony tree builder.
*
* @return BaseTreeBuilder
*/
public function getTreeBuilder()
{
return $this->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;
/**
* 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 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 PDepend\Util\FileUtil;
use PDepend\Util\Workarounds;
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
{
const DEFAULT_TTL = 2592000; //30 days
/**
* @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->getRootNode();
$rootNode
->children()
->arrayNode('cache')
->addDefaultsIfNotSet()
->children()
->enumNode('driver')->defaultValue($defaultCacheDriver)->values(array('file', 'memory'))->end()
->scalarNode('location')->info('This value is only used for the file cache.')->defaultValue($home . '/.pdepend')->end()
->integerNode('ttl')->info('This value is only used for the file cache. Value in seconds.')->defaultValue(self::DEFAULT_TTL)->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->getTreeBuilder();
}
}
<?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->cache->ttl = $config['cache']['ttl'];
$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\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\DbusUI;
// This is just fun and it is not really testable
// @codeCoverageIgnoreStart
use Dbus;
use DBusArray;
use DBusDict;
use DBusUInt32;
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;
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, array>
*/
public function getAvailableLoggerOptions()
{
return $this->getAvailableOptionsFor('pdepend.logger');
}
/**
* Returns available analyzer options and documentation messages.
*
* @return array<string, array>
*/
public function getAvailableAnalyzerOptions()
{
return $this->getAvailableOptionsFor('pdepend.analyzer');
}
/**
* @return array<string, array>
*/
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\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 integer
* @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 array<integer, string>
*/
private $source = array();
/**
* 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 integer $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\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
*/
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)) {
$this->fireEndClass($class);
return;
}
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);
$this->fireEndFile($compilationUnit);
return;
}
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)) {
$this->fireEndFunction($function);
return;
}
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)) {
$this->fireEndInterface($interface);
return;
}
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)) {
$this->fireEndMethod($method);
return;
}
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\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
*/
private $ccnAnalyzer = null;
/**
* 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\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\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\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\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\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;
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<string, integer>
*/
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) 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\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);
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);
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) 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\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\Source\AST\AbstractASTArtifact;
use PDepend\Source\AST\AbstractASTClassOrInterface;
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();
/**
* Nodes in which the current analyzed dependency is used.
*
* @var array<string, array<integer, \PDepend\Source\AST\AbstractASTArtifact>>
*/
private $efferentNodes = array();
/**
* Nodes that is used by the current analyzed node.
*
* @var array<string, array<integer, \PDepend\Source\AST\AbstractASTArtifact>>
*/
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|null>
*/
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
*/
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 $node
* @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) 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\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();
/**
* Nodes in which the current analyzed class is used.
*
* @var array<string, array<integer, \PDepend\Source\AST\AbstractASTArtifact>>
*/
private $efferentNodes = array();
/**
* Nodes that is used by the current analyzed class.
*
* @var array<string, array<integer, \PDepend\Source\AST\AbstractASTArtifact>>
*/
private $afferentNodes = 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 $typeA
* @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 $node
* @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\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 = count($class->getInterfaces());
$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) 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 (...)â€<C3A2>, “if (...)â€<C3A2>, “switch (...)â€<C3A2>, “while(...)â€<C3A2>,
* “try-catch( )â€<C3A2> 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â€<C3A2> 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\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 = array();
/**
* @var array<integer>
*
* @deprecated 3.0.0 This property will no longer be accessible on the public access level in next major version.
*/
public $derivedClasses = array();
/**
* 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\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
* @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;
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;
/**
* 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\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\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
* @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;
/**
* 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
{
}
<?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;
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);
}
<?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|null
*/
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;
/**
* 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\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\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', (string)$type->getStartLine());
$typeXml->setAttribute('end', (string)$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', (string)$function->getStartLine());
$functionXml->setAttribute('end', (string)$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', (string)$method->getStartLine());
$methodXml->setAttribute('end', (string)$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;
/**
* 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;
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;
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);
}
<?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,
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);
}
}
<?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);
}
}
<?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\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\ClassDependencyAnalyzer|null
*/
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\Metrics\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 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(PHP_VERSION, '5.4.0', '>') && version_compare(PHP_VERSION, '5.4.5', '<=');
}
/**
* 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 ' . PHP_VERSION;
}
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;
/**
* 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|null
*/
private static $configuration = null;
/**
* Returns a configured config instance or <b>null</b>.
*
* @return \PDepend\Util\Configuration|null
*/
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 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()
{
$userHomeDir = getenv('HOME');
if (!$userHomeDir) {
// The HOME environment isn't always set on Windows, then we do a fallback to the HOMEDRIVE and HOMEPATH
$userHomeDir = getenv('HOMEDRIVE') . getenv('HOMEPATH');
}
return $userHomeDir;
}
}
<?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
{
/**
* @var array<array>
*
* @deprecated 3.0.0 This property will no longer be accessible on the public access level in next major version.
*/
public $offsetInFile = array();
/**
* 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
*/
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) {
$xmlError = libxml_get_last_error();
throw new \RuntimeException($xmlError ? trim($xmlError->message) : 'Unknown error');
}
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;
/**
* 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, bool>
*/
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|null
*/
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) {
self::$internalNamespaces = array();
foreach (self::initTypeToExtension() as $namespace) {
self::$internalNamespaces[$namespace] = $namespace;
}
}
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|null
* @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;
/**
* 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
* @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
{
const DEFAULT_TTL = 2592000; //30 days
/**
* 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;
/**
* This method constructs a new file cache instance for the given root
* directory.
*
* @param string $root The cache root directory.
* @param int $ttl The cache TTL.
* @param string|null $cacheKey Unique key for this cache instance.
*/
public function __construct($root, $ttl = self::DEFAULT_TTL, $cacheKey = null)
{
$this->directory = new FileCacheDirectory($root);
$this->version = preg_replace('(^(\d+\.\d+).*)', '\\1', phpversion());
$this->cacheKey = $cacheKey;
$this->garbageCollect($root, $ttl);
}
/**
* 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)
{
// unserialize() throws E_NOTICE when data is corrupt
$data = @unserialize($this->read($file));
if ($data !== false && $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
* @param int $ttl
* @return void
*/
protected function garbageCollect($root, $ttl)
{
$garbageCollector = new FileCacheGarbageCollector($root, $ttl);
$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
* @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<string, array<string, array<integer, mixed>>>
*/
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
*/
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
{
const DEFAULT_TTL = 2592000; //30 days
/**
* @var string
*/
private $cacheDir;
/**
* @var integer
*/
private $expirationTimestamp;
/**
* @param string $cacheDir
* @param integer $ttl
*/
public function __construct($cacheDir, $ttl = self::DEFAULT_TTL)
{
$this->cacheDir = $cacheDir;
$this->expirationTimestamp = time() - $ttl;
}
/**
* 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->expirationTimestamp) {
return false;
}
$time = $file->getMTime();
if ($time > $this->expirationTimestamp) {
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\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|null
*/
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
* @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
{
const DEFAULT_TTL = 2592000; //30 days
/**
* 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|null $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 = null)
{
switch ($this->configuration->cache->driver) {
case 'file':
return $this->createFileCache(
$this->configuration->cache->location,
$this->configuration->cache->ttl,
$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 int $ttl Cache ttl
* @param string|null $cacheKey The name/identifier for the cache instance.
* @return \PDepend\Util\Cache\Driver\FileCacheDriver
*/
protected function createFileCache($location, $ttl = self::DEFAULT_TTL, $cacheKey = null)
{
return new FileCacheDriver($location, $ttl, $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;
/**
* 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:a31e9e344aac643e20751f6d915114eb:@';
/**
* 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
*/
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 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\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)
{
$encoding = 'UTF8';
if (function_exists('mb_detect_encoding')) {
$encoding = mb_detect_encoding($raw) ?: $encoding;
}
$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;
// @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;
use ArrayIterator;
use GlobIterator;
use PDepend\Input\CompositeFilter;
use PDepend\Input\Filter;
use PDepend\Input\Iterator;
use PDepend\Metrics\AnalyzerCacheAware;
use PDepend\Metrics\AnalyzerFactory;
use PDepend\Metrics\AnalyzerFilterAware;
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;
use SplFileObject;
/**
* 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;
/**
* Prefix for PHP streams.
*
* @var string
*/
protected $phpStreamPrefix = 'php://';
/**
* 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 ($dir === false || !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 = $this->phpStreamPrefix . 'stdin';
}
if ($this->isPhpStream($file)) {
$this->files[] = $file;
return;
}
if (!is_file($file)) {
throw new \InvalidArgumentException(sprintf('The given file "%s" does not exist.', $file));
}
$this->files[] = realpath($file);
}
/**
* 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 += count($namespace->getTypes());
}
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(
$this->isPhpStream($file)
? new ArrayIterator(array(new SplFileObject($file)))
: 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 = $file->getRealPath() ?: $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;
}
private function isPhpStream($path)
{
return substr($path, 0, strlen($this->phpStreamPrefix)) === $this->phpStreamPrefix;
}
}
<?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;
/**
* 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()
{
if ($this->getInnerIterator()->current()->isDir()) {
return false;
}
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;
/**
* 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\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;
/**
* 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
* @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\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 node for the iterable type.
*
* @return \PDepend\Source\AST\ASTTypeIterable
* @since 2.5.1
*/
public function buildAstTypeIterable();
/**
* 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.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.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.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.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.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
* @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
*/
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
*/
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 \PDepend\Source\AST\ASTArtifactList
* @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.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|null
*/
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 string
* @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|null
*/
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;
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.
*
* 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;
use OutOfBoundsException;
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 have 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()
{
$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()
{
$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 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 1.0.0
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* This node class represents a trait 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[]|null
*/
private $allMethods;
/**
* Returns an array with all aliased or directly imported methods.
*
* @return \PDepend\Source\AST\ASTMethod[]
*/
public function getAllMethods()
{
if ($this->allMethods === null) {
$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
* @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.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 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;
/**
* 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|null
*/
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|null
*/
protected $compilationUnit = null;
/**
* The comment for this type.
*
* @var string|null
*/
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(uniqid('', true));
}
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|null
*/
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 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 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.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;
/**
* 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
*/
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 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.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.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
* @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.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.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;
/**
* 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.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
*/
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 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.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.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.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;
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|null
*/
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
*/
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
* @since 0.9.6
*/
namespace PDepend\Source\AST;
use OutOfBoundsException;
/**
* 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
{
/**
* 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 have a type specification.');
}
/**
* 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
* @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
*/
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 $classReference
* @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 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
*/
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|null
* @since 0.10.0
*/
private $namespace = null;
/**
* The currently used builder context.
*
* @var \PDepend\Source\Builder\BuilderContext|null
* @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|null
*/
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
* @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.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 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()
{
$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
*/
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
*/
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
*/
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.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.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;
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
{
/**
* 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;
if (($expected & $modifiers) !== 0) {
throw new \InvalidArgumentException(
'Invalid field modifiers given, allowed modifiers are ' .
'IS_PUBLIC, IS_PROTECTED and IS_PRIVATE.'
);
}
$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);
}
/**
* 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);
}
/**
* 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
* @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
* @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
*/
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 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.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.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 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 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|null
*/
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 integer
*/
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
*/
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.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
* @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
* @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(
sprintf(
'The mandatory parent was not defined for the %s named %s.',
get_class($owner),
$owner->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.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
*/
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
*/
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|null $fileName The source file name/path.
*/
public function __construct($fileName)
{
if ($fileName && 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 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.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
* @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.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.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 1.0.0
*/
namespace PDepend\Source\AST;
use PDepend\Source\Builder\BuilderContext;
use PDepend\Source\Tokenizer\Token;
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|null
*/
protected $cache = null;
/**
* The currently used builder context.
*
* @var \PDepend\Source\Builder\BuilderContext|null
*/
protected $context = null;
/**
* The parent namespace for this class.
*
* @var \PDepend\Source\AST\ASTNamespace|null
*/
private $namespace = null;
/**
* An <b>array</b> with all constants defined in this class or interface.
*
* @var array<string, mixed>|null
*/
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|null
*/
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 ASTMethod[]|null
* @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|null
* @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 ASTArtifactList<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 ASTMethod $method
* @return 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 ASTMethod[]
* @since 1.0.0
*/
protected function getTraitMethods()
{
$methods = array();
$uses = $this->findChildrenOfType(
'PDepend\\Source\\AST\\ASTTraitUseStatement'
);
foreach ($uses as $use) {
$priorMethods = array();
$precedences = $use->findChildrenOfType('PDepend\\Source\\AST\\ASTTraitAdaptationPrecedence');
/** @var ASTTraitAdaptationPrecedence $precedence */
foreach ($precedences as $precedence) {
$priorMethods[strtolower($precedence->getImage())] = true;
}
/** @var ASTMethod $method */
foreach ($use->getAllMethods() as $method) {
foreach ($uses as $use2) {
if ($use2->hasExcludeFor($method)) {
continue 2;
}
}
$name = strtolower($method->getName());
if (!isset($methods[$name]) || isset($priorMethods[$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, Token $startToken = null)
{
if (!$startToken) {
$startToken = reset($tokens);
}
$this->startLine = $startToken->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 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
*/
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|null
* @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|null
* @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|null
* @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.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;
/**
* 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|null
*/
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|null
*/
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.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 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
*/
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|null
* @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|null
* @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[]|null
*/
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|null
* @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 ASTClassOrInterfaceReferenceIterator
*/
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|null
* @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|null
*/
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 ASTClassOrInterfaceReferenceIterator
*/
public function getExceptionClasses()
{
return new ASTClassOrInterfaceReferenceIterator(
$this->exceptionClassReferences
);
}
/**
* Returns an array with all method/function parameters.
*
* @return \PDepend\Source\AST\ASTParameter[]|null
*/
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
* @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
* @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
* @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;
/**
* 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 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 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.
*
* 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.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.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;
/**
* 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
*/
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 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 ASTFormalParameter $formalParameter
*/
public function __construct(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|null
* @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|null
* @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();
return $value === null ? null : $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
* @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.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;
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
* @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 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 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.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.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;
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|null
* @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()
{
$static = '';
if ($this->isStatic() === true) {
$static = ' static';
}
$visibility = ' public';
if ($this->isProtected() === true) {
$visibility = ' protected';
} elseif ($this->isPrivate() === true) {
$visibility = ' private';
}
return sprintf(
'Property [%s%s %s ]%s',
$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
* @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.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 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.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
*/
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.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;
/**
* 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
*/
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;
/**
* 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;
/**
* 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
* @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
* @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.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 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.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.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|null
*/
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.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 $target
*/
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;
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;
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
* @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 2.5.1
*/
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 2.5.1
*/
class ASTTypeIterable extends ASTType
{
/**
* The visual image for this node type.
*/
const IMAGE = 'iterable';
/**
* @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->visitTypeIterable($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.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.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
* @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
*/
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 2.3
*/
namespace PDepend\Source\Language\PHP;
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 PHPParserVersion55 extends PHPParserVersion54
{
/**
* Parses a full qualified class name postfix.
*
* parseFullQualifiedClassNamePostfix() exists since 2.0.0 and have been customized for PHP 5.5 since 2.6.0.
*
* @return \PDepend\Source\AST\ASTClassFqnPostfix
* @since 2.0.0
*/
protected function parseFullQualifiedClassNamePostfix()
{
$this->tokenStack->push();
$this->consumeToken(Tokens::T_CLASS_FQN);
return $this->setNodePositionsAndReturn(
$this->builder->buildAstClassFqnPostfix()
);
}
}
<?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\ASTAllocationExpression;
use PDepend\Source\AST\ASTArguments;
use PDepend\Source\AST\ASTArray;
use PDepend\Source\AST\ASTCatchStatement;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTCompoundVariable;
use PDepend\Source\AST\ASTDeclareStatement;
use PDepend\Source\AST\ASTExpression;
use PDepend\Source\AST\ASTFunctionPostfix;
use PDepend\Source\AST\ASTIndexExpression;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMemberPrimaryPrefix;
use PDepend\Source\AST\ASTNode;
use PDepend\Source\AST\ASTStatement;
use PDepend\Source\AST\ASTSwitchStatement;
use PDepend\Source\AST\ASTTrait;
use PDepend\Source\AST\ASTTraitAdaptation;
use PDepend\Source\AST\ASTTraitUseStatement;
use PDepend\Source\AST\ASTValue;
use PDepend\Source\AST\ASTVariable;
use PDepend\Source\AST\ASTVariableVariable;
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|null
*/
private $namespaceName;
/**
* Last parsed package tag.
*
* @var string|null
*/
private $packageName = Builder::DEFAULT_NAMESPACE;
/**
* The package defined in the file level comment.
*
* @var string|null
*/
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|null
*/
private $docComment;
/**
* Bitfield of last parsed modifiers.
*
* @var integer
*/
private $modifiers = 0;
/**
* The actually parsed class or interface instance.
*
* @var \PDepend\Source\AST\AbstractASTClassOrInterface|null
*/
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\Parser\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', (string)$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 integer $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);
}
throw $this->getUnexpectedTokenException();
}
/**
* 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);
}
throw $this->getUnexpectedTokenException();
}
/**
* @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);
}
throw $this->getUnexpectedTokenException();
}
/**
* @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()
{
$startToken = $this->tokenizer->currentToken();
$this->tokenStack->push();
$class = $this->parseClassSignature();
$class = $this->parseTypeBody($class);
$class->setTokens($this->tokenStack->pop(), $startToken);
$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\AbstractASTClassOrInterface $classOrInterface
* @return \PDepend\Source\AST\AbstractASTClassOrInterface
* @throws \PDepend\Source\Parser\UnexpectedTokenException
* @throws \PDepend\Source\Parser\TokenStreamEndException
*/
protected function parseTypeBody(AbstractASTClassOrInterface $classOrInterface)
{
$this->classOrInterface = $classOrInterface;
// Consume comments and read opening curly brace
$this->consumeComments();
$this->consumeToken(Tokens::T_CURLY_BRACE_OPEN);
$defaultModifier = State::IS_PUBLIC;
if ($classOrInterface 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 ASTNode) {
$classOrInterface->addChild($methodOrProperty);
}
$this->reset();
break;
case Tokens::T_CONST:
$classOrInterface->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 $classOrInterface;
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
);
$classOrInterface->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
);
$classOrInterface->addChild($comment);
$this->docComment = $token->image;
break;
case Tokens::T_USE:
$classOrInterface->addChild($this->parseTraitUseStatement());
break;
default:
throw $this->getUnexpectedTokenException();
}
$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
*/
protected 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:
return $this->parseUnknownDeclaration($tokenType, $modifiers);
}
$this->consumeToken($tokenType);
$this->consumeComments();
$tokenType = $this->tokenizer->peek();
}
throw $this->getUnexpectedTokenException();
}
/**
* Override this in later PHPParserVersions as necessary
* @param integer $tokenType
* @param integer $modifiers
* @return \PDepend\Source\AST\ASTConstantDefinition
* @throws UnexpectedTokenException
*/
protected function parseUnknownDeclaration($tokenType, $modifiers)
{
throw $this->getUnexpectedTokenException();
}
/**
* 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
*/
protected 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()) {
return $this->setNodePositionsAndReturn(
$this->parseClosureDeclaration()
);
}
$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
*/
protected function parseOptionalByReference()
{
return $this->isNextTokenByReference() && $this->parseByReference();
}
/**
* 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 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 ASTTraitUseStatement $useStatement
* @return ASTTraitUseStatement
* @since 1.0.0
*/
private function parseOptionalTraitAdaptation(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 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();
$stmt = Tokens::T_AS === $this->tokenizer->peek()
? $this->parseTraitAdaptationAliasStatement($reference)
: $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);
}
/**
* Throws an exception if the given token is not a valid list unpacking opening token for current PHP level.
*
* @param int $tokenType
* @param \PDepend\Source\Tokenizer\Token $unexpectedToken
*/
private function ensureTokenIsListUnpackingOpening($tokenType, $unexpectedToken = null)
{
if (!$this->isListUnpacking($tokenType)) {
throw $this->getUnexpectedTokenException($unexpectedToken ?: $this->tokenizer->prevToken());
}
}
/**
* Return true if current PHP level supports keys in lists.
*
* @return bool
*/
protected function supportsKeysInList()
{
return false;
}
/**
* This method parses a single list-statement node.
*
* @return \PDepend\Source\AST\ASTListExpression
* @since 0.9.12
*/
private function parseListExpression()
{
$this->tokenStack->push();
$tokenType = $this->tokenizer->peek();
$this->ensureTokenIsListUnpackingOpening($tokenType);
$shortSyntax = ($tokenType !== Tokens::T_LIST);
if ($shortSyntax) {
$token = $this->consumeToken(Tokens::T_SQUARED_BRACKET_OPEN);
$list = $this->builder->buildAstListExpression($token->image);
} else {
$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_SQUARED_BRACKET_CLOSE:
case Tokens::T_PARENTHESIS_CLOSE:
break 2;
case Tokens::T_LIST:
case Tokens::T_SQUARED_BRACKET_OPEN:
$list->addChild($this->parseListExpression());
$this->consumeComments();
break;
default:
$list->addChild($this->parseListSlotExpression());
$this->consumeComments();
break;
}
}
$closeToken = $shortSyntax ? Tokens::T_SQUARED_BRACKET_CLOSE : Tokens::T_PARENTHESIS_CLOSE;
$this->consumeToken($closeToken);
return $this->setNodePositionsAndReturn($list);
}
/**
* Parse individual slot of a list() expression.
*
* @return \PDepend\Source\AST\ASTListExpression|ASTNode
*/
private function parseListSlotExpression()
{
$startToken = $this->tokenizer->currentToken();
$node = $this->parseOptionalExpression();
if ($node && !$this->isReadWriteVariable($node) && $this->tokenizer->peek() === Tokens::T_DOUBLE_ARROW) {
if (!$this->supportsKeysInList()) {
throw $this->getUnexpectedTokenException($startToken);
}
$this->consumeComments();
$this->consumeToken(Tokens::T_DOUBLE_ARROW);
$this->consumeComments();
return in_array($this->tokenizer->peek(), array(Tokens::T_LIST, Tokens::T_SQUARED_BRACKET_OPEN))
? $this->parseListExpression()
: $this->parseVariableOrConstantOrPrimaryPrefix();
}
return $node ?: $this->parseVariableOrConstantOrPrimaryPrefix();
}
/**
* 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\ASTCastExpression
* @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|null $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;
}
/**
* @param boolean $classRef
* @return \PDepend\Source\AST\ASTClassOrInterfaceReference|ASTNode|\PDepend\Source\AST\ASTSelfReference|\PDepend\Source\AST\ASTStaticReference
*/
private function parseStandAloneExpressionTypeReference($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;
}
return $ref;
}
/**
* 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)
{
$expr->addChild(
$this->parseOptionalMemberPrimaryPrefix(
$this->parseOptionalStaticMemberPrimaryPrefix(
$this->parseStandAloneExpressionTypeReference($classRef)
)
)
);
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();
return $this->setNodePositionsAndReturn(
$this->builder->buildAstNeededReference(
$this->parseQualifiedName(),
$classReference
)
);
}
/**
* 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
*/
protected 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 $exprList
* @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|null
* @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:
case Tokens::T_SQUARED_BRACKET_OPEN:
$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_FN:
$expressions[] = $this->parseLambdaFunctionDeclaration();
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:
case Tokens::T_COALESCE_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_ELLIPSIS:
$this->checkEllipsisInExpressionSupport();
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()
{
throw $this->getUnexpectedTokenException();
}
/**
* 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;
}
}
throw $this->getUnexpectedTokenException();
}
/**
* 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))) {
throw $this->getUnexpectedTokenException();
}
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);
$this->parseCatchExceptionClass($catch);
$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 class references in catch statement.
*
* @param \PDepend\Source\AST\ASTCatchStatement $stmt The owning catch statement.
*/
protected function parseCatchExceptionClass(ASTCatchStatement $stmt)
{
$stmt->addChild(
$this->builder->buildAstClassOrInterfaceReference(
$this->parseQualifiedName()
)
);
}
/**
* 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();
$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|null
* @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|null
* @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 methods return true if the token matches a list opening in the current PHP version level.
*
* @param int $tokenType
* @return bool
* @since 2.6.0
*/
protected function isListUnpacking($tokenType = null)
{
return ($tokenType ?: $this->tokenizer->peek()) === Tokens::T_LIST;
}
/**
* Get the parsed list of a foreach statement children.
*
* @return ASTNode[]
*/
private function parseForeachChildren()
{
if ($this->tokenizer->peek() === Tokens::T_BITWISE_AND) {
return array($this->parseVariableOrMemberByReference());
}
if ($this->isListUnpacking()) {
return array($this->parseListExpression());
}
$children = array(
$this->parseVariableOrConstantOrPrimaryPrefix()
);
if ($this->tokenizer->peek() === Tokens::T_DOUBLE_ARROW) {
$this->consumeToken(Tokens::T_DOUBLE_ARROW);
$children[] = $this->isListUnpacking()
? $this->parseListExpression()
: $this->parseVariableOrMemberOptionalByReference();
}
return $children;
}
/**
* 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();
foreach ($this->parseForeachChildren() as $child) {
$foreach->addChild($child);
}
$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 builds a return statement from a given token.
*
* @return \PDepend\Source\AST\ASTReturnStatement
* @since 2.7.0
*/
protected function buildReturnStatement(Token $token)
{
$stmt = $this->builder->buildAstReturnStatement($token->image);
if (($expr = $this->parseOptionalExpression()) != null) {
$stmt->addChild($expr);
}
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();
$stmt = $this->buildReturnStatement(
$this->consumeToken(Tokens::T_RETURN)
);
$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
*/
protected 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 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 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
*/
protected function parseFullQualifiedClassNamePostfix()
{
throw $this->getUnexpectedTokenException();
}
/**
* 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 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:
return $this->parseVariableOrFunctionPostfixOrMemberPrimaryPrefix();
case Tokens::T_SELF:
return $this->parseConstantOrSelfMemberPrimaryPrefix();
case Tokens::T_PARENT:
return $this->parseConstantOrParentMemberPrimaryPrefix();
case Tokens::T_STATIC:
return $this->parseStaticVariableDeclarationOrMemberPrimaryPrefix();
case Tokens::T_STRING:
case Tokens::T_BACKSLASH:
case Tokens::T_NAMESPACE:
return $this->parseMemberPrefixOrFunctionPostfix();
}
throw $this->getUnexpectedTokenException();
}
/**
* 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)
);
}
}
/**
* 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 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 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);
/**
* Return true if [, $foo] or [$foo, , $bar] is allowed.
*
* @return bool
*/
protected function canHaveCommaBetweenArrayElements()
{
return 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)
{
$consecutiveComma = null;
$openingToken = $this->tokenizer->prevToken();
$useSquaredBrackets = ($endDelimiter === Tokens::T_SQUARED_BRACKET_CLOSE);
$this->consumeComments();
while ($endDelimiter !== $this->tokenizer->peek()) {
while ($this->canHaveCommaBetweenArrayElements() && Tokens::T_COMMA === $this->tokenizer->peek()) {
$this->consumeToken(Tokens::T_COMMA);
$this->consumeComments();
}
$array->addChild($this->parseArrayElement($static));
$this->consumeComments();
if (Tokens::T_COMMA === $this->tokenizer->peek()) {
$this->consumeToken(Tokens::T_COMMA);
$this->consumeComments();
}
if ($useSquaredBrackets && $this->isListUnpacking(Tokens::T_SQUARED_BRACKET_OPEN)) {
while (Tokens::T_COMMA === $this->tokenizer->peek()) {
$consecutiveComma = $this->tokenizer->prevToken();
$this->consumeToken(Tokens::T_COMMA);
$this->consumeComments();
}
}
}
// Once we parsed the whole array, detect if it's a destructuring list or a value,
// then check the content is consistent
$this->ensureArrayIsValid($useSquaredBrackets, $openingToken, $consecutiveComma);
return $array;
}
/**
* Check if the given array/list is a value and so does not have consecutive commas in it,
* or if it's a destructuring list and so check the syntax is valid in the current PHP level.
*
* @param bool $useSquaredBrackets
* @param Token|null $openingToken
* @param Token|null $consecutiveComma
*
* @throws UnexpectedTokenException
*
* @return void
*/
protected function ensureArrayIsValid($useSquaredBrackets, $openingToken, $consecutiveComma)
{
// If this array is followed by =, it's in fact a destructuring list
if ($this->tokenizer->peekNext() === Tokens::T_EQUAL) {
// If it uses [], check the PHP level allow it
if ($useSquaredBrackets) {
$this->ensureTokenIsListUnpackingOpening(Tokens::T_SQUARED_BRACKET_OPEN, $openingToken);
}
} elseif ($consecutiveComma) {
// If it's not a destructuring list, it must not contain 2 consecutive commas
throw $this->getUnexpectedTokenException($consecutiveComma);
}
}
/**
* 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();
throw $this->getUnexpectedTokenException(end($tokens));
}
$element->setByReference();
}
$this->consumeComments();
if ($this->isKeyword($this->tokenizer->peek())) {
throw $this->getUnexpectedTokenException();
}
$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
*/
protected 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|null
* @since 1.0.0
*/
protected function parseTypeHint()
{
switch ($this->tokenizer->peek()) {
case Tokens::T_STRING:
case Tokens::T_BACKSLASH:
case Tokens::T_NAMESPACE:
return $this->builder->buildAstClassOrInterfaceReference(
$this->parseQualifiedName()
);
}
return null;
}
/**
* 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())) {
throw $this->getUnexpectedTokenException($token);
}
throw new TokenStreamEndException($this->tokenizer);
}
/**
* Parses an optional statement or returns <b>null</b>.
*
* @return \PDepend\Source\AST\ASTNode|null
* @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_FN:
return $this->parseLambdaFunctionDeclaration();
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_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
*/
protected 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);
}
if ($this->isScalarOrCallableTypeHint($fragments[0])) {
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;
}
/**
* Determines if the given image is a PHP 7 type hint.
*
* @param string $image
* @return boolean
*/
protected function isScalarOrCallableTypeHint($image)
{
// Scalar & callable type hints were not present in PHP 5
return false;
}
/**
* @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
*/
protected 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)) {
throw $this->getUnexpectedTokenException();
}
$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
) {
return $this->setNodePositionsAndReturn(
$this->parseStaticMemberPrimaryPrefix(
$this->parseStaticReference($token)
)
);
} elseif ($tokenType === Tokens::T_FUNCTION) {
$closure = $this->parseClosureDeclaration();
$closure->setStatic(true);
return $this->setNodePositionsAndReturn($closure);
} elseif ($tokenType === Tokens::T_FN) {
$closure = $this->parseLambdaFunctionDeclaration();
$closure->setStatic(true);
return $this->setNodePositionsAndReturn($closure);
}
return $this->setNodePositionsAndReturn(
$this->parseStaticVariableDeclaration($token)
);
}
/**
* 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_ELLIPSIS:
$this->checkEllipsisInExpressionSupport();
$this->consumeToken(Tokens::T_ELLIPSIS);
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_STATIC:
case Tokens::T_SELF:
case Tokens::T_PARENT:
$node = $this->parseStandAloneExpressionTypeReference(true);
if ($this->tokenizer->peek() === Tokens::T_DOUBLE_COLON) {
$node->addChild($this->parseStaticMemberPrimaryPrefix($node));
}
$defaultValue->setValue($node);
break;
case Tokens::T_STRING:
case Tokens::T_BACKSLASH:
$node = $this->builder->buildAstClassOrInterfaceReference(
$this->parseQualifiedName()
);
if ($this->tokenizer->peek() === Tokens::T_DOUBLE_COLON) {
$node->addChild($this->parseStaticMemberPrimaryPrefix($node));
}
$defaultValue->setValue($node);
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:
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)
{
throw $this->getUnexpectedTokenException();
}
/**
* Parses fn operator of lambda function for syntax fn() => available since PHP 7.4.
*
* @return \PDepend\Source\AST\ASTValue
* @throws \PDepend\Source\Parser\UnexpectedTokenException
*/
protected function parseLambdaFunctionDeclaration()
{
throw $this->getUnexpectedTokenException();
}
/**
* 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 ASTVariable
|| $expr instanceof ASTFunctionPostfix
|| $expr instanceof ASTVariableVariable
|| $expr instanceof ASTCompoundVariable
|| $expr instanceof 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|null
*/
private function parsePackageAnnotation($comment)
{
if (getenv('DISMISS_PACKAGES')) {
$this->packageName = null;
$this->globalPackageName = null;
return null;
}
$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|null
*/
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|null
* @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)
);
}
if (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|null
* @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\ASTYieldStatement
*/
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);
}
throw $this->getUnexpectedTokenException();
}
/**
* 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);
}
}
}
/**
* @return UnexpectedTokenException
*/
protected function getUnexpectedTokenException(Token $token = null)
{
return new UnexpectedTokenException(
(null === $token) ? $this->tokenizer->next() : $token,
$this->tokenizer->getSourceFile()
);
}
/**
* 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 $this->getUnexpectedTokenException($token);
}
protected function checkEllipsisInExpressionSupport()
{
$this->throwUnexpectedTokenException();
}
}
<?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\ASTFieldDeclaration;
use PDepend\Source\AST\ASTType;
use PDepend\Source\Parser\UnexpectedTokenException;
use PDepend\Source\Tokenizer\Tokens;
/**
* Concrete parser implementation that supports features up to PHP version 7.4.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @since 2.4
*/
abstract class PHPParserVersion74 extends PHPParserVersion73
{
protected function parseUnknownDeclaration($tokenType, $modifiers)
{
/**
* Typed properties
* https://www.php.net/manual/en/migration74.new-features.php#migration74.new-features.core.typed-properties
*/
if (in_array($tokenType, array(
Tokens::T_STRING,
Tokens::T_ARRAY,
Tokens::T_QUESTION_MARK,
Tokens::T_BACKSLASH,
Tokens::T_CALLABLE,
Tokens::T_SELF,
))) {
$type = $this->parseTypeHint();
$declaration = $this->parseFieldDeclaration();
$declaration->prependChild($type);
$declaration->setModifiers($modifiers);
return $declaration;
}
return parent::parseUnknownDeclaration($tokenType, $modifiers);
}
protected function parseMethodOrFieldDeclaration($modifiers = 0)
{
$field = parent::parseMethodOrFieldDeclaration($modifiers);
if ($field instanceof ASTType) {
$type = $field;
$field = parent::parseMethodOrFieldDeclaration($modifiers);
if (!($field instanceof ASTFieldDeclaration)) {
throw new UnexpectedTokenException($this->tokenizer->prevToken(), $this->tokenizer->getSourceFile());
}
$field->prependChild($type);
}
return $field;
}
protected function parseLambdaFunctionDeclaration()
{
$this->tokenStack->push();
if (Tokens::T_FN === $this->tokenizer->peek()) {
$this->consumeToken(Tokens::T_FN);
}
$closure = $this->builder->buildAstClosure();
$closure->setReturnsByReference($this->parseOptionalByReference());
$closure->addChild($this->parseFormalParameters());
$closure = $this->parseCallableDeclarationAddition($closure);
$closure->addChild(
$this->buildReturnStatement(
$this->consumeToken(Tokens::T_DOUBLE_ARROW)
)
);
return $this->setNodePositionsAndReturn($closure);
}
/**
* Override PHP 7.3 checkEllipsisInExpressionSupport to stop throwing the
* parsing exception.
*/
protected function checkEllipsisInExpressionSupport()
{
// Do not throw the exception from parent PHP 7.3
}
}
<?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.
*
* @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_EMPTY:
case Tokens::T_EVAL:
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_ISSET:
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:
case Tokens::T_UNSET:
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_ARRAY:
$type = $this->parseArrayType();
break;
case Tokens::T_SELF:
$type = $this->parseSelfType();
break;
case Tokens::T_STRING:
case Tokens::T_BACKSLASH:
case Tokens::T_NAMESPACE:
$name = $this->parseQualifiedName();
$type = $this->isScalarOrCallableTypeHint($name)
? $this->parseScalarOrCallableTypeHint($name)
: $this->builder->buildAstClassOrInterfaceReference($name);
break;
default:
$type = parent::parseTypeHint();
break;
}
return $type;
}
/**
* Parses any expression that is surrounded by an opening and a closing
* parenthesis
*
* @return \PDepend\Source\AST\ASTExpression
*/
protected 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
);
while ($this->tokenizer->peek() === Tokens::T_PARENTHESIS_OPEN) {
$function = $this->builder->buildAstFunctionPostfix($expr->getImage());
$function->addChild($expr);
$function->addChild($this->parseArguments());
$expr = $function;
}
return $this->setNodePositionsAndReturn($expr);
}
/**
* Tests if the given image is a PHP 7 type hint.
*
* @param string $image
* @return boolean
*/
protected function isScalarOrCallableTypeHint($image)
{
switch (strtolower($image)) {
case 'int':
case 'bool':
case 'float':
case 'string':
case 'callable':
case 'iterable':
case 'void':
return true;
}
return false;
}
/**
* Parses a scalar type hint or a callable type hint.
*
* @param string $image
* @return \PDepend\Source\AST\ASTType|false
*/
protected 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();
case 'void':
case 'iterable':
throw $this->getUnexpectedTokenException($this->tokenizer->prevToken());
}
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)
{
return $this->parseAnonymousClassDeclaration($allocation)
?: 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) {
$node = count($expr->getChildren()) === 0 ? $expr : $expr->getChild(0);
return $this->parseMemberPrimaryPrefix($node);
}
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()
{
return $this->parseExpressionVersion70()
?: 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()) {
$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|null
*/
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;
}
throw $this->getUnexpectedTokenException($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
* @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\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.
*
* @var \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);
}
/**
* Builds a new code type reference instance, either Class or ClassOrInterface.
*
* @param string $qualifiedName The qualified name of the referenced type.
* @param bool $classReference true if class reference only.
*
* @return ASTClassOrInterfaceReference
* @since 0.9.5
*/
public function buildAstNeededReference($qualifiedName, $classReference)
{
if ($classReference === true) {
return $this->buildAstClassReference($qualifiedName);
}
return $this->buildAstClassOrInterfaceReference($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\ASTPrintExpression
* @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 node for the iterable type.
*
* @return \PDepend\Source\AST\ASTTypeIterable
* @since 2.5.1
*/
public function buildAstTypeIterable()
{
return $this->buildAstNodeInstance('ASTTypeIterable');
}
/**
* 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 (count($this->defaultPackage->getTypes()) === 0
&& count($this->defaultPackage->getFunctions()) === 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|null
* @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|null
* @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|null
* @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|null
* @since 0.9.5
*/
protected function findType(array $instances, $qualifiedName)
{
$classOrInterfaceName = $this->extractTypeName($qualifiedName);
$caseInsensitiveName = strtolower($classOrInterfaceName);
if (!isset($instances[$caseInsensitiveName])) {
return null;
}
$namespaceName = $this->extractNamespaceName($qualifiedName);
if ($namespaceName === null) {
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|null
*/
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 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\FullTokenizer;
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|null
* @throws \PDepend\Source\Parser\UnexpectedTokenException
*/
protected function parseStaticValueVersionSpecific(ASTValue $value)
{
$expressions = array();
while (($tokenType = $this->tokenizer->peek()) != Tokenizer::T_EOF) {
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_ELLIPSIS:
$this->checkEllipsisInExpressionSupport();
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:
case Tokens::T_COALESCE_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;
}
/**
* 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
*/
protected function parseConstantDeclaratorValue()
{
if ($this->isFollowedByStaticValueOrStaticArray()) {
return $this->parseStaticValueOrStaticArray();
}
// Else it would be provided as ASTLiteral or expressions object.
$value = new ASTValue();
$value->setValue($this->parseOptionalExpression());
return $value;
}
/**
* Determines if the following expression can be stored as a static value.
*
* @return bool
*/
protected function isFollowedByStaticValueOrStaticArray()
{
// If we can't anticipate, we should assume it can be a dynamic value
if (!($this->tokenizer instanceof FullTokenizer)) {
return false;
}
for($i = 0; $type = $this->tokenizer->peekAt($i); $i++) {
switch ($type) {
case Tokens::T_COMMENT:
case Tokens::T_DOC_COMMENT:
case Tokens::T_ARRAY:
case Tokens::T_SQUARED_BRACKET_OPEN:
case Tokens::T_SQUARED_BRACKET_CLOSE:
case Tokens::T_PARENTHESIS_OPEN:
case Tokens::T_PARENTHESIS_CLOSE:
case Tokens::T_COMMA:
case Tokens::T_DOUBLE_ARROW:
case Tokens::T_NULL:
case Tokens::T_TRUE:
case Tokens::T_FALSE:
case Tokens::T_LNUMBER:
case Tokens::T_DNUMBER:
case Tokens::T_STRING:
case Tokens::T_EQUAL:
case Tokens::T_START_HEREDOC:
case Tokens::T_END_HEREDOC:
case Tokens::T_ENCAPSED_AND_WHITESPACE:
break;
case Tokens::T_SEMICOLON:
case Tokenizer::T_EOF:
return true;
default:
return false;
}
}
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 0.9.20
*/
namespace PDepend\Source\Language\PHP;
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 PHPParserVersion74
{
/**
* Tests if the given token type is a reserved keyword in the supported PHP
* version.
*
* @param integer $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;
}
/**
* 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;
}*/
}
<?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\FullTokenizer;
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);
}
/**
* Define PHP 7.4's fn arrow function keyword
*/
if (!defined('T_FN')) {
define('T_FN', 42016);
}
/**
* Define PHP 7.4's ??= operator
*/
if (!defined('T_COALESCE_EQUAL')) {
define('T_COALESCE_EQUAL', 42017);
}
/**
* 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 FullTokenizer
{
/**
* 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_COALESCE_EQUAL => Tokens::T_COALESCE_EQUAL,
// T_DOLLAR_OPEN_CURLY_BRACES => Tokens::T_CURLY_BRACE_OPEN,
T_FN => Tokens::T_FN,
);
/**
* 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,
'yield from' => 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_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[]|null
*/
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 previous token or null if there is no one yet.
*
* @return Token|null
*/
public function prevToken()
{
$this->tokenize();
if ($this->index > 0 && $this->index < $this->count - 1) {
return $this->tokens[$this->index - 1];
}
return null;
}
/**
* Returns the current token or null if there is no more.
*
* @return Token|null
*/
public function currentToken()
{
$this->tokenize();
if ($this->index < $this->count - 1) {
return $this->tokens[$this->index];
}
return null;
}
/**
* 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 token type at the given position relatively to the current position.
*
* @param integer $shift positive or negative to apply to the current index.
* @return integer
*/
public function peekAt($shift)
{
$this->tokenize();
if ($this->index < -$shift) {
return self::T_BOF;
}
$index = $this->index + $shift;
if (isset($this->tokens[$index])) {
return $this->tokens[$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 !== null) {
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
);
$tokens = $this->substituteTokens(token_get_all($source));
// 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
* @since 2.3
*/
namespace PDepend\Source\Language\PHP;
use PDepend\Source\AST\ASTCatchStatement;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\State;
use PDepend\Source\Parser\InvalidStateException;
use PDepend\Source\Parser\UnexpectedTokenException;
use PDepend\Source\Tokenizer\Tokens;
/**
* Concrete parser implementation that supports features up to PHP version 7.1.
*
* @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 true if current PHP level supports keys in lists.
*
* @return bool
*/
protected function supportsKeysInList()
{
return true;
}
/**
* This methods return true if the token matches a list opening in the current PHP version level.
*
* @param int $tokenType
* @return bool
* @since 2.6.0
*/
protected function isListUnpacking($tokenType = null)
{
return in_array($tokenType ?: $this->tokenizer->peek(), array(Tokens::T_LIST, Tokens::T_SQUARED_BRACKET_OPEN));
}
/**
* @return \PDepend\Source\AST\ASTType
*/
protected function parseReturnTypeHint()
{
$this->consumeComments();
$this->consumeQuestionMark();
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();
$this->consumeQuestionMark();
return parent::parseFormalParameterOrTypeHintOrByReference();
}
/**
* Parses a type hint that is valid in the supported PHP version.
*
* @return \PDepend\Source\AST\ASTNode
*/
protected function parseTypeHint()
{
$this->consumeQuestionMark();
return parent::parseTypeHint();
}
/**
* Override this in later PHPParserVersions as necessary
* @param integer $tokenType
* @param integer $modifiers
* @return \PDepend\Source\AST\ASTConstantDefinition;
* @throws UnexpectedTokenException
*/
protected function parseUnknownDeclaration($tokenType, $modifiers)
{
if ($tokenType == Tokens::T_CONST) {
$definition = $this->parseConstantDefinition();
$constantModifiers = $this->getModifiersForConstantDefinition($tokenType, $modifiers);
$definition->setModifiers($constantModifiers);
return $definition;
}
return parent::parseUnknownDeclaration($tokenType, $modifiers);
}
/**
* Tests if the given image is a PHP 7 type hint.
*
* @param string $image
* @return boolean
*/
protected function isScalarOrCallableTypeHint($image)
{
switch (strtolower($image)) {
case 'iterable':
case 'void':
return true;
}
return parent::isScalarOrCallableTypeHint($image);
}
/**
* Parses a scalar type hint or a callable type hint.
*
* @param string $image
* @return \PDepend\Source\AST\ASTType
*/
protected function parseScalarOrCallableTypeHint($image)
{
switch (strtolower($image)) {
case 'void':
return $this->builder->buildAstScalarType($image);
case 'iterable':
return $this->builder->buildAstTypeIterable();
}
return parent::parseScalarOrCallableTypeHint($image);
}
/**
* This method parses class references in catch statement.
*
* @param \PDepend\Source\AST\ASTCatchStatement $stmt The owning catch statement.
*/
protected function parseCatchExceptionClass(ASTCatchStatement $stmt)
{
do {
$repeat = false;
parent::parseCatchExceptionClass($stmt);
if (Tokens::T_BITWISE_OR === $this->tokenizer->peek()) {
$this->consumeToken(Tokens::T_BITWISE_OR);
$repeat = true;
}
} while ($repeat === true);
}
/**
* Return true if [, $foo] or [$foo, , $bar] is allowed.
*
* @return bool
*/
protected function canHaveCommaBetweenArrayElements()
{
return true;
}
private function consumeQuestionMark()
{
if ($this->tokenizer->peek() === Tokens::T_QUESTION_MARK) {
$this->consumeToken(Tokens::T_QUESTION_MARK);
}
}
private function getModifiersForConstantDefinition($tokenType, $modifiers)
{
$allowed = State::IS_PUBLIC | State::IS_PROTECTED | State::IS_PRIVATE;
$modifiers &= $allowed;
if ($this->classOrInterface instanceof ASTInterface && ($modifiers & (State::IS_PROTECTED | State::IS_PRIVATE)) !== 0) {
throw new InvalidStateException(
$this->tokenizer->next()->startLine,
(string) $this->compilationUnit,
sprintf(
'Constant can\'t be declared private or protected in interface "%s".',
$this->classOrInterface->getName()
)
);
}
return $modifiers;
}
}
<?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 7.3.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @since 2.4
*/
abstract class PHPParserVersion73 extends PHPParserVersion72
{
}
<?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 7.2.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
* @since 2.4
*/
abstract class PHPParserVersion72 extends PHPParserVersion71
{
}
<?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\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\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
*/
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;
/**
* 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\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|integer
*/
public function next();
/**
* Returns the previous token or null if there is no one yet.
*
* @return \PDepend\Source\Tokenizer\Token|null
* @since 2.6.0
*/
public function prevToken();
/**
* Returns the current token or null if there is no more.
*
* @return \PDepend\Source\Tokenizer\Token|null
* @since 2.6.0
*/
public function currentToken();
/**
* 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\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;
/**
* Token that represents the 'fn' keyword of arrow functions.
*/
const T_FN = 165;
/**
* Token that represents the '??=' null coalescing assignment operator
*/
const T_COALESCE_EQUAL = 166;
/**
* Marks any content not between php tags.
*/
const T_NO_PHP = 255;
}
<?php
/**
* This file is part of 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.
*
* @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 php code tokenizers that can access any token anytime.
*
* - Are able to return previously emitted token.
* - Are able to return token from the not yet buffered string.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
interface FullTokenizer extends Tokenizer
{
/**
* Returns the token type at the given position relatively to the current position.
*
* @param integer $shift positive or negative to apply to the current index.
* @return integer
*/
public function peekAt($shift);
}
<?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
*/
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
*/
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;
/**
* 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>|null
*/
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
* @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
* @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
{
}
<?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" public="true">
<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" public="true">
<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" public="true">
<argument type="service" id="service_container" />
</service>
<service id="pdepend.configuration" class="PDepend\Util\Configuration" public="true">
</service>
<service id="pdepend.textui.result_printer" class="PDepend\TextUI\ResultPrinter" />
<service id="pdepend.report.summary.xml" class="PDepend\Report\Summary\Xml" public="true">
<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" public="true">
<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" public="true">
<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" public="true">
<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" public="true">
<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" public="true">
<argument type="service" id="service_container" />
</service>
<service id="pdepend.analyzer.class_level" class="PDepend\Metrics\Analyzer\ClassLevelAnalyzer" public="true">
<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" public="true">
<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" public="true">
<tag name="pdepend.analyzer" />
</service>
<service id="pdepend.analyzer.coupling" class="PDepend\Metrics\Analyzer\CouplingAnalyzer" public="true">
<tag name="pdepend.analyzer" />
</service>
<service id="pdepend.analyzer.crap_index" class="PDepend\Metrics\Analyzer\CrapIndexAnalyzer" public="true">
<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" public="true">
<tag name="pdepend.analyzer" />
</service>
<service id="pdepend.analyzer.dependency" class="PDepend\Metrics\Analyzer\DependencyAnalyzer" public="true">
<tag name="pdepend.analyzer" />
</service>
<service id="pdepend.analyzer.class_dependency" class="PDepend\Metrics\Analyzer\ClassDependencyAnalyzer" public="true">
<tag name="pdepend.analyzer" />
</service>
<service id="pdepend.analyzer.hierarchy" class="PDepend\Metrics\Analyzer\HierarchyAnalyzer" public="true">
<tag name="pdepend.analyzer" />
</service>
<service id="pdepend.analyzer.inheritance" class="PDepend\Metrics\Analyzer\InheritanceAnalyzer" public="true">
<tag name="pdepend.analyzer" />
</service>
<service id="pdepend.analyzer.npath_complexity" class="PDepend\Metrics\Analyzer\NPathComplexityAnalyzer" public="true">
<tag name="pdepend.analyzer" />
</service>
<service id="pdepend.analyzer.node_count" class="PDepend\Metrics\Analyzer\NodeCountAnalyzer" public="true">
<tag name="pdepend.analyzer" />
</service>
<service id="pdepend.analyzer.node_loc" class="PDepend\Metrics\Analyzer\NodeLocAnalyzer" public="true">
<tag name="pdepend.analyzer" />
</service>
<service id="pdepend.analyzer.halstead" class="PDepend\Metrics\Analyzer\HalsteadAnalyzer" public="true">
<tag name="pdepend.analyzer" />
</service>
<service id="pdepend.analyzer.maintainability" class="PDepend\Metrics\Analyzer\MaintainabilityIndexAnalyzer" public="true">
<tag name="pdepend.analyzer" />
</service>
</services>
</container>
<?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>
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'320cde22f66dd4f5d3fd621d3e88b98f' => $vendorDir . '/symfony/polyfill-ctype/bootstrap.php',
);
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit0cffd5de0edad1133a933321d7b83570
{
public static $files = array (
'320cde22f66dd4f5d3fd621d3e88b98f' => __DIR__ . '/..' . '/symfony/polyfill-ctype/bootstrap.php',
);
public static $prefixLengthsPsr4 = array (
'S' =>
array (
'Symfony\\Polyfill\\Ctype\\' => 23,
'Symfony\\Component\\Filesystem\\' => 29,
'Symfony\\Component\\DependencyInjection\\' => 38,
'Symfony\\Component\\Config\\' => 25,
),
'P' =>
array (
'Psr\\Log\\' => 8,
'PDepend\\' => 8,
),
'C' =>
array (
'Composer\\XdebugHandler\\' => 23,
),
);
public static $prefixDirsPsr4 = array (
'Symfony\\Polyfill\\Ctype\\' =>
array (
0 => __DIR__ . '/..' . '/symfony/polyfill-ctype',
),
'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',
),
'Psr\\Log\\' =>
array (
0 => __DIR__ . '/..' . '/psr/log/Psr/Log',
),
'PDepend\\' =>
array (
0 => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend',
),
'Composer\\XdebugHandler\\' =>
array (
0 => __DIR__ . '/..' . '/composer/xdebug-handler/src',
),
);
public static $prefixesPsr0 = array (
'P' =>
array (
'PHPMD\\' =>
array (
0 => __DIR__ . '/../..' . '/src/main/php',
),
),
);
public static $classMap = array (
'Composer\\XdebugHandler\\PhpConfig' => __DIR__ . '/..' . '/composer/xdebug-handler/src/PhpConfig.php',
'Composer\\XdebugHandler\\Process' => __DIR__ . '/..' . '/composer/xdebug-handler/src/Process.php',
'Composer\\XdebugHandler\\Status' => __DIR__ . '/..' . '/composer/xdebug-handler/src/Status.php',
'Composer\\XdebugHandler\\XdebugHandler' => __DIR__ . '/..' . '/composer/xdebug-handler/src/XdebugHandler.php',
'PDepend\\Application' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Application.php',
'PDepend\\DbusUI\\ResultPrinter' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/DbusUI/ResultPrinter.php',
'PDepend\\DependencyInjection\\Compiler\\ProcessListenerPass' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/Compiler/ProcessListenerPass.php',
'PDepend\\DependencyInjection\\Configuration' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/Configuration.php',
'PDepend\\DependencyInjection\\Extension' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/Extension.php',
'PDepend\\DependencyInjection\\ExtensionManager' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/ExtensionManager.php',
'PDepend\\DependencyInjection\\PdependExtension' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/PdependExtension.php',
'PDepend\\DependencyInjection\\TreeBuilder' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/TreeBuilder.php',
'PDepend\\Engine' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Engine.php',
'PDepend\\Input\\CompositeFilter' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Input/CompositeFilter.php',
'PDepend\\Input\\ExcludePathFilter' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Input/ExcludePathFilter.php',
'PDepend\\Input\\ExtensionFilter' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Input/ExtensionFilter.php',
'PDepend\\Input\\Filter' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Input/Filter.php',
'PDepend\\Input\\Iterator' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Input/Iterator.php',
'PDepend\\Metrics\\AbstractAnalyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AbstractAnalyzer.php',
'PDepend\\Metrics\\AbstractCachingAnalyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AbstractCachingAnalyzer.php',
'PDepend\\Metrics\\AggregateAnalyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AggregateAnalyzer.php',
'PDepend\\Metrics\\Analyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer.php',
'PDepend\\Metrics\\AnalyzerCacheAware' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerCacheAware.php',
'PDepend\\Metrics\\AnalyzerFactory' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerFactory.php',
'PDepend\\Metrics\\AnalyzerFilterAware' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerFilterAware.php',
'PDepend\\Metrics\\AnalyzerIterator' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerIterator.php',
'PDepend\\Metrics\\AnalyzerListener' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerListener.php',
'PDepend\\Metrics\\AnalyzerNodeAware' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerNodeAware.php',
'PDepend\\Metrics\\AnalyzerProjectAware' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerProjectAware.php',
'PDepend\\Metrics\\Analyzer\\ClassDependencyAnalyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/ClassDependencyAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\ClassLevelAnalyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/ClassLevelAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\CodeRankAnalyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\CodeRankAnalyzer\\CodeRankStrategyI' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/CodeRankStrategyI.php',
'PDepend\\Metrics\\Analyzer\\CodeRankAnalyzer\\InheritanceStrategy' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/InheritanceStrategy.php',
'PDepend\\Metrics\\Analyzer\\CodeRankAnalyzer\\MethodStrategy' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/MethodStrategy.php',
'PDepend\\Metrics\\Analyzer\\CodeRankAnalyzer\\PropertyStrategy' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/PropertyStrategy.php',
'PDepend\\Metrics\\Analyzer\\CodeRankAnalyzer\\StrategyFactory' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/StrategyFactory.php',
'PDepend\\Metrics\\Analyzer\\CohesionAnalyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CohesionAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\CouplingAnalyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CouplingAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\CrapIndexAnalyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CrapIndexAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\CyclomaticComplexityAnalyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CyclomaticComplexityAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\DependencyAnalyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/DependencyAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\HalsteadAnalyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/HalsteadAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\HierarchyAnalyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/HierarchyAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\InheritanceAnalyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/InheritanceAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\MaintainabilityIndexAnalyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/MaintainabilityIndexAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\NPathComplexityAnalyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/NPathComplexityAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\NodeCountAnalyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/NodeCountAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\NodeLocAnalyzer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/NodeLocAnalyzer.php',
'PDepend\\ProcessListener' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/ProcessListener.php',
'PDepend\\Report\\CodeAwareGenerator' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Report/CodeAwareGenerator.php',
'PDepend\\Report\\Dependencies\\Xml' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Report/Dependencies/Xml.php',
'PDepend\\Report\\FileAwareGenerator' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Report/FileAwareGenerator.php',
'PDepend\\Report\\Jdepend\\Chart' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Report/Jdepend/Chart.php',
'PDepend\\Report\\Jdepend\\Xml' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Report/Jdepend/Xml.php',
'PDepend\\Report\\NoLogOutputException' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Report/NoLogOutputException.php',
'PDepend\\Report\\Overview\\Pyramid' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Report/Overview/Pyramid.php',
'PDepend\\Report\\ReportGenerator' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Report/ReportGenerator.php',
'PDepend\\Report\\ReportGeneratorFactory' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Report/ReportGeneratorFactory.php',
'PDepend\\Report\\Summary\\Xml' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Report/Summary/Xml.php',
'PDepend\\Source\\ASTVisitor\\ASTVisitListener' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/ASTVisitor/ASTVisitListener.php',
'PDepend\\Source\\ASTVisitor\\ASTVisitor' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/ASTVisitor/ASTVisitor.php',
'PDepend\\Source\\ASTVisitor\\AbstractASTVisitListener' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/ASTVisitor/AbstractASTVisitListener.php',
'PDepend\\Source\\ASTVisitor\\AbstractASTVisitor' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/ASTVisitor/AbstractASTVisitor.php',
'PDepend\\Source\\AST\\ASTAllocationExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTAllocationExpression.php',
'PDepend\\Source\\AST\\ASTAnonymousClass' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTAnonymousClass.php',
'PDepend\\Source\\AST\\ASTArguments' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArguments.php',
'PDepend\\Source\\AST\\ASTArray' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArray.php',
'PDepend\\Source\\AST\\ASTArrayElement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArrayElement.php',
'PDepend\\Source\\AST\\ASTArrayIndexExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArrayIndexExpression.php',
'PDepend\\Source\\AST\\ASTArtifact' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifact.php',
'PDepend\\Source\\AST\\ASTArtifactList' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList.php',
'PDepend\\Source\\AST\\ASTArtifactList\\ArtifactFilter' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList/ArtifactFilter.php',
'PDepend\\Source\\AST\\ASTArtifactList\\CollectionArtifactFilter' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList/CollectionArtifactFilter.php',
'PDepend\\Source\\AST\\ASTArtifactList\\NullArtifactFilter' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList/NullArtifactFilter.php',
'PDepend\\Source\\AST\\ASTArtifactList\\PackageArtifactFilter' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList/PackageArtifactFilter.php',
'PDepend\\Source\\AST\\ASTAssignmentExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTAssignmentExpression.php',
'PDepend\\Source\\AST\\ASTBooleanAndExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTBooleanAndExpression.php',
'PDepend\\Source\\AST\\ASTBooleanOrExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTBooleanOrExpression.php',
'PDepend\\Source\\AST\\ASTBreakStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTBreakStatement.php',
'PDepend\\Source\\AST\\ASTCallable' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCallable.php',
'PDepend\\Source\\AST\\ASTCastExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCastExpression.php',
'PDepend\\Source\\AST\\ASTCatchStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCatchStatement.php',
'PDepend\\Source\\AST\\ASTClass' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClass.php',
'PDepend\\Source\\AST\\ASTClassFqnPostfix' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassFqnPostfix.php',
'PDepend\\Source\\AST\\ASTClassOrInterfaceRecursiveInheritanceException' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassOrInterfaceRecursiveInheritanceException.php',
'PDepend\\Source\\AST\\ASTClassOrInterfaceReference' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassOrInterfaceReference.php',
'PDepend\\Source\\AST\\ASTClassOrInterfaceReferenceIterator' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassOrInterfaceReferenceIterator.php',
'PDepend\\Source\\AST\\ASTClassReference' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassReference.php',
'PDepend\\Source\\AST\\ASTCloneExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCloneExpression.php',
'PDepend\\Source\\AST\\ASTClosure' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClosure.php',
'PDepend\\Source\\AST\\ASTComment' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTComment.php',
'PDepend\\Source\\AST\\ASTCompilationUnit' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCompilationUnit.php',
'PDepend\\Source\\AST\\ASTCompilationUnitNotFoundException' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCompilationUnitNotFoundException.php',
'PDepend\\Source\\AST\\ASTCompoundExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCompoundExpression.php',
'PDepend\\Source\\AST\\ASTCompoundVariable' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCompoundVariable.php',
'PDepend\\Source\\AST\\ASTConditionalExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConditionalExpression.php',
'PDepend\\Source\\AST\\ASTConstant' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConstant.php',
'PDepend\\Source\\AST\\ASTConstantDeclarator' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConstantDeclarator.php',
'PDepend\\Source\\AST\\ASTConstantDefinition' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConstantDefinition.php',
'PDepend\\Source\\AST\\ASTConstantPostfix' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConstantPostfix.php',
'PDepend\\Source\\AST\\ASTContinueStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTContinueStatement.php',
'PDepend\\Source\\AST\\ASTDeclareStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTDeclareStatement.php',
'PDepend\\Source\\AST\\ASTDoWhileStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTDoWhileStatement.php',
'PDepend\\Source\\AST\\ASTEchoStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTEchoStatement.php',
'PDepend\\Source\\AST\\ASTElseIfStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTElseIfStatement.php',
'PDepend\\Source\\AST\\ASTEvalExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTEvalExpression.php',
'PDepend\\Source\\AST\\ASTExitExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTExitExpression.php',
'PDepend\\Source\\AST\\ASTExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTExpression.php',
'PDepend\\Source\\AST\\ASTFieldDeclaration' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFieldDeclaration.php',
'PDepend\\Source\\AST\\ASTFinallyStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFinallyStatement.php',
'PDepend\\Source\\AST\\ASTForInit' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTForInit.php',
'PDepend\\Source\\AST\\ASTForStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTForStatement.php',
'PDepend\\Source\\AST\\ASTForUpdate' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTForUpdate.php',
'PDepend\\Source\\AST\\ASTForeachStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTForeachStatement.php',
'PDepend\\Source\\AST\\ASTFormalParameter' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFormalParameter.php',
'PDepend\\Source\\AST\\ASTFormalParameters' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFormalParameters.php',
'PDepend\\Source\\AST\\ASTFunction' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFunction.php',
'PDepend\\Source\\AST\\ASTFunctionPostfix' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFunctionPostfix.php',
'PDepend\\Source\\AST\\ASTGlobalStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTGlobalStatement.php',
'PDepend\\Source\\AST\\ASTGotoStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTGotoStatement.php',
'PDepend\\Source\\AST\\ASTHeredoc' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTHeredoc.php',
'PDepend\\Source\\AST\\ASTIdentifier' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIdentifier.php',
'PDepend\\Source\\AST\\ASTIfStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIfStatement.php',
'PDepend\\Source\\AST\\ASTIncludeExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIncludeExpression.php',
'PDepend\\Source\\AST\\ASTIndexExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIndexExpression.php',
'PDepend\\Source\\AST\\ASTInstanceOfExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTInstanceOfExpression.php',
'PDepend\\Source\\AST\\ASTInterface' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTInterface.php',
'PDepend\\Source\\AST\\ASTInvocation' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTInvocation.php',
'PDepend\\Source\\AST\\ASTIssetExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIssetExpression.php',
'PDepend\\Source\\AST\\ASTLabelStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLabelStatement.php',
'PDepend\\Source\\AST\\ASTListExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTListExpression.php',
'PDepend\\Source\\AST\\ASTLiteral' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLiteral.php',
'PDepend\\Source\\AST\\ASTLogicalAndExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLogicalAndExpression.php',
'PDepend\\Source\\AST\\ASTLogicalOrExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLogicalOrExpression.php',
'PDepend\\Source\\AST\\ASTLogicalXorExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLogicalXorExpression.php',
'PDepend\\Source\\AST\\ASTMemberPrimaryPrefix' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTMemberPrimaryPrefix.php',
'PDepend\\Source\\AST\\ASTMethod' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTMethod.php',
'PDepend\\Source\\AST\\ASTMethodPostfix' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTMethodPostfix.php',
'PDepend\\Source\\AST\\ASTNamespace' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTNamespace.php',
'PDepend\\Source\\AST\\ASTNode' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTNode.php',
'PDepend\\Source\\AST\\ASTParameter' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTParameter.php',
'PDepend\\Source\\AST\\ASTParentReference' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTParentReference.php',
'PDepend\\Source\\AST\\ASTPostfixExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPostfixExpression.php',
'PDepend\\Source\\AST\\ASTPreDecrementExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPreDecrementExpression.php',
'PDepend\\Source\\AST\\ASTPreIncrementExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPreIncrementExpression.php',
'PDepend\\Source\\AST\\ASTPrintExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPrintExpression.php',
'PDepend\\Source\\AST\\ASTProperty' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTProperty.php',
'PDepend\\Source\\AST\\ASTPropertyPostfix' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPropertyPostfix.php',
'PDepend\\Source\\AST\\ASTRequireExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTRequireExpression.php',
'PDepend\\Source\\AST\\ASTReturnStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTReturnStatement.php',
'PDepend\\Source\\AST\\ASTScalarType' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTScalarType.php',
'PDepend\\Source\\AST\\ASTScope' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTScope.php',
'PDepend\\Source\\AST\\ASTScopeStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTScopeStatement.php',
'PDepend\\Source\\AST\\ASTSelfReference' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTSelfReference.php',
'PDepend\\Source\\AST\\ASTShiftLeftExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTShiftLeftExpression.php',
'PDepend\\Source\\AST\\ASTShiftRightExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTShiftRightExpression.php',
'PDepend\\Source\\AST\\ASTStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTStatement.php',
'PDepend\\Source\\AST\\ASTStaticReference' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTStaticReference.php',
'PDepend\\Source\\AST\\ASTStaticVariableDeclaration' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTStaticVariableDeclaration.php',
'PDepend\\Source\\AST\\ASTString' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTString.php',
'PDepend\\Source\\AST\\ASTStringIndexExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTStringIndexExpression.php',
'PDepend\\Source\\AST\\ASTSwitchLabel' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTSwitchLabel.php',
'PDepend\\Source\\AST\\ASTSwitchStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTSwitchStatement.php',
'PDepend\\Source\\AST\\ASTThrowStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTThrowStatement.php',
'PDepend\\Source\\AST\\ASTTrait' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTrait.php',
'PDepend\\Source\\AST\\ASTTraitAdaptation' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitAdaptation.php',
'PDepend\\Source\\AST\\ASTTraitAdaptationAlias' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitAdaptationAlias.php',
'PDepend\\Source\\AST\\ASTTraitAdaptationPrecedence' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitAdaptationPrecedence.php',
'PDepend\\Source\\AST\\ASTTraitMethodCollisionException' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitMethodCollisionException.php',
'PDepend\\Source\\AST\\ASTTraitReference' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitReference.php',
'PDepend\\Source\\AST\\ASTTraitUseStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitUseStatement.php',
'PDepend\\Source\\AST\\ASTTryStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTryStatement.php',
'PDepend\\Source\\AST\\ASTType' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTType.php',
'PDepend\\Source\\AST\\ASTTypeArray' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTypeArray.php',
'PDepend\\Source\\AST\\ASTTypeCallable' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTypeCallable.php',
'PDepend\\Source\\AST\\ASTTypeIterable' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTypeIterable.php',
'PDepend\\Source\\AST\\ASTUnaryExpression' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTUnaryExpression.php',
'PDepend\\Source\\AST\\ASTUnsetStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTUnsetStatement.php',
'PDepend\\Source\\AST\\ASTValue' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTValue.php',
'PDepend\\Source\\AST\\ASTVariable' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTVariable.php',
'PDepend\\Source\\AST\\ASTVariableDeclarator' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTVariableDeclarator.php',
'PDepend\\Source\\AST\\ASTVariableVariable' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTVariableVariable.php',
'PDepend\\Source\\AST\\ASTWhileStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTWhileStatement.php',
'PDepend\\Source\\AST\\ASTYieldStatement' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTYieldStatement.php',
'PDepend\\Source\\AST\\AbstractASTArtifact' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTArtifact.php',
'PDepend\\Source\\AST\\AbstractASTCallable' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTCallable.php',
'PDepend\\Source\\AST\\AbstractASTClassOrInterface' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTClassOrInterface.php',
'PDepend\\Source\\AST\\AbstractASTNode' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTNode.php',
'PDepend\\Source\\AST\\AbstractASTType' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTType.php',
'PDepend\\Source\\AST\\State' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/State.php',
'PDepend\\Source\\Builder\\Builder' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Builder/Builder.php',
'PDepend\\Source\\Builder\\BuilderContext' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Builder/BuilderContext.php',
'PDepend\\Source\\Builder\\BuilderContext\\GlobalBuilderContext' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Builder/BuilderContext/GlobalBuilderContext.php',
'PDepend\\Source\\Language\\PHP\\AbstractPHPParser' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/AbstractPHPParser.php',
'PDepend\\Source\\Language\\PHP\\PHPBuilder' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPBuilder.php',
'PDepend\\Source\\Language\\PHP\\PHPParserGeneric' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserGeneric.php',
'PDepend\\Source\\Language\\PHP\\PHPParserVersion53' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion53.php',
'PDepend\\Source\\Language\\PHP\\PHPParserVersion54' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion54.php',
'PDepend\\Source\\Language\\PHP\\PHPParserVersion55' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion55.php',
'PDepend\\Source\\Language\\PHP\\PHPParserVersion56' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion56.php',
'PDepend\\Source\\Language\\PHP\\PHPParserVersion70' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion70.php',
'PDepend\\Source\\Language\\PHP\\PHPParserVersion71' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion71.php',
'PDepend\\Source\\Language\\PHP\\PHPParserVersion72' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion72.php',
'PDepend\\Source\\Language\\PHP\\PHPParserVersion73' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion73.php',
'PDepend\\Source\\Language\\PHP\\PHPParserVersion74' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion74.php',
'PDepend\\Source\\Language\\PHP\\PHPTokenizerInternal' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPTokenizerInternal.php',
'PDepend\\Source\\Parser\\InvalidStateException' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Parser/InvalidStateException.php',
'PDepend\\Source\\Parser\\MissingValueException' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Parser/MissingValueException.php',
'PDepend\\Source\\Parser\\NoActiveScopeException' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Parser/NoActiveScopeException.php',
'PDepend\\Source\\Parser\\ParserException' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Parser/ParserException.php',
'PDepend\\Source\\Parser\\SymbolTable' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Parser/SymbolTable.php',
'PDepend\\Source\\Parser\\TokenException' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Parser/TokenException.php',
'PDepend\\Source\\Parser\\TokenStack' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Parser/TokenStack.php',
'PDepend\\Source\\Parser\\TokenStreamEndException' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Parser/TokenStreamEndException.php',
'PDepend\\Source\\Parser\\UnexpectedTokenException' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Parser/UnexpectedTokenException.php',
'PDepend\\Source\\Tokenizer\\FullTokenizer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Tokenizer/FullTokenizer.php',
'PDepend\\Source\\Tokenizer\\Token' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Tokenizer/Token.php',
'PDepend\\Source\\Tokenizer\\Tokenizer' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Tokenizer/Tokenizer.php',
'PDepend\\Source\\Tokenizer\\Tokens' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Source/Tokenizer/Tokens.php',
'PDepend\\TextUI\\Command' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/TextUI/Command.php',
'PDepend\\TextUI\\ResultPrinter' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/TextUI/ResultPrinter.php',
'PDepend\\TextUI\\Runner' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/TextUI/Runner.php',
'PDepend\\Util\\Cache\\CacheDriver' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/Cache/CacheDriver.php',
'PDepend\\Util\\Cache\\CacheFactory' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/Cache/CacheFactory.php',
'PDepend\\Util\\Cache\\Driver\\FileCacheDriver' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/Cache/Driver/FileCacheDriver.php',
'PDepend\\Util\\Cache\\Driver\\File\\FileCacheDirectory' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/Cache/Driver/File/FileCacheDirectory.php',
'PDepend\\Util\\Cache\\Driver\\File\\FileCacheGarbageCollector' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/Cache/Driver/File/FileCacheGarbageCollector.php',
'PDepend\\Util\\Cache\\Driver\\MemoryCacheDriver' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/Cache/Driver/MemoryCacheDriver.php',
'PDepend\\Util\\Configuration' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/Configuration.php',
'PDepend\\Util\\ConfigurationInstance' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/ConfigurationInstance.php',
'PDepend\\Util\\Coverage\\CloverReport' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/Coverage/CloverReport.php',
'PDepend\\Util\\Coverage\\Factory' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/Coverage/Factory.php',
'PDepend\\Util\\Coverage\\Report' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/Coverage/Report.php',
'PDepend\\Util\\FileUtil' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/FileUtil.php',
'PDepend\\Util\\IdBuilder' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/IdBuilder.php',
'PDepend\\Util\\ImageConvert' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/ImageConvert.php',
'PDepend\\Util\\Log' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/Log.php',
'PDepend\\Util\\MathUtil' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/MathUtil.php',
'PDepend\\Util\\Type' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/Type.php',
'PDepend\\Util\\Utf8Util' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/Utf8Util.php',
'PDepend\\Util\\Workarounds' => __DIR__ . '/..' . '/pdepend/pdepend/src/main/php/PDepend/Util/Workarounds.php',
'PHPMD\\AbstractNode' => __DIR__ . '/../..' . '/src/main/php/PHPMD/AbstractNode.php',
'PHPMD\\AbstractRenderer' => __DIR__ . '/../..' . '/src/main/php/PHPMD/AbstractRenderer.php',
'PHPMD\\AbstractRule' => __DIR__ . '/../..' . '/src/main/php/PHPMD/AbstractRule.php',
'PHPMD\\AbstractWriter' => __DIR__ . '/../..' . '/src/main/php/PHPMD/AbstractWriter.php',
'PHPMD\\Exception\\RuleClassFileNotFoundException' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Exception/RuleClassFileNotFoundException.php',
'PHPMD\\Exception\\RuleClassNotFoundException' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Exception/RuleClassNotFoundException.php',
'PHPMD\\Exception\\RuleSetNotFoundException' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Exception/RuleSetNotFoundException.php',
'PHPMD\\Node\\ASTNode' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Node/ASTNode.php',
'PHPMD\\Node\\AbstractCallableNode' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Node/AbstractCallableNode.php',
'PHPMD\\Node\\AbstractNode' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Node/AbstractNode.php',
'PHPMD\\Node\\AbstractTypeNode' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Node/AbstractTypeNode.php',
'PHPMD\\Node\\Annotation' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Node/Annotation.php',
'PHPMD\\Node\\Annotations' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Node/Annotations.php',
'PHPMD\\Node\\ClassNode' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Node/ClassNode.php',
'PHPMD\\Node\\FunctionNode' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Node/FunctionNode.php',
'PHPMD\\Node\\InterfaceNode' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Node/InterfaceNode.php',
'PHPMD\\Node\\MethodNode' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Node/MethodNode.php',
'PHPMD\\Node\\TraitNode' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Node/TraitNode.php',
'PHPMD\\PHPMD' => __DIR__ . '/../..' . '/src/main/php/PHPMD/PHPMD.php',
'PHPMD\\Parser' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Parser.php',
'PHPMD\\ParserFactory' => __DIR__ . '/../..' . '/src/main/php/PHPMD/ParserFactory.php',
'PHPMD\\ProcessingError' => __DIR__ . '/../..' . '/src/main/php/PHPMD/ProcessingError.php',
'PHPMD\\Renderer\\AnsiRenderer' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Renderer/AnsiRenderer.php',
'PHPMD\\Renderer\\HTMLRenderer' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Renderer/HTMLRenderer.php',
'PHPMD\\Renderer\\JSONRenderer' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Renderer/JSONRenderer.php',
'PHPMD\\Renderer\\TextRenderer' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Renderer/TextRenderer.php',
'PHPMD\\Renderer\\XMLRenderer' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Renderer/XMLRenderer.php',
'PHPMD\\Report' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Report.php',
'PHPMD\\Rule' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule.php',
'PHPMD\\RuleSet' => __DIR__ . '/../..' . '/src/main/php/PHPMD/RuleSet.php',
'PHPMD\\RuleSetFactory' => __DIR__ . '/../..' . '/src/main/php/PHPMD/RuleSetFactory.php',
'PHPMD\\RuleViolation' => __DIR__ . '/../..' . '/src/main/php/PHPMD/RuleViolation.php',
'PHPMD\\Rule\\AbstractLocalVariable' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/AbstractLocalVariable.php',
'PHPMD\\Rule\\ClassAware' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/ClassAware.php',
'PHPMD\\Rule\\CleanCode\\BooleanArgumentFlag' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/CleanCode/BooleanArgumentFlag.php',
'PHPMD\\Rule\\CleanCode\\DuplicatedArrayKey' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/CleanCode/DuplicatedArrayKey.php',
'PHPMD\\Rule\\CleanCode\\ElseExpression' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/CleanCode/ElseExpression.php',
'PHPMD\\Rule\\CleanCode\\ErrorControlOperator' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/CleanCode/ErrorControlOperator.php',
'PHPMD\\Rule\\CleanCode\\IfStatementAssignment' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/CleanCode/IfStatementAssignment.php',
'PHPMD\\Rule\\CleanCode\\MissingImport' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/CleanCode/MissingImport.php',
'PHPMD\\Rule\\CleanCode\\StaticAccess' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/CleanCode/StaticAccess.php',
'PHPMD\\Rule\\CleanCode\\UndefinedVariable' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/CleanCode/UndefinedVariable.php',
'PHPMD\\Rule\\Controversial\\CamelCaseClassName' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Controversial/CamelCaseClassName.php',
'PHPMD\\Rule\\Controversial\\CamelCaseMethodName' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Controversial/CamelCaseMethodName.php',
'PHPMD\\Rule\\Controversial\\CamelCaseParameterName' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Controversial/CamelCaseParameterName.php',
'PHPMD\\Rule\\Controversial\\CamelCasePropertyName' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Controversial/CamelCasePropertyName.php',
'PHPMD\\Rule\\Controversial\\CamelCaseVariableName' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Controversial/CamelCaseVariableName.php',
'PHPMD\\Rule\\Controversial\\Superglobals' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Controversial/Superglobals.php',
'PHPMD\\Rule\\CyclomaticComplexity' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/CyclomaticComplexity.php',
'PHPMD\\Rule\\Design\\CountInLoopExpression' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Design/CountInLoopExpression.php',
'PHPMD\\Rule\\Design\\CouplingBetweenObjects' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Design/CouplingBetweenObjects.php',
'PHPMD\\Rule\\Design\\DepthOfInheritance' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Design/DepthOfInheritance.php',
'PHPMD\\Rule\\Design\\DevelopmentCodeFragment' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Design/DevelopmentCodeFragment.php',
'PHPMD\\Rule\\Design\\EmptyCatchBlock' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Design/EmptyCatchBlock.php',
'PHPMD\\Rule\\Design\\EvalExpression' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Design/EvalExpression.php',
'PHPMD\\Rule\\Design\\ExitExpression' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Design/ExitExpression.php',
'PHPMD\\Rule\\Design\\GotoStatement' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Design/GotoStatement.php',
'PHPMD\\Rule\\Design\\LongClass' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Design/LongClass.php',
'PHPMD\\Rule\\Design\\LongMethod' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Design/LongMethod.php',
'PHPMD\\Rule\\Design\\LongParameterList' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Design/LongParameterList.php',
'PHPMD\\Rule\\Design\\NpathComplexity' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Design/NpathComplexity.php',
'PHPMD\\Rule\\Design\\NumberOfChildren' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Design/NumberOfChildren.php',
'PHPMD\\Rule\\Design\\TooManyFields' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Design/TooManyFields.php',
'PHPMD\\Rule\\Design\\TooManyMethods' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Design/TooManyMethods.php',
'PHPMD\\Rule\\Design\\TooManyPublicMethods' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Design/TooManyPublicMethods.php',
'PHPMD\\Rule\\Design\\WeightedMethodCount' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Design/WeightedMethodCount.php',
'PHPMD\\Rule\\ExcessivePublicCount' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/ExcessivePublicCount.php',
'PHPMD\\Rule\\FunctionAware' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/FunctionAware.php',
'PHPMD\\Rule\\InterfaceAware' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/InterfaceAware.php',
'PHPMD\\Rule\\MethodAware' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/MethodAware.php',
'PHPMD\\Rule\\Naming\\BooleanGetMethodName' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Naming/BooleanGetMethodName.php',
'PHPMD\\Rule\\Naming\\ConstantNamingConventions' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Naming/ConstantNamingConventions.php',
'PHPMD\\Rule\\Naming\\ConstructorWithNameAsEnclosingClass' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Naming/ConstructorWithNameAsEnclosingClass.php',
'PHPMD\\Rule\\Naming\\LongClassName' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Naming/LongClassName.php',
'PHPMD\\Rule\\Naming\\LongVariable' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Naming/LongVariable.php',
'PHPMD\\Rule\\Naming\\ShortClassName' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Naming/ShortClassName.php',
'PHPMD\\Rule\\Naming\\ShortMethodName' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Naming/ShortMethodName.php',
'PHPMD\\Rule\\Naming\\ShortVariable' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/Naming/ShortVariable.php',
'PHPMD\\Rule\\UnusedFormalParameter' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/UnusedFormalParameter.php',
'PHPMD\\Rule\\UnusedLocalVariable' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/UnusedLocalVariable.php',
'PHPMD\\Rule\\UnusedPrivateField' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/UnusedPrivateField.php',
'PHPMD\\Rule\\UnusedPrivateMethod' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Rule/UnusedPrivateMethod.php',
'PHPMD\\TextUI\\Command' => __DIR__ . '/../..' . '/src/main/php/PHPMD/TextUI/Command.php',
'PHPMD\\TextUI\\CommandLineOptions' => __DIR__ . '/../..' . '/src/main/php/PHPMD/TextUI/CommandLineOptions.php',
'PHPMD\\Utility\\Strings' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Utility/Strings.php',
'PHPMD\\Writer\\StreamWriter' => __DIR__ . '/../..' . '/src/main/php/PHPMD/Writer/StreamWriter.php',
'Psr\\Log\\AbstractLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/AbstractLogger.php',
'Psr\\Log\\InvalidArgumentException' => __DIR__ . '/..' . '/psr/log/Psr/Log/InvalidArgumentException.php',
'Psr\\Log\\LogLevel' => __DIR__ . '/..' . '/psr/log/Psr/Log/LogLevel.php',
'Psr\\Log\\LoggerAwareInterface' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerAwareInterface.php',
'Psr\\Log\\LoggerAwareTrait' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerAwareTrait.php',
'Psr\\Log\\LoggerInterface' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerInterface.php',
'Psr\\Log\\LoggerTrait' => __DIR__ . '/..' . '/psr/log/Psr/Log/LoggerTrait.php',
'Psr\\Log\\NullLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/NullLogger.php',
'Psr\\Log\\Test\\DummyTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/DummyTest.php',
'Psr\\Log\\Test\\LoggerInterfaceTest' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php',
'Psr\\Log\\Test\\TestLogger' => __DIR__ . '/..' . '/psr/log/Psr/Log/Test/TestLogger.php',
'Symfony\\Component\\Config\\ConfigCache' => __DIR__ . '/..' . '/symfony/config/ConfigCache.php',
'Symfony\\Component\\Config\\ConfigCacheFactory' => __DIR__ . '/..' . '/symfony/config/ConfigCacheFactory.php',
'Symfony\\Component\\Config\\ConfigCacheFactoryInterface' => __DIR__ . '/..' . '/symfony/config/ConfigCacheFactoryInterface.php',
'Symfony\\Component\\Config\\ConfigCacheInterface' => __DIR__ . '/..' . '/symfony/config/ConfigCacheInterface.php',
'Symfony\\Component\\Config\\Definition\\ArrayNode' => __DIR__ . '/..' . '/symfony/config/Definition/ArrayNode.php',
'Symfony\\Component\\Config\\Definition\\BaseNode' => __DIR__ . '/..' . '/symfony/config/Definition/BaseNode.php',
'Symfony\\Component\\Config\\Definition\\BooleanNode' => __DIR__ . '/..' . '/symfony/config/Definition/BooleanNode.php',
'Symfony\\Component\\Config\\Definition\\Builder\\ArrayNodeDefinition' => __DIR__ . '/..' . '/symfony/config/Definition/Builder/ArrayNodeDefinition.php',
'Symfony\\Component\\Config\\Definition\\Builder\\BooleanNodeDefinition' => __DIR__ . '/..' . '/symfony/config/Definition/Builder/BooleanNodeDefinition.php',
'Symfony\\Component\\Config\\Definition\\Builder\\EnumNodeDefinition' => __DIR__ . '/..' . '/symfony/config/Definition/Builder/EnumNodeDefinition.php',
'Symfony\\Component\\Config\\Definition\\Builder\\ExprBuilder' => __DIR__ . '/..' . '/symfony/config/Definition/Builder/ExprBuilder.php',
'Symfony\\Component\\Config\\Definition\\Builder\\FloatNodeDefinition' => __DIR__ . '/..' . '/symfony/config/Definition/Builder/FloatNodeDefinition.php',
'Symfony\\Component\\Config\\Definition\\Builder\\IntegerNodeDefinition' => __DIR__ . '/..' . '/symfony/config/Definition/Builder/IntegerNodeDefinition.php',
'Symfony\\Component\\Config\\Definition\\Builder\\MergeBuilder' => __DIR__ . '/..' . '/symfony/config/Definition/Builder/MergeBuilder.php',
'Symfony\\Component\\Config\\Definition\\Builder\\NodeBuilder' => __DIR__ . '/..' . '/symfony/config/Definition/Builder/NodeBuilder.php',
'Symfony\\Component\\Config\\Definition\\Builder\\NodeDefinition' => __DIR__ . '/..' . '/symfony/config/Definition/Builder/NodeDefinition.php',
'Symfony\\Component\\Config\\Definition\\Builder\\NodeParentInterface' => __DIR__ . '/..' . '/symfony/config/Definition/Builder/NodeParentInterface.php',
'Symfony\\Component\\Config\\Definition\\Builder\\NormalizationBuilder' => __DIR__ . '/..' . '/symfony/config/Definition/Builder/NormalizationBuilder.php',
'Symfony\\Component\\Config\\Definition\\Builder\\NumericNodeDefinition' => __DIR__ . '/..' . '/symfony/config/Definition/Builder/NumericNodeDefinition.php',
'Symfony\\Component\\Config\\Definition\\Builder\\ParentNodeDefinitionInterface' => __DIR__ . '/..' . '/symfony/config/Definition/Builder/ParentNodeDefinitionInterface.php',
'Symfony\\Component\\Config\\Definition\\Builder\\ScalarNodeDefinition' => __DIR__ . '/..' . '/symfony/config/Definition/Builder/ScalarNodeDefinition.php',
'Symfony\\Component\\Config\\Definition\\Builder\\TreeBuilder' => __DIR__ . '/..' . '/symfony/config/Definition/Builder/TreeBuilder.php',
'Symfony\\Component\\Config\\Definition\\Builder\\ValidationBuilder' => __DIR__ . '/..' . '/symfony/config/Definition/Builder/ValidationBuilder.php',
'Symfony\\Component\\Config\\Definition\\Builder\\VariableNodeDefinition' => __DIR__ . '/..' . '/symfony/config/Definition/Builder/VariableNodeDefinition.php',
'Symfony\\Component\\Config\\Definition\\ConfigurationInterface' => __DIR__ . '/..' . '/symfony/config/Definition/ConfigurationInterface.php',
'Symfony\\Component\\Config\\Definition\\Dumper\\XmlReferenceDumper' => __DIR__ . '/..' . '/symfony/config/Definition/Dumper/XmlReferenceDumper.php',
'Symfony\\Component\\Config\\Definition\\Dumper\\YamlReferenceDumper' => __DIR__ . '/..' . '/symfony/config/Definition/Dumper/YamlReferenceDumper.php',
'Symfony\\Component\\Config\\Definition\\EnumNode' => __DIR__ . '/..' . '/symfony/config/Definition/EnumNode.php',
'Symfony\\Component\\Config\\Definition\\Exception\\DuplicateKeyException' => __DIR__ . '/..' . '/symfony/config/Definition/Exception/DuplicateKeyException.php',
'Symfony\\Component\\Config\\Definition\\Exception\\Exception' => __DIR__ . '/..' . '/symfony/config/Definition/Exception/Exception.php',
'Symfony\\Component\\Config\\Definition\\Exception\\ForbiddenOverwriteException' => __DIR__ . '/..' . '/symfony/config/Definition/Exception/ForbiddenOverwriteException.php',
'Symfony\\Component\\Config\\Definition\\Exception\\InvalidConfigurationException' => __DIR__ . '/..' . '/symfony/config/Definition/Exception/InvalidConfigurationException.php',
'Symfony\\Component\\Config\\Definition\\Exception\\InvalidDefinitionException' => __DIR__ . '/..' . '/symfony/config/Definition/Exception/InvalidDefinitionException.php',
'Symfony\\Component\\Config\\Definition\\Exception\\InvalidTypeException' => __DIR__ . '/..' . '/symfony/config/Definition/Exception/InvalidTypeException.php',
'Symfony\\Component\\Config\\Definition\\Exception\\UnsetKeyException' => __DIR__ . '/..' . '/symfony/config/Definition/Exception/UnsetKeyException.php',
'Symfony\\Component\\Config\\Definition\\FloatNode' => __DIR__ . '/..' . '/symfony/config/Definition/FloatNode.php',
'Symfony\\Component\\Config\\Definition\\IntegerNode' => __DIR__ . '/..' . '/symfony/config/Definition/IntegerNode.php',
'Symfony\\Component\\Config\\Definition\\NodeInterface' => __DIR__ . '/..' . '/symfony/config/Definition/NodeInterface.php',
'Symfony\\Component\\Config\\Definition\\NumericNode' => __DIR__ . '/..' . '/symfony/config/Definition/NumericNode.php',
'Symfony\\Component\\Config\\Definition\\Processor' => __DIR__ . '/..' . '/symfony/config/Definition/Processor.php',
'Symfony\\Component\\Config\\Definition\\PrototypeNodeInterface' => __DIR__ . '/..' . '/symfony/config/Definition/PrototypeNodeInterface.php',
'Symfony\\Component\\Config\\Definition\\PrototypedArrayNode' => __DIR__ . '/..' . '/symfony/config/Definition/PrototypedArrayNode.php',
'Symfony\\Component\\Config\\Definition\\ReferenceDumper' => __DIR__ . '/..' . '/symfony/config/Definition/ReferenceDumper.php',
'Symfony\\Component\\Config\\Definition\\ScalarNode' => __DIR__ . '/..' . '/symfony/config/Definition/ScalarNode.php',
'Symfony\\Component\\Config\\Definition\\VariableNode' => __DIR__ . '/..' . '/symfony/config/Definition/VariableNode.php',
'Symfony\\Component\\Config\\Exception\\FileLoaderImportCircularReferenceException' => __DIR__ . '/..' . '/symfony/config/Exception/FileLoaderImportCircularReferenceException.php',
'Symfony\\Component\\Config\\Exception\\FileLoaderLoadException' => __DIR__ . '/..' . '/symfony/config/Exception/FileLoaderLoadException.php',
'Symfony\\Component\\Config\\FileLocator' => __DIR__ . '/..' . '/symfony/config/FileLocator.php',
'Symfony\\Component\\Config\\FileLocatorInterface' => __DIR__ . '/..' . '/symfony/config/FileLocatorInterface.php',
'Symfony\\Component\\Config\\Loader\\DelegatingLoader' => __DIR__ . '/..' . '/symfony/config/Loader/DelegatingLoader.php',
'Symfony\\Component\\Config\\Loader\\FileLoader' => __DIR__ . '/..' . '/symfony/config/Loader/FileLoader.php',
'Symfony\\Component\\Config\\Loader\\Loader' => __DIR__ . '/..' . '/symfony/config/Loader/Loader.php',
'Symfony\\Component\\Config\\Loader\\LoaderInterface' => __DIR__ . '/..' . '/symfony/config/Loader/LoaderInterface.php',
'Symfony\\Component\\Config\\Loader\\LoaderResolver' => __DIR__ . '/..' . '/symfony/config/Loader/LoaderResolver.php',
'Symfony\\Component\\Config\\Loader\\LoaderResolverInterface' => __DIR__ . '/..' . '/symfony/config/Loader/LoaderResolverInterface.php',
'Symfony\\Component\\Config\\ResourceCheckerConfigCache' => __DIR__ . '/..' . '/symfony/config/ResourceCheckerConfigCache.php',
'Symfony\\Component\\Config\\ResourceCheckerConfigCacheFactory' => __DIR__ . '/..' . '/symfony/config/ResourceCheckerConfigCacheFactory.php',
'Symfony\\Component\\Config\\ResourceCheckerInterface' => __DIR__ . '/..' . '/symfony/config/ResourceCheckerInterface.php',
'Symfony\\Component\\Config\\Resource\\BCResourceInterfaceChecker' => __DIR__ . '/..' . '/symfony/config/Resource/BCResourceInterfaceChecker.php',
'Symfony\\Component\\Config\\Resource\\DirectoryResource' => __DIR__ . '/..' . '/symfony/config/Resource/DirectoryResource.php',
'Symfony\\Component\\Config\\Resource\\FileExistenceResource' => __DIR__ . '/..' . '/symfony/config/Resource/FileExistenceResource.php',
'Symfony\\Component\\Config\\Resource\\FileResource' => __DIR__ . '/..' . '/symfony/config/Resource/FileResource.php',
'Symfony\\Component\\Config\\Resource\\ResourceInterface' => __DIR__ . '/..' . '/symfony/config/Resource/ResourceInterface.php',
'Symfony\\Component\\Config\\Resource\\SelfCheckingResourceChecker' => __DIR__ . '/..' . '/symfony/config/Resource/SelfCheckingResourceChecker.php',
'Symfony\\Component\\Config\\Resource\\SelfCheckingResourceInterface' => __DIR__ . '/..' . '/symfony/config/Resource/SelfCheckingResourceInterface.php',
'Symfony\\Component\\Config\\Util\\XmlUtils' => __DIR__ . '/..' . '/symfony/config/Util/XmlUtils.php',
'Symfony\\Component\\DependencyInjection\\Alias' => __DIR__ . '/..' . '/symfony/dependency-injection/Alias.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\AnalyzeServiceReferencesPass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/AnalyzeServiceReferencesPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\AutoAliasServicePass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/AutoAliasServicePass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\AutowirePass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/AutowirePass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\CheckCircularReferencesPass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/CheckCircularReferencesPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\CheckDefinitionValidityPass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/CheckDefinitionValidityPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\CheckExceptionOnInvalidReferenceBehaviorPass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\CheckReferenceValidityPass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/CheckReferenceValidityPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\Compiler' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/Compiler.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/CompilerPassInterface.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\DecoratorServicePass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/DecoratorServicePass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\ExtensionCompilerPass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/ExtensionCompilerPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\InlineServiceDefinitionsPass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/InlineServiceDefinitionsPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\LoggingFormatter' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/LoggingFormatter.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\MergeExtensionConfigurationPass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/MergeExtensionConfigurationPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\PassConfig' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/PassConfig.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\RemoveAbstractDefinitionsPass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/RemoveAbstractDefinitionsPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\RemovePrivateAliasesPass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/RemovePrivateAliasesPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\RemoveUnusedDefinitionsPass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/RemoveUnusedDefinitionsPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\RepeatablePassInterface' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/RepeatablePassInterface.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\RepeatedPass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/RepeatedPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\ReplaceAliasByActualDefinitionPass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/ReplaceAliasByActualDefinitionPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\ResolveDefinitionTemplatesPass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/ResolveDefinitionTemplatesPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\ResolveInvalidReferencesPass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/ResolveInvalidReferencesPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\ResolveParameterPlaceHoldersPass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/ResolveParameterPlaceHoldersPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\ResolveReferencesToAliasesPass' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/ResolveReferencesToAliasesPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\ServiceReferenceGraph' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/ServiceReferenceGraph.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\ServiceReferenceGraphEdge' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/ServiceReferenceGraphEdge.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\ServiceReferenceGraphNode' => __DIR__ . '/..' . '/symfony/dependency-injection/Compiler/ServiceReferenceGraphNode.php',
'Symfony\\Component\\DependencyInjection\\Container' => __DIR__ . '/..' . '/symfony/dependency-injection/Container.php',
'Symfony\\Component\\DependencyInjection\\ContainerAware' => __DIR__ . '/..' . '/symfony/dependency-injection/ContainerAware.php',
'Symfony\\Component\\DependencyInjection\\ContainerAwareInterface' => __DIR__ . '/..' . '/symfony/dependency-injection/ContainerAwareInterface.php',
'Symfony\\Component\\DependencyInjection\\ContainerAwareTrait' => __DIR__ . '/..' . '/symfony/dependency-injection/ContainerAwareTrait.php',
'Symfony\\Component\\DependencyInjection\\ContainerBuilder' => __DIR__ . '/..' . '/symfony/dependency-injection/ContainerBuilder.php',
'Symfony\\Component\\DependencyInjection\\ContainerInterface' => __DIR__ . '/..' . '/symfony/dependency-injection/ContainerInterface.php',
'Symfony\\Component\\DependencyInjection\\Definition' => __DIR__ . '/..' . '/symfony/dependency-injection/Definition.php',
'Symfony\\Component\\DependencyInjection\\DefinitionDecorator' => __DIR__ . '/..' . '/symfony/dependency-injection/DefinitionDecorator.php',
'Symfony\\Component\\DependencyInjection\\Dumper\\Dumper' => __DIR__ . '/..' . '/symfony/dependency-injection/Dumper/Dumper.php',
'Symfony\\Component\\DependencyInjection\\Dumper\\DumperInterface' => __DIR__ . '/..' . '/symfony/dependency-injection/Dumper/DumperInterface.php',
'Symfony\\Component\\DependencyInjection\\Dumper\\GraphvizDumper' => __DIR__ . '/..' . '/symfony/dependency-injection/Dumper/GraphvizDumper.php',
'Symfony\\Component\\DependencyInjection\\Dumper\\PhpDumper' => __DIR__ . '/..' . '/symfony/dependency-injection/Dumper/PhpDumper.php',
'Symfony\\Component\\DependencyInjection\\Dumper\\XmlDumper' => __DIR__ . '/..' . '/symfony/dependency-injection/Dumper/XmlDumper.php',
'Symfony\\Component\\DependencyInjection\\Dumper\\YamlDumper' => __DIR__ . '/..' . '/symfony/dependency-injection/Dumper/YamlDumper.php',
'Symfony\\Component\\DependencyInjection\\Exception\\BadMethodCallException' => __DIR__ . '/..' . '/symfony/dependency-injection/Exception/BadMethodCallException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/dependency-injection/Exception/ExceptionInterface.php',
'Symfony\\Component\\DependencyInjection\\Exception\\InactiveScopeException' => __DIR__ . '/..' . '/symfony/dependency-injection/Exception/InactiveScopeException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\InvalidArgumentException' => __DIR__ . '/..' . '/symfony/dependency-injection/Exception/InvalidArgumentException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\LogicException' => __DIR__ . '/..' . '/symfony/dependency-injection/Exception/LogicException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\OutOfBoundsException' => __DIR__ . '/..' . '/symfony/dependency-injection/Exception/OutOfBoundsException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\ParameterCircularReferenceException' => __DIR__ . '/..' . '/symfony/dependency-injection/Exception/ParameterCircularReferenceException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\ParameterNotFoundException' => __DIR__ . '/..' . '/symfony/dependency-injection/Exception/ParameterNotFoundException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\RuntimeException' => __DIR__ . '/..' . '/symfony/dependency-injection/Exception/RuntimeException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\ScopeCrossingInjectionException' => __DIR__ . '/..' . '/symfony/dependency-injection/Exception/ScopeCrossingInjectionException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\ScopeWideningInjectionException' => __DIR__ . '/..' . '/symfony/dependency-injection/Exception/ScopeWideningInjectionException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\ServiceCircularReferenceException' => __DIR__ . '/..' . '/symfony/dependency-injection/Exception/ServiceCircularReferenceException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\ServiceNotFoundException' => __DIR__ . '/..' . '/symfony/dependency-injection/Exception/ServiceNotFoundException.php',
'Symfony\\Component\\DependencyInjection\\ExpressionLanguage' => __DIR__ . '/..' . '/symfony/dependency-injection/ExpressionLanguage.php',
'Symfony\\Component\\DependencyInjection\\ExpressionLanguageProvider' => __DIR__ . '/..' . '/symfony/dependency-injection/ExpressionLanguageProvider.php',
'Symfony\\Component\\DependencyInjection\\Extension\\ConfigurationExtensionInterface' => __DIR__ . '/..' . '/symfony/dependency-injection/Extension/ConfigurationExtensionInterface.php',
'Symfony\\Component\\DependencyInjection\\Extension\\Extension' => __DIR__ . '/..' . '/symfony/dependency-injection/Extension/Extension.php',
'Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface' => __DIR__ . '/..' . '/symfony/dependency-injection/Extension/ExtensionInterface.php',
'Symfony\\Component\\DependencyInjection\\Extension\\PrependExtensionInterface' => __DIR__ . '/..' . '/symfony/dependency-injection/Extension/PrependExtensionInterface.php',
'Symfony\\Component\\DependencyInjection\\IntrospectableContainerInterface' => __DIR__ . '/..' . '/symfony/dependency-injection/IntrospectableContainerInterface.php',
'Symfony\\Component\\DependencyInjection\\LazyProxy\\Instantiator\\InstantiatorInterface' => __DIR__ . '/..' . '/symfony/dependency-injection/LazyProxy/Instantiator/InstantiatorInterface.php',
'Symfony\\Component\\DependencyInjection\\LazyProxy\\Instantiator\\RealServiceInstantiator' => __DIR__ . '/..' . '/symfony/dependency-injection/LazyProxy/Instantiator/RealServiceInstantiator.php',
'Symfony\\Component\\DependencyInjection\\LazyProxy\\PhpDumper\\DumperInterface' => __DIR__ . '/..' . '/symfony/dependency-injection/LazyProxy/PhpDumper/DumperInterface.php',
'Symfony\\Component\\DependencyInjection\\LazyProxy\\PhpDumper\\NullDumper' => __DIR__ . '/..' . '/symfony/dependency-injection/LazyProxy/PhpDumper/NullDumper.php',
'Symfony\\Component\\DependencyInjection\\Loader\\ClosureLoader' => __DIR__ . '/..' . '/symfony/dependency-injection/Loader/ClosureLoader.php',
'Symfony\\Component\\DependencyInjection\\Loader\\DirectoryLoader' => __DIR__ . '/..' . '/symfony/dependency-injection/Loader/DirectoryLoader.php',
'Symfony\\Component\\DependencyInjection\\Loader\\FileLoader' => __DIR__ . '/..' . '/symfony/dependency-injection/Loader/FileLoader.php',
'Symfony\\Component\\DependencyInjection\\Loader\\IniFileLoader' => __DIR__ . '/..' . '/symfony/dependency-injection/Loader/IniFileLoader.php',
'Symfony\\Component\\DependencyInjection\\Loader\\PhpFileLoader' => __DIR__ . '/..' . '/symfony/dependency-injection/Loader/PhpFileLoader.php',
'Symfony\\Component\\DependencyInjection\\Loader\\XmlFileLoader' => __DIR__ . '/..' . '/symfony/dependency-injection/Loader/XmlFileLoader.php',
'Symfony\\Component\\DependencyInjection\\Loader\\YamlFileLoader' => __DIR__ . '/..' . '/symfony/dependency-injection/Loader/YamlFileLoader.php',
'Symfony\\Component\\DependencyInjection\\Parameter' => __DIR__ . '/..' . '/symfony/dependency-injection/Parameter.php',
'Symfony\\Component\\DependencyInjection\\ParameterBag\\FrozenParameterBag' => __DIR__ . '/..' . '/symfony/dependency-injection/ParameterBag/FrozenParameterBag.php',
'Symfony\\Component\\DependencyInjection\\ParameterBag\\ParameterBag' => __DIR__ . '/..' . '/symfony/dependency-injection/ParameterBag/ParameterBag.php',
'Symfony\\Component\\DependencyInjection\\ParameterBag\\ParameterBagInterface' => __DIR__ . '/..' . '/symfony/dependency-injection/ParameterBag/ParameterBagInterface.php',
'Symfony\\Component\\DependencyInjection\\Reference' => __DIR__ . '/..' . '/symfony/dependency-injection/Reference.php',
'Symfony\\Component\\DependencyInjection\\ResettableContainerInterface' => __DIR__ . '/..' . '/symfony/dependency-injection/ResettableContainerInterface.php',
'Symfony\\Component\\DependencyInjection\\Scope' => __DIR__ . '/..' . '/symfony/dependency-injection/Scope.php',
'Symfony\\Component\\DependencyInjection\\ScopeInterface' => __DIR__ . '/..' . '/symfony/dependency-injection/ScopeInterface.php',
'Symfony\\Component\\DependencyInjection\\SimpleXMLElement' => __DIR__ . '/..' . '/symfony/dependency-injection/SimpleXMLElement.php',
'Symfony\\Component\\DependencyInjection\\TaggedContainerInterface' => __DIR__ . '/..' . '/symfony/dependency-injection/TaggedContainerInterface.php',
'Symfony\\Component\\DependencyInjection\\Variable' => __DIR__ . '/..' . '/symfony/dependency-injection/Variable.php',
'Symfony\\Component\\Filesystem\\Exception\\ExceptionInterface' => __DIR__ . '/..' . '/symfony/filesystem/Exception/ExceptionInterface.php',
'Symfony\\Component\\Filesystem\\Exception\\FileNotFoundException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/FileNotFoundException.php',
'Symfony\\Component\\Filesystem\\Exception\\IOException' => __DIR__ . '/..' . '/symfony/filesystem/Exception/IOException.php',
'Symfony\\Component\\Filesystem\\Exception\\IOExceptionInterface' => __DIR__ . '/..' . '/symfony/filesystem/Exception/IOExceptionInterface.php',
'Symfony\\Component\\Filesystem\\Filesystem' => __DIR__ . '/..' . '/symfony/filesystem/Filesystem.php',
'Symfony\\Component\\Filesystem\\LockHandler' => __DIR__ . '/..' . '/symfony/filesystem/LockHandler.php',
'Symfony\\Polyfill\\Ctype\\Ctype' => __DIR__ . '/..' . '/symfony/polyfill-ctype/Ctype.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit0cffd5de0edad1133a933321d7b83570::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit0cffd5de0edad1133a933321d7b83570::$prefixDirsPsr4;
$loader->prefixesPsr0 = ComposerStaticInit0cffd5de0edad1133a933321d7b83570::$prefixesPsr0;
$loader->classMap = ComposerStaticInit0cffd5de0edad1133a933321d7b83570::$classMap;
}, null, ClassLoader::class);
}
}
Copyright (c) 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 ComposerAutoloaderInit0cffd5de0edad1133a933321d7b83570
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit0cffd5de0edad1133a933321d7b83570', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit0cffd5de0edad1133a933321d7b83570', '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\ComposerStaticInit0cffd5de0edad1133a933321d7b83570::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);
if ($useStaticLoader) {
$includeFiles = Composer\Autoload\ComposerStaticInit0cffd5de0edad1133a933321d7b83570::$files;
} else {
$includeFiles = require __DIR__ . '/autoload_files.php';
}
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire0cffd5de0edad1133a933321d7b83570($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequire0cffd5de0edad1133a933321d7b83570($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Symfony\\Polyfill\\Ctype\\' => array($vendorDir . '/symfony/polyfill-ctype'),
'Symfony\\Component\\Filesystem\\' => array($vendorDir . '/symfony/filesystem'),
'Symfony\\Component\\DependencyInjection\\' => array($vendorDir . '/symfony/dependency-injection'),
'Symfony\\Component\\Config\\' => array($vendorDir . '/symfony/config'),
'Psr\\Log\\' => array($vendorDir . '/psr/log/Psr/Log'),
'PDepend\\' => array($vendorDir . '/pdepend/pdepend/src/main/php/PDepend'),
'Composer\\XdebugHandler\\' => array($vendorDir . '/composer/xdebug-handler/src'),
);
<?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', array_values($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') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $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])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
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;
}
[
{
"name": "composer/xdebug-handler",
"version": "1.4.3",
"version_normalized": "1.4.3.0",
"source": {
"type": "git",
"url": "https://github.com/composer/xdebug-handler.git",
"reference": "ebd27a9866ae8254e873866f795491f02418c5a5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ebd27a9866ae8254e873866f795491f02418c5a5",
"reference": "ebd27a9866ae8254e873866f795491f02418c5a5",
"shasum": ""
},
"require": {
"php": "^5.3.2 || ^7.0 || ^8.0",
"psr/log": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8"
},
"time": "2020-08-19T10:27:58+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Composer\\XdebugHandler\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "John Stevenson",
"email": "john-stevenson@blueyonder.co.uk"
}
],
"description": "Restarts a process without Xdebug.",
"keywords": [
"Xdebug",
"performance"
],
"funding": [
{
"url": "https://packagist.com",
"type": "custom"
},
{
"url": "https://github.com/composer",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/composer/composer",
"type": "tidelift"
}
]
},
{
"name": "pdepend/pdepend",
"version": "2.8.0",
"version_normalized": "2.8.0.0",
"source": {
"type": "git",
"url": "https://github.com/pdepend/pdepend.git",
"reference": "c64472f8e76ca858c79ad9a4cf1e2734b3f8cc38"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pdepend/pdepend/zipball/c64472f8e76ca858c79ad9a4cf1e2734b3f8cc38",
"reference": "c64472f8e76ca858c79ad9a4cf1e2734b3f8cc38",
"shasum": ""
},
"require": {
"php": ">=5.3.7",
"symfony/config": "^2.3.0|^3|^4|^5",
"symfony/dependency-injection": "^2.3.0|^3|^4|^5",
"symfony/filesystem": "^2.3.0|^3|^4|^5"
},
"require-dev": {
"easy-doc/easy-doc": "0.0.0 || ^1.2.3",
"gregwar/rst": "^1.0",
"phpunit/phpunit": "^4.8.35|^5.7",
"squizlabs/php_codesniffer": "^2.0.0"
},
"time": "2020-06-20T10:53:13+00:00",
"bin": [
"src/bin/pdepend"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"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",
"funding": [
{
"url": "https://tidelift.com/funding/github/packagist/pdepend/pdepend",
"type": "tidelift"
}
]
},
{
"name": "psr/log",
"version": "1.1.3",
"version_normalized": "1.1.3.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "0f73288fd15629204f9d42b7055f72dacbe811fc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/0f73288fd15629204f9d42b7055f72dacbe811fc",
"reference": "0f73288fd15629204f9d42b7055f72dacbe811fc",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2020-03-23T09:12:05+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
]
},
{
"name": "symfony/config",
"version": "v2.8.52",
"version_normalized": "2.8.52.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/config.git",
"reference": "7dd5f5040dc04c118d057fb5886563963eb70011"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/config/zipball/7dd5f5040dc04c118d057fb5886563963eb70011",
"reference": "7dd5f5040dc04c118d057fb5886563963eb70011",
"shasum": ""
},
"require": {
"php": ">=5.3.9",
"symfony/filesystem": "~2.3|~3.0.0",
"symfony/polyfill-ctype": "~1.8"
},
"require-dev": {
"symfony/yaml": "~2.7|~3.0.0"
},
"suggest": {
"symfony/yaml": "To use the yaml reference dumper"
},
"time": "2018-11-26T09:38:12+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\Config\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Config Component",
"homepage": "https://symfony.com"
},
{
"name": "symfony/dependency-injection",
"version": "v2.8.52",
"version_normalized": "2.8.52.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/dependency-injection.git",
"reference": "c306198fee8f872a8f5f031e6e4f6f83086992d8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/dependency-injection/zipball/c306198fee8f872a8f5f031e6e4f6f83086992d8",
"reference": "c306198fee8f872a8f5f031e6e4f6f83086992d8",
"shasum": ""
},
"require": {
"php": ">=5.3.9"
},
"conflict": {
"symfony/expression-language": "<2.6"
},
"require-dev": {
"symfony/config": "~2.2|~3.0.0",
"symfony/expression-language": "~2.6|~3.0.0",
"symfony/yaml": "~2.3.42|~2.7.14|~2.8.7|~3.0.7"
},
"suggest": {
"symfony/config": "",
"symfony/expression-language": "For using expressions in service container configuration",
"symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
"symfony/yaml": ""
},
"time": "2019-04-16T11:33:46+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\DependencyInjection\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony DependencyInjection Component",
"homepage": "https://symfony.com"
},
{
"name": "symfony/filesystem",
"version": "v2.8.52",
"version_normalized": "2.8.52.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/filesystem.git",
"reference": "7ae46872dad09dffb7fe1e93a0937097339d0080"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/filesystem/zipball/7ae46872dad09dffb7fe1e93a0937097339d0080",
"reference": "7ae46872dad09dffb7fe1e93a0937097339d0080",
"shasum": ""
},
"require": {
"php": ">=5.3.9",
"symfony/polyfill-ctype": "~1.8"
},
"time": "2018-11-11T11:18:13+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\Filesystem\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Filesystem Component",
"homepage": "https://symfony.com"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.18.1",
"version_normalized": "1.18.1.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "1c302646f6efc070cd46856e600e5e0684d6b454"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454",
"reference": "1c302646f6efc070cd46856e600e5e0684d6b454",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"suggest": {
"ext-ctype": "For best performance"
},
"time": "2020-07-14T12:35:20+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.18-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
},
"files": [
"bootstrap.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
]
}
]
# composer/xdebug-handler
[![packagist](https://img.shields.io/packagist/v/composer/xdebug-handler.svg)](https://packagist.org/packages/composer/xdebug-handler)
[![linux build](https://img.shields.io/travis/composer/xdebug-handler/master.svg?label=linux+build)](https://travis-ci.org/composer/xdebug-handler)
[![windows build](https://img.shields.io/appveyor/ci/Seldaek/xdebug-handler/master.svg?label=windows+build)](https://ci.appveyor.com/project/Seldaek/xdebug-handler)
![license](https://img.shields.io/github/license/composer/xdebug-handler.svg)
![php](https://img.shields.io/packagist/php-v/composer/xdebug-handler.svg?colorB=8892BF&label=php)
Restart a CLI process without loading the Xdebug extension.
Originally written as part of [composer/composer](https://github.com/composer/composer),
now extracted and made available as a stand-alone library.
## Installation
Install the latest version with:
```bash
$ composer require composer/xdebug-handler
```
## Requirements
* PHP 5.3.2 minimum, although functionality is disabled below PHP 5.4.0. Using the latest PHP version is highly recommended.
## Basic Usage
```php
use Composer\XdebugHandler\XdebugHandler;
$xdebug = new XdebugHandler('myapp');
$xdebug->check();
unset($xdebug);
```
The constructor takes two parameters:
#### _$envPrefix_
This is used to create distinct environment variables and is upper-cased and prepended to default base values. The above example enables the use of:
- `MYAPP_ALLOW_XDEBUG=1` to override automatic restart and allow Xdebug
- `MYAPP_ORIGINAL_INIS` to obtain ini file locations in a restarted process
#### _$colorOption_
This optional value is added to the restart command-line and is needed to force color output in a piped child process. Only long-options are supported, for example `--ansi` or `--colors=always` etc.
If the original command-line contains an argument that pattern matches this value (for example `--no-ansi`, `--colors=never`) then _$colorOption_ is ignored.
If the pattern match ends with `=auto` (for example `--colors=auto`), the argument is replaced by _$colorOption_. Otherwise it is added at either the end of the command-line, or preceding the first double-dash `--` delimiter.
## Advanced Usage
* [How it works](#how-it-works)
* [Limitations](#limitations)
* [Helper methods](#helper-methods)
* [Setter methods](#setter-methods)
* [Process configuration](#process-configuration)
* [Troubleshooting](#troubleshooting)
* [Extending the library](#extending-the-library)
### How it works
A temporary ini file is created from the loaded (and scanned) ini files, with any references to the Xdebug extension commented out. Current ini settings are merged, so that most ini settings made on the command-line or by the application are included (see [Limitations](#limitations))
* `MYAPP_ALLOW_XDEBUG` is set with internal data to flag and use in the restart.
* The command-line and environment are [configured](#process-configuration) for the restart.
* The application is restarted in a new process using `passthru`.
* The restart settings are stored in the environment.
* `MYAPP_ALLOW_XDEBUG` is unset.
* The application runs and exits.
* The main process exits with the exit code from the restarted process.
#### Signal handling
From PHP 7.1 with the pcntl extension loaded, asynchronous signal handling is automatically enabled. `SIGINT` is set to `SIG_IGN` in the parent
process and restored to `SIG_DFL` in the restarted process (if no other handler has been set).
### Limitations
There are a few things to be aware of when running inside a restarted process.
* Extensions set on the command-line will not be loaded.
* Ini file locations will be reported as per the restart - see [getAllIniFiles()](#getallinifiles).
* Php sub-processes may be loaded with Xdebug enabled - see [Process configuration](#process-configuration).
* On Windows `sapi_windows_set_ctrl_handler` handlers will not receive CTRL events.
### Helper methods
These static methods provide information from the current process, regardless of whether it has been restarted or not.
#### _getAllIniFiles()_
Returns an array of the original ini file locations. Use this instead of calling `php_ini_loaded_file` and `php_ini_scanned_files`, which will report the wrong values in a restarted process.
```php
use Composer\XdebugHandler\XdebugHandler;
$files = XdebugHandler::getAllIniFiles();
# $files[0] always exists, it could be an empty string
$loadedIni = array_shift($files);
$scannedInis = $files;
```
These locations are also available in the `MYAPP_ORIGINAL_INIS` environment variable. This is a path-separated string comprising the location returned from `php_ini_loaded_file`, which could be empty, followed by locations parsed from calling `php_ini_scanned_files`.
#### _getRestartSettings()_
Returns an array of settings that can be used with PHP [sub-processes](#sub-processes), or null if the process was not restarted.
```php
use Composer\XdebugHandler\XdebugHandler;
$settings = XdebugHandler::getRestartSettings();
/**
* $settings: array (if the current process was restarted,
* or called with the settings from a previous restart), or null
*
* 'tmpIni' => the temporary ini file used in the restart (string)
* 'scannedInis' => if there were any scanned inis (bool)
* 'scanDir' => the original PHP_INI_SCAN_DIR value (false|string)
* 'phprc' => the original PHPRC value (false|string)
* 'inis' => the original inis from getAllIniFiles (array)
* 'skipped' => the skipped version from getSkippedVersion (string)
*/
```
#### _getSkippedVersion()_
Returns the Xdebug version string that was skipped by the restart, or an empty value if there was no restart (or Xdebug is still loaded, perhaps by an extending class restarting for a reason other than removing Xdebug).
```php
use Composer\XdebugHandler\XdebugHandler;
$version = XdebugHandler::getSkippedVersion();
# $version: '2.6.0' (for example), or an empty string
```
### Setter methods
These methods implement a fluent interface and must be called before the main `check()` method.
#### _setLogger($logger)_
Enables the output of status messages to an external PSR3 logger. All messages are reported with either `DEBUG` or `WARNING` log levels. For example (showing the level and message):
```
// Restart overridden
DEBUG Checking MYAPP_ALLOW_XDEBUG
DEBUG The Xdebug extension is loaded (2.5.0)
DEBUG No restart (MYAPP_ALLOW_XDEBUG=1)
// Failed restart
DEBUG Checking MYAPP_ALLOW_XDEBUG
DEBUG The Xdebug extension is loaded (2.5.0)
WARNING No restart (Unable to create temp ini file at: ...)
```
Status messages can also be output with `XDEBUG_HANDLER_DEBUG`. See [Troubleshooting](#troubleshooting).
#### _setMainScript($script)_
Sets the location of the main script to run in the restart. This is only needed in more esoteric use-cases, or if the `argv[0]` location is inaccessible. The script name `--` is supported for standard input.
#### _setPersistent()_
Configures the restart using [persistent settings](#persistent-settings), so that Xdebug is not loaded in any sub-process.
Use this method if your application invokes one or more PHP sub-process and the Xdebug extension is not needed. This avoids the overhead of implementing specific [sub-process](#sub-processes) strategies.
Alternatively, this method can be used to set up a default _Xdebug-free_ environment which can be changed if a sub-process requires Xdebug, then restored afterwards:
```php
function SubProcessWithXdebug()
{
$phpConfig = new Composer\XdebugHandler\PhpConfig();
# Set the environment to the original configuration
$phpConfig->useOriginal();
# run the process with Xdebug loaded
...
# Restore Xdebug-free environment
$phpConfig->usePersistent();
}
```
### Process configuration
The library offers two strategies to invoke a new PHP process without loading Xdebug, using either _standard_ or _persistent_ settings. Note that this is only important if the application calls a PHP sub-process.
#### Standard settings
Uses command-line options to remove Xdebug from the new process only.
* The -n option is added to the command-line. This tells PHP not to scan for additional inis.
* The temporary ini is added to the command-line with the -c option.
>_If the new process calls a PHP sub-process, Xdebug will be loaded in that sub-process (unless it implements xdebug-handler, in which case there will be another restart)._
This is the default strategy used in the restart.
#### Persistent settings
Uses environment variables to remove Xdebug from the new process and persist these settings to any sub-process.
* `PHP_INI_SCAN_DIR` is set to an empty string. This tells PHP not to scan for additional inis.
* `PHPRC` is set to the temporary ini.
>_If the new process calls a PHP sub-process, Xdebug will not be loaded in that sub-process._
This strategy can be used in the restart by calling [setPersistent()](#setpersistent).
#### Sub-processes
The `PhpConfig` helper class makes it easy to invoke a PHP sub-process (with or without Xdebug loaded), regardless of whether there has been a restart.
Each of its methods returns an array of PHP options (to add to the command-line) and sets up the environment for the required strategy. The [getRestartSettings()](#getrestartsettings) method is used internally.
* `useOriginal()` - Xdebug will be loaded in the new process.
* `useStandard()` - Xdebug will **not** be loaded in the new process - see [standard settings](#standard-settings).
* `userPersistent()` - Xdebug will **not** be loaded in the new process - see [persistent settings](#persistent-settings)
If there was no restart, an empty options array is returned and the environment is not changed.
```php
use Composer\XdebugHandler\PhpConfig;
$config = new PhpConfig;
$options = $config->useOriginal();
# $options: empty array
# environment: PHPRC and PHP_INI_SCAN_DIR set to original values
$options = $config->useStandard();
# $options: [-n, -c, tmpIni]
# environment: PHPRC and PHP_INI_SCAN_DIR set to original values
$options = $config->usePersistent();
# $options: empty array
# environment: PHPRC=tmpIni, PHP_INI_SCAN_DIR=''
```
### Troubleshooting
The following environment settings can be used to troubleshoot unexpected behavior:
* `XDEBUG_HANDLER_DEBUG=1` Outputs status messages to `STDERR`, if it is defined, irrespective of any PSR3 logger. Each message is prefixed `xdebug-handler[pid]`, where pid is the process identifier.
* `XDEBUG_HANDLER_DEBUG=2` As above, but additionally saves the temporary ini file and reports its location in a status message.
### Extending the library
The API is defined by classes and their accessible elements that are not annotated as @internal. The main class has two protected methods that can be overridden to provide additional functionality:
#### _requiresRestart($isLoaded)_
By default the process will restart if Xdebug is loaded. Extending this method allows an application to decide, by returning a boolean (or equivalent) value. It is only called if `MYAPP_ALLOW_XDEBUG` is empty, so it will not be called in the restarted process (where this variable contains internal data), or if the restart has been overridden.
Note that the [setMainScript()](#setmainscriptscript) and [setPersistent()](#setpersistent) setters can be used here, if required.
#### _restart($command)_
An application can extend this to modify the temporary ini file, its location given in the `tmpIni` property. New settings can be safely appended to the end of the data, which is `PHP_EOL` terminated.
Note that the `$command` parameter is the escaped command-line string that will be used for the new process and must be treated accordingly.
Remember to finish with `parent::restart($command)`.
#### Example
This example demonstrates two ways to extend basic functionality:
* To avoid the overhead of spinning up a new process, the restart is skipped if a simple help command is requested.
* The application needs write-access to phar files, so it will force a restart if `phar.readonly` is set (regardless of whether Xdebug is loaded) and change this value in the temporary ini file.
```php
use Composer\XdebugHandler\XdebugHandler;
use MyApp\Command;
class MyRestarter extends XdebugHandler
{
private $required;
protected function requiresRestart($isLoaded)
{
if (Command::isHelp()) {
# No need to disable Xdebug for this
return false;
}
$this->required = (bool) ini_get('phar.readonly');
return $isLoaded || $this->required;
}
protected function restart($command)
{
if ($this->required) {
# Add required ini setting to tmpIni
$content = file_get_contents($this->tmpIni);
$content .= 'phar.readonly=0'.PHP_EOL;
file_put_contents($this->tmpIni, $content);
}
parent::restart($command);
}
}
```
## License
composer/xdebug-handler is licensed under the MIT License, see the LICENSE file for details.
MIT License
Copyright (c) 2017 Composer
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.
## [Unreleased]
## [1.4.3] - 2020-08-19
* Fixed: restore SIGINT to default handler in restarted process if no other handler exists.
## [1.4.2] - 2020-06-04
* Fixed: ignore SIGINTs to let the restarted process handle them.
## [1.4.1] - 2020-03-01
* Fixed: restart fails if an ini file is empty.
## [1.4.0] - 2019-11-06
* Added: support for `NO_COLOR` environment variable: https://no-color.org
* Added: color support for Hyper terminal: https://github.com/zeit/hyper
* Fixed: correct capitalization of Xdebug (apparently).
* Fixed: improved handling for uopz extension.
## [1.3.3] - 2019-05-27
* Fixed: add environment changes to `$_ENV` if it is being used.
## [1.3.2] - 2019-01-28
* Fixed: exit call being blocked by uopz extension, resulting in application code running twice.
## [1.3.1] - 2018-11-29
* Fixed: fail restart if `passthru` has been disabled in `disable_functions`.
* Fixed: fail restart if an ini file cannot be opened, otherwise settings will be missing.
## [1.3.0] - 2018-08-31
* Added: `setPersistent` method to use environment variables for the restart.
* Fixed: improved debugging by writing output to stderr.
* Fixed: no restart when `php_ini_scanned_files` is not functional and is needed.
## [1.2.1] - 2018-08-23
* Fixed: fatal error with apc, when using `apc.mmap_file_mask`.
## [1.2.0] - 2018-08-16
* Added: debug information using `XDEBUG_HANDLER_DEBUG`.
* Added: fluent interface for setters.
* Added: `PhpConfig` helper class for calling PHP sub-processes.
* Added: `PHPRC` original value to restart stettings, for use in a restarted process.
* Changed: internal procedure to disable ini-scanning, using `-n` command-line option.
* Fixed: replaced `escapeshellarg` usage to avoid locale problems.
* Fixed: improved color-option handling to respect double-dash delimiter.
* Fixed: color-option handling regression from main script changes.
* Fixed: improved handling when checking main script.
* Fixed: handling for standard input, that never actually did anything.
* Fixed: fatal error when ctype extension is not available.
## [1.1.0] - 2018-04-11
* Added: `getRestartSettings` method for calling PHP processes in a restarted process.
* Added: API definition and @internal class annotations.
* Added: protected `requiresRestart` method for extending classes.
* Added: `setMainScript` method for applications that change the working directory.
* Changed: private `tmpIni` variable to protected for extending classes.
* Fixed: environment variables not available in $_SERVER when restored in the restart.
* Fixed: relative path problems caused by Phar::interceptFileFuncs.
* Fixed: incorrect handling when script file cannot be found.
## [1.0.0] - 2018-03-08
* Added: PSR3 logging for optional status output.
* Added: existing ini settings are merged to catch command-line overrides.
* Added: code, tests and other artefacts to decouple from Composer.
* Break: the following class was renamed:
- `Composer\XdebugHandler` -> `Composer\XdebugHandler\XdebugHandler`
[Unreleased]: https://github.com/composer/xdebug-handler/compare/1.4.3...HEAD
[1.4.3]: https://github.com/composer/xdebug-handler/compare/1.4.2...1.4.3
[1.4.2]: https://github.com/composer/xdebug-handler/compare/1.4.1...1.4.2
[1.4.1]: https://github.com/composer/xdebug-handler/compare/1.4.0...1.4.1
[1.4.0]: https://github.com/composer/xdebug-handler/compare/1.3.3...1.4.0
[1.3.3]: https://github.com/composer/xdebug-handler/compare/1.3.2...1.3.3
[1.3.2]: https://github.com/composer/xdebug-handler/compare/1.3.1...1.3.2
[1.3.1]: https://github.com/composer/xdebug-handler/compare/1.3.0...1.3.1
[1.3.0]: https://github.com/composer/xdebug-handler/compare/1.2.1...1.3.0
[1.2.1]: https://github.com/composer/xdebug-handler/compare/1.2.0...1.2.1
[1.2.0]: https://github.com/composer/xdebug-handler/compare/1.1.0...1.2.0
[1.1.0]: https://github.com/composer/xdebug-handler/compare/1.0.0...1.1.0
[1.0.0]: https://github.com/composer/xdebug-handler/compare/d66f0d15cb57...1.0.0
{
"name": "composer/xdebug-handler",
"description": "Restarts a process without Xdebug.",
"type": "library",
"license": "MIT",
"keywords": [
"xdebug",
"performance"
],
"authors": [
{
"name": "John Stevenson",
"email": "john-stevenson@blueyonder.co.uk"
}
],
"support": {
"irc": "irc://irc.freenode.org/composer",
"issues": "https://github.com/composer/xdebug-handler/issues"
},
"require": {
"php": "^5.3.2 || ^7.0 || ^8.0",
"psr/log": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7 || 6.5 - 8"
},
"autoload": {
"psr-4": {
"Composer\\XdebugHandler\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Composer\\XdebugHandler\\": "tests"
}
},
"scripts": {
"test": "phpunit"
}
}
<?php
/*
* This file is part of composer/xdebug-handler.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\XdebugHandler;
use Psr\Log\LoggerInterface;
/**
* @author John Stevenson <john-stevenson@blueyonder.co.uk>
*/
class XdebugHandler
{
const SUFFIX_ALLOW = '_ALLOW_XDEBUG';
const SUFFIX_INIS = '_ORIGINAL_INIS';
const RESTART_ID = 'internal';
const RESTART_SETTINGS = 'XDEBUG_HANDLER_SETTINGS';
const DEBUG = 'XDEBUG_HANDLER_DEBUG';
/** @var string|null */
protected $tmpIni;
private static $inRestart;
private static $name;
private static $skipped;
private $cli;
private $colorOption;
private $debug;
private $envAllowXdebug;
private $envOriginalInis;
private $loaded;
private $persistent;
private $script;
/** @var Status|null */
private $statusWriter;
/**
* Constructor
*
* The $envPrefix is used to create distinct environment variables. It is
* uppercased and prepended to the default base values. For example 'myapp'
* would result in MYAPP_ALLOW_XDEBUG and MYAPP_ORIGINAL_INIS.
*
* @param string $envPrefix Value used in environment variables
* @param string $colorOption Command-line long option to force color output
* @throws \RuntimeException If a parameter is invalid
*/
public function __construct($envPrefix, $colorOption = '')
{
if (!is_string($envPrefix) || empty($envPrefix) || !is_string($colorOption)) {
throw new \RuntimeException('Invalid constructor parameter');
}
self::$name = strtoupper($envPrefix);
$this->envAllowXdebug = self::$name.self::SUFFIX_ALLOW;
$this->envOriginalInis = self::$name.self::SUFFIX_INIS;
$this->colorOption = $colorOption;
if (extension_loaded('xdebug')) {
$ext = new \ReflectionExtension('xdebug');
$this->loaded = $ext->getVersion() ?: 'unknown';
}
if ($this->cli = PHP_SAPI === 'cli') {
$this->debug = getenv(self::DEBUG);
}
$this->statusWriter = new Status($this->envAllowXdebug, (bool) $this->debug);
}
/**
* Activates status message output to a PSR3 logger
*
* @param LoggerInterface $logger
*
* @return $this
*/
public function setLogger(LoggerInterface $logger)
{
$this->statusWriter->setLogger($logger);
return $this;
}
/**
* Sets the main script location if it cannot be called from argv
*
* @param string $script
*
* @return $this
*/
public function setMainScript($script)
{
$this->script = $script;
return $this;
}
/**
* Persist the settings to keep Xdebug out of sub-processes
*
* @return $this
*/
public function setPersistent()
{
$this->persistent = true;
return $this;
}
/**
* Checks if Xdebug is loaded and the process needs to be restarted
*
* This behaviour can be disabled by setting the MYAPP_ALLOW_XDEBUG
* environment variable to 1. This variable is used internally so that
* the restarted process is created only once.
*/
public function check()
{
$this->notify(Status::CHECK, $this->loaded);
$envArgs = explode('|', (string) getenv($this->envAllowXdebug));
if (empty($envArgs[0]) && $this->requiresRestart((bool) $this->loaded)) {
// Restart required
$this->notify(Status::RESTART);
if ($this->prepareRestart()) {
$command = $this->getCommand();
$this->restart($command);
}
return;
}
if (self::RESTART_ID === $envArgs[0] && count($envArgs) === 5) {
// Restarted, so unset environment variable and use saved values
$this->notify(Status::RESTARTED);
Process::setEnv($this->envAllowXdebug);
self::$inRestart = true;
if (!$this->loaded) {
// Skipped version is only set if Xdebug is not loaded
self::$skipped = $envArgs[1];
}
$this->tryEnableSignals();
// Put restart settings in the environment
$this->setEnvRestartSettings($envArgs);
return;
}
$this->notify(Status::NORESTART);
if ($settings = self::getRestartSettings()) {
// Called with existing settings, so sync our settings
$this->syncSettings($settings);
}
}
/**
* Returns an array of php.ini locations with at least one entry
*
* The equivalent of calling php_ini_loaded_file then php_ini_scanned_files.
* The loaded ini location is the first entry and may be empty.
*
* @return array
*/
public static function getAllIniFiles()
{
if (!empty(self::$name)) {
$env = getenv(self::$name.self::SUFFIX_INIS);
if (false !== $env) {
return explode(PATH_SEPARATOR, $env);
}
}
$paths = array((string) php_ini_loaded_file());
if ($scanned = php_ini_scanned_files()) {
$paths = array_merge($paths, array_map('trim', explode(',', $scanned)));
}
return $paths;
}
/**
* Returns an array of restart settings or null
*
* Settings will be available if the current process was restarted, or
* called with the settings from an existing restart.
*
* @return array|null
*/
public static function getRestartSettings()
{
$envArgs = explode('|', (string) getenv(self::RESTART_SETTINGS));
if (count($envArgs) !== 6
|| (!self::$inRestart && php_ini_loaded_file() !== $envArgs[0])) {
return;
}
return array(
'tmpIni' => $envArgs[0],
'scannedInis' => (bool) $envArgs[1],
'scanDir' => '*' === $envArgs[2] ? false : $envArgs[2],
'phprc' => '*' === $envArgs[3] ? false : $envArgs[3],
'inis' => explode(PATH_SEPARATOR, $envArgs[4]),
'skipped' => $envArgs[5],
);
}
/**
* Returns the Xdebug version that triggered a successful restart
*
* @return string
*/
public static function getSkippedVersion()
{
return (string) self::$skipped;
}
/**
* Returns true if Xdebug is loaded, or as directed by an extending class
*
* @param bool $isLoaded Whether Xdebug is loaded
*
* @return bool
*/
protected function requiresRestart($isLoaded)
{
return $isLoaded;
}
/**
* Allows an extending class to access the tmpIni
*
* @param string $command
*/
protected function restart($command)
{
$this->doRestart($command);
}
/**
* Executes the restarted command then deletes the tmp ini
*
* @param string $command
*/
private function doRestart($command)
{
$this->tryEnableSignals();
$this->notify(Status::RESTARTING, $command);
passthru($command, $exitCode);
$this->notify(Status::INFO, 'Restarted process exited '.$exitCode);
if ($this->debug === '2') {
$this->notify(Status::INFO, 'Temp ini saved: '.$this->tmpIni);
} else {
@unlink($this->tmpIni);
}
exit($exitCode);
}
/**
* Returns true if everything was written for the restart
*
* If any of the following fails (however unlikely) we must return false to
* stop potential recursion:
* - tmp ini file creation
* - environment variable creation
*
* @return bool
*/
private function prepareRestart()
{
$error = '';
$iniFiles = self::getAllIniFiles();
$scannedInis = count($iniFiles) > 1;
$tmpDir = sys_get_temp_dir();
if (!$this->cli) {
$error = 'Unsupported SAPI: '.PHP_SAPI;
} elseif (!defined('PHP_BINARY')) {
$error = 'PHP version is too old: '.PHP_VERSION;
} elseif (!$this->checkConfiguration($info)) {
$error = $info;
} elseif (!$this->checkScanDirConfig()) {
$error = 'PHP version does not report scanned inis: '.PHP_VERSION;
} elseif (!$this->checkMainScript()) {
$error = 'Unable to access main script: '.$this->script;
} elseif (!$this->writeTmpIni($iniFiles, $tmpDir, $error)) {
$error = $error ?: 'Unable to create temp ini file at: '.$tmpDir;
} elseif (!$this->setEnvironment($scannedInis, $iniFiles)) {
$error = 'Unable to set environment variables';
}
if ($error) {
$this->notify(Status::ERROR, $error);
}
return empty($error);
}
/**
* Returns true if the tmp ini file was written
*
* @param array $iniFiles All ini files used in the current process
* @param string $tmpDir The system temporary directory
* @param string $error Set by method if ini file cannot be read
*
* @return bool
*/
private function writeTmpIni(array $iniFiles, $tmpDir, &$error)
{
if (!$this->tmpIni = @tempnam($tmpDir, '')) {
return false;
}
// $iniFiles has at least one item and it may be empty
if (empty($iniFiles[0])) {
array_shift($iniFiles);
}
$content = '';
$regex = '/^\s*(zend_extension\s*=.*xdebug.*)$/mi';
foreach ($iniFiles as $file) {
// Check for inaccessible ini files
if (($data = @file_get_contents($file)) === false) {
$error = 'Unable to read ini: '.$file;
return false;
}
$content .= preg_replace($regex, ';$1', $data).PHP_EOL;
}
// Merge loaded settings into our ini content, if it is valid
if ($config = parse_ini_string($content)) {
$loaded = ini_get_all(null, false);
$content .= $this->mergeLoadedConfig($loaded, $config);
}
// Work-around for https://bugs.php.net/bug.php?id=75932
$content .= 'opcache.enable_cli=0'.PHP_EOL;
return @file_put_contents($this->tmpIni, $content);
}
/**
* Returns the restart command line
*
* @return string
*/
private function getCommand()
{
$php = array(PHP_BINARY);
$args = array_slice($_SERVER['argv'], 1);
if (!$this->persistent) {
// Use command-line options
array_push($php, '-n', '-c', $this->tmpIni);
}
if (defined('STDOUT') && Process::supportsColor(STDOUT)) {
$args = Process::addColorOption($args, $this->colorOption);
}
$args = array_merge($php, array($this->script), $args);
$cmd = Process::escape(array_shift($args), true, true);
foreach ($args as $arg) {
$cmd .= ' '.Process::escape($arg);
}
return $cmd;
}
/**
* Returns true if the restart environment variables were set
*
* No need to update $_SERVER since this is set in the restarted process.
*
* @param bool $scannedInis Whether there were scanned ini files
* @param array $iniFiles All ini files used in the current process
*
* @return bool
*/
private function setEnvironment($scannedInis, array $iniFiles)
{
$scanDir = getenv('PHP_INI_SCAN_DIR');
$phprc = getenv('PHPRC');
// Make original inis available to restarted process
if (!putenv($this->envOriginalInis.'='.implode(PATH_SEPARATOR, $iniFiles))) {
return false;
}
if ($this->persistent) {
// Use the environment to persist the settings
if (!putenv('PHP_INI_SCAN_DIR=') || !putenv('PHPRC='.$this->tmpIni)) {
return false;
}
}
// Flag restarted process and save values for it to use
$envArgs = array(
self::RESTART_ID,
$this->loaded,
(int) $scannedInis,
false === $scanDir ? '*' : $scanDir,
false === $phprc ? '*' : $phprc,
);
return putenv($this->envAllowXdebug.'='.implode('|', $envArgs));
}
/**
* Logs status messages
*
* @param string $op Status handler constant
* @param null|string $data Optional data
*/
private function notify($op, $data = null)
{
$this->statusWriter->report($op, $data);
}
/**
* Returns default, changed and command-line ini settings
*
* @param array $loadedConfig All current ini settings
* @param array $iniConfig Settings from user ini files
*
* @return string
*/
private function mergeLoadedConfig(array $loadedConfig, array $iniConfig)
{
$content = '';
foreach ($loadedConfig as $name => $value) {
// Value will either be null, string or array (HHVM only)
if (!is_string($value)
|| strpos($name, 'xdebug') === 0
|| $name === 'apc.mmap_file_mask') {
continue;
}
if (!isset($iniConfig[$name]) || $iniConfig[$name] !== $value) {
// Double-quote escape each value
$content .= $name.'="'.addcslashes($value, '\\"').'"'.PHP_EOL;
}
}
return $content;
}
/**
* Returns true if the script name can be used
*
* @return bool
*/
private function checkMainScript()
{
if (null !== $this->script) {
// Allow an application to set -- for standard input
return file_exists($this->script) || '--' === $this->script;
}
if (file_exists($this->script = $_SERVER['argv'][0])) {
return true;
}
// Use a backtrace to resolve Phar and chdir issues
$options = PHP_VERSION_ID >= 50306 ? DEBUG_BACKTRACE_IGNORE_ARGS : false;
$trace = debug_backtrace($options);
if (($main = end($trace)) && isset($main['file'])) {
return file_exists($this->script = $main['file']);
}
return false;
}
/**
* Adds restart settings to the environment
*
* @param string $envArgs
*/
private function setEnvRestartSettings($envArgs)
{
$settings = array(
php_ini_loaded_file(),
$envArgs[2],
$envArgs[3],
$envArgs[4],
getenv($this->envOriginalInis),
self::$skipped,
);
Process::setEnv(self::RESTART_SETTINGS, implode('|', $settings));
}
/**
* Syncs settings and the environment if called with existing settings
*
* @param array $settings
*/
private function syncSettings(array $settings)
{
if (false === getenv($this->envOriginalInis)) {
// Called by another app, so make original inis available
Process::setEnv($this->envOriginalInis, implode(PATH_SEPARATOR, $settings['inis']));
}
self::$skipped = $settings['skipped'];
$this->notify(Status::INFO, 'Process called with existing restart settings');
}
/**
* Returns true if there are scanned inis and PHP is able to report them
*
* php_ini_scanned_files will fail when PHP_CONFIG_FILE_SCAN_DIR is empty.
* Fixed in 7.1.13 and 7.2.1
*
* @return bool
*/
private function checkScanDirConfig()
{
return !(getenv('PHP_INI_SCAN_DIR')
&& !PHP_CONFIG_FILE_SCAN_DIR
&& (PHP_VERSION_ID < 70113
|| PHP_VERSION_ID === 70200));
}
/**
* Returns true if there are no known configuration issues
*
* @param string $info Set by method
*/
private function checkConfiguration(&$info)
{
if (false !== strpos(ini_get('disable_functions'), 'passthru')) {
$info = 'passthru function is disabled';
return false;
}
if (extension_loaded('uopz') && !ini_get('uopz.disable')) {
// uopz works at opcode level and disables exit calls
if (function_exists('uopz_allow_exit')) {
@uopz_allow_exit(true);
} else {
$info = 'uopz extension is not compatible';
return false;
}
}
return true;
}
/**
* Enables async signals and control interrupts in the restarted process
*
* Only available on Unix PHP 7.1+ with the pcntl extension. To replicate on
* Windows would require PHP 7.4+ using proc_open rather than passthru.
*/
private function tryEnableSignals()
{
if (!function_exists('pcntl_async_signals')) {
return;
}
pcntl_async_signals(true);
$message = 'Async signals enabled';
if (!self::$inRestart) {
// Restarting, so ignore SIGINT in parent
pcntl_signal(SIGINT, SIG_IGN);
$message .= ' (SIGINT = SIG_IGN)';
} elseif (is_int(pcntl_signal_get_handler(SIGINT))) {
// Restarted, no handler set so force default action
pcntl_signal(SIGINT, SIG_DFL);
$message .= ' (SIGINT = SIG_DFL)';
}
$this->notify(Status::INFO, $message);
}
}
<?php
/*
* This file is part of composer/xdebug-handler.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\XdebugHandler;
/**
* @author John Stevenson <john-stevenson@blueyonder.co.uk>
*/
class PhpConfig
{
/**
* Use the original PHP configuration
*
* @return array PHP cli options
*/
public function useOriginal()
{
$this->getDataAndReset();
return array();
}
/**
* Use standard restart settings
*
* @return array PHP cli options
*/
public function useStandard()
{
if ($data = $this->getDataAndReset()) {
return array('-n', '-c', $data['tmpIni']);
}
return array();
}
/**
* Use environment variables to persist settings
*
* @return array PHP cli options
*/
public function usePersistent()
{
if ($data = $this->getDataAndReset()) {
Process::setEnv('PHPRC', $data['tmpIni']);
Process::setEnv('PHP_INI_SCAN_DIR', '');
}
return array();
}
/**
* Returns restart data if available and resets the environment
*
* @return array|null
*/
private function getDataAndReset()
{
if ($data = XdebugHandler::getRestartSettings()) {
Process::setEnv('PHPRC', $data['phprc']);
Process::setEnv('PHP_INI_SCAN_DIR', $data['scanDir']);
}
return $data;
}
}
<?php
/*
* This file is part of composer/xdebug-handler.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\XdebugHandler;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
/**
* @author John Stevenson <john-stevenson@blueyonder.co.uk>
* @internal
*/
class Status
{
const ENV_RESTART = 'XDEBUG_HANDLER_RESTART';
const CHECK = 'Check';
const ERROR = 'Error';
const INFO = 'Info';
const NORESTART = 'NoRestart';
const RESTART = 'Restart';
const RESTARTING = 'Restarting';
const RESTARTED = 'Restarted';
private $debug;
private $envAllowXdebug;
private $loaded;
private $logger;
private $time;
/**
* Constructor
*
* @param string $envAllowXdebug Prefixed _ALLOW_XDEBUG name
* @param bool $debug Whether debug output is required
*/
public function __construct($envAllowXdebug, $debug)
{
$start = getenv(self::ENV_RESTART);
Process::setEnv(self::ENV_RESTART);
$this->time = $start ? round((microtime(true) - $start) * 1000) : 0;
$this->envAllowXdebug = $envAllowXdebug;
$this->debug = $debug && defined('STDERR');
}
/**
* @param LoggerInterface $logger
*/
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
/**
* Calls a handler method to report a message
*
* @param string $op The handler constant
* @param null|string $data Data required by the handler
*/
public function report($op, $data)
{
if ($this->logger || $this->debug) {
call_user_func(array($this, 'report'.$op), $data);
}
}
/**
* Outputs a status message
*
* @param string $text
* @param string $level
*/
private function output($text, $level = null)
{
if ($this->logger) {
$this->logger->log($level ?: LogLevel::DEBUG, $text);
}
if ($this->debug) {
fwrite(STDERR, sprintf('xdebug-handler[%d] %s', getmypid(), $text.PHP_EOL));
}
}
private function reportCheck($loaded)
{
$this->loaded = $loaded;
$this->output('Checking '.$this->envAllowXdebug);
}
private function reportError($error)
{
$this->output(sprintf('No restart (%s)', $error), LogLevel::WARNING);
}
private function reportInfo($info)
{
$this->output($info);
}
private function reportNoRestart()
{
$this->output($this->getLoadedMessage());
if ($this->loaded) {
$text = sprintf('No restart (%s)', $this->getEnvAllow());
if (!getenv($this->envAllowXdebug)) {
$text .= ' Allowed by application';
}
$this->output($text);
}
}
private function reportRestart()
{
$this->output($this->getLoadedMessage());
Process::setEnv(self::ENV_RESTART, (string) microtime(true));
}
private function reportRestarted()
{
$loaded = $this->getLoadedMessage();
$text = sprintf('Restarted (%d ms). %s', $this->time, $loaded);
$level = $this->loaded ? LogLevel::WARNING : null;
$this->output($text, $level);
}
private function reportRestarting($command)
{
$text = sprintf('Process restarting (%s)', $this->getEnvAllow());
$this->output($text);
$text = 'Running '.$command;
$this->output($text);
}
/**
* Returns the _ALLOW_XDEBUG environment variable as name=value
*
* @return string
*/
private function getEnvAllow()
{
return $this->envAllowXdebug.'='.getenv($this->envAllowXdebug);
}
/**
* Returns the Xdebug status and version
*
* @return string
*/
private function getLoadedMessage()
{
$loaded = $this->loaded ? sprintf('loaded (%s)', $this->loaded) : 'not loaded';
return 'The Xdebug extension is '.$loaded;
}
}
<?php
/*
* This file is part of composer/xdebug-handler.
*
* (c) Composer <https://github.com/composer>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Composer\XdebugHandler;
/**
* Provides utility functions to prepare a child process command-line and set
* environment variables in that process.
*
* @author John Stevenson <john-stevenson@blueyonder.co.uk>
* @internal
*/
class Process
{
/**
* Returns an array of parameters, including a color option if required
*
* A color option is needed because child process output is piped.
*
* @param array $args The script parameters
* @param string $colorOption The long option to force color output
*
* @return array
*/
public static function addColorOption(array $args, $colorOption)
{
if (!$colorOption
|| in_array($colorOption, $args)
|| !preg_match('/^--([a-z]+$)|(^--[a-z]+=)/', $colorOption, $matches)) {
return $args;
}
if (isset($matches[2])) {
// Handle --color(s)= options
if (false !== ($index = array_search($matches[2].'auto', $args))) {
$args[$index] = $colorOption;
return $args;
} elseif (preg_grep('/^'.$matches[2].'/', $args)) {
return $args;
}
} elseif (in_array('--no-'.$matches[1], $args)) {
return $args;
}
// Check for NO_COLOR variable (https://no-color.org/)
if (false !== getenv('NO_COLOR')) {
return $args;
}
if (false !== ($index = array_search('--', $args))) {
// Position option before double-dash delimiter
array_splice($args, $index, 0, $colorOption);
} else {
$args[] = $colorOption;
}
return $args;
}
/**
* Escapes a string to be used as a shell argument.
*
* From https://github.com/johnstevenson/winbox-args
* MIT Licensed (c) John Stevenson <john-stevenson@blueyonder.co.uk>
*
* @param string $arg The argument to be escaped
* @param bool $meta Additionally escape cmd.exe meta characters
* @param bool $module The argument is the module to invoke
*
* @return string The escaped argument
*/
public static function escape($arg, $meta = true, $module = false)
{
if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
return "'".str_replace("'", "'\\''", $arg)."'";
}
$quote = strpbrk($arg, " \t") !== false || $arg === '';
$arg = preg_replace('/(\\\\*)"/', '$1$1\\"', $arg, -1, $dquotes);
if ($meta) {
$meta = $dquotes || preg_match('/%[^%]+%/', $arg);
if (!$meta) {
$quote = $quote || strpbrk($arg, '^&|<>()') !== false;
} elseif ($module && !$dquotes && $quote) {
$meta = false;
}
}
if ($quote) {
$arg = '"'.preg_replace('/(\\\\*)$/', '$1$1', $arg).'"';
}
if ($meta) {
$arg = preg_replace('/(["^&|<>()%])/', '^$1', $arg);
}
return $arg;
}
/**
* Returns true if the output stream supports colors
*
* This is tricky on Windows, because Cygwin, Msys2 etc emulate pseudo
* terminals via named pipes, so we can only check the environment.
*
* @param mixed $output A valid CLI output stream
*
* @return bool
*/
public static function supportsColor($output)
{
if ('Hyper' === getenv('TERM_PROGRAM')) {
return true;
}
if (defined('PHP_WINDOWS_VERSION_BUILD')) {
return (function_exists('sapi_windows_vt100_support')
&& sapi_windows_vt100_support($output))
|| false !== getenv('ANSICON')
|| 'ON' === getenv('ConEmuANSI')
|| 'xterm' === getenv('TERM');
}
if (function_exists('stream_isatty')) {
return stream_isatty($output);
}
if (function_exists('posix_isatty')) {
return posix_isatty($output);
}
$stat = fstat($output);
// Check if formatted mode is S_IFCHR
return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
}
/**
* Makes putenv environment changes available in $_SERVER and $_ENV
*
* @param string $name
* @param string|false $value A false value unsets the variable
*
* @return bool Whether the environment variable was set
*/
public static function setEnv($name, $value = false)
{
$unset = false === $value;
if (!putenv($unset ? $name : $name.'='.$value)) {
return false;
}
if ($unset) {
unset($_SERVER[$name]);
} else {
$_SERVER[$name] = $value;
}
// Update $_ENV if it is being used
if (false !== stripos((string) ini_get('variables_order'), 'E')) {
if ($unset) {
unset($_ENV[$name]);
} else {
$_ENV[$name] = $value;
}
}
return true;
}
}
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Composer\\XdebugHandler\\PhpConfig' => $vendorDir . '/composer/xdebug-handler/src/PhpConfig.php',
'Composer\\XdebugHandler\\Process' => $vendorDir . '/composer/xdebug-handler/src/Process.php',
'Composer\\XdebugHandler\\Status' => $vendorDir . '/composer/xdebug-handler/src/Status.php',
'Composer\\XdebugHandler\\XdebugHandler' => $vendorDir . '/composer/xdebug-handler/src/XdebugHandler.php',
'PDepend\\Application' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Application.php',
'PDepend\\DbusUI\\ResultPrinter' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/DbusUI/ResultPrinter.php',
'PDepend\\DependencyInjection\\Compiler\\ProcessListenerPass' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/Compiler/ProcessListenerPass.php',
'PDepend\\DependencyInjection\\Configuration' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/Configuration.php',
'PDepend\\DependencyInjection\\Extension' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/Extension.php',
'PDepend\\DependencyInjection\\ExtensionManager' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/ExtensionManager.php',
'PDepend\\DependencyInjection\\PdependExtension' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/PdependExtension.php',
'PDepend\\DependencyInjection\\TreeBuilder' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/DependencyInjection/TreeBuilder.php',
'PDepend\\Engine' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Engine.php',
'PDepend\\Input\\CompositeFilter' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Input/CompositeFilter.php',
'PDepend\\Input\\ExcludePathFilter' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Input/ExcludePathFilter.php',
'PDepend\\Input\\ExtensionFilter' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Input/ExtensionFilter.php',
'PDepend\\Input\\Filter' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Input/Filter.php',
'PDepend\\Input\\Iterator' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Input/Iterator.php',
'PDepend\\Metrics\\AbstractAnalyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AbstractAnalyzer.php',
'PDepend\\Metrics\\AbstractCachingAnalyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AbstractCachingAnalyzer.php',
'PDepend\\Metrics\\AggregateAnalyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AggregateAnalyzer.php',
'PDepend\\Metrics\\Analyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer.php',
'PDepend\\Metrics\\AnalyzerCacheAware' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerCacheAware.php',
'PDepend\\Metrics\\AnalyzerFactory' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerFactory.php',
'PDepend\\Metrics\\AnalyzerFilterAware' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerFilterAware.php',
'PDepend\\Metrics\\AnalyzerIterator' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerIterator.php',
'PDepend\\Metrics\\AnalyzerListener' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerListener.php',
'PDepend\\Metrics\\AnalyzerNodeAware' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerNodeAware.php',
'PDepend\\Metrics\\AnalyzerProjectAware' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/AnalyzerProjectAware.php',
'PDepend\\Metrics\\Analyzer\\ClassDependencyAnalyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/ClassDependencyAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\ClassLevelAnalyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/ClassLevelAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\CodeRankAnalyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\CodeRankAnalyzer\\CodeRankStrategyI' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/CodeRankStrategyI.php',
'PDepend\\Metrics\\Analyzer\\CodeRankAnalyzer\\InheritanceStrategy' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/InheritanceStrategy.php',
'PDepend\\Metrics\\Analyzer\\CodeRankAnalyzer\\MethodStrategy' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/MethodStrategy.php',
'PDepend\\Metrics\\Analyzer\\CodeRankAnalyzer\\PropertyStrategy' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/PropertyStrategy.php',
'PDepend\\Metrics\\Analyzer\\CodeRankAnalyzer\\StrategyFactory' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CodeRankAnalyzer/StrategyFactory.php',
'PDepend\\Metrics\\Analyzer\\CohesionAnalyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CohesionAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\CouplingAnalyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CouplingAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\CrapIndexAnalyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CrapIndexAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\CyclomaticComplexityAnalyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/CyclomaticComplexityAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\DependencyAnalyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/DependencyAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\HalsteadAnalyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/HalsteadAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\HierarchyAnalyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/HierarchyAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\InheritanceAnalyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/InheritanceAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\MaintainabilityIndexAnalyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/MaintainabilityIndexAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\NPathComplexityAnalyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/NPathComplexityAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\NodeCountAnalyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/NodeCountAnalyzer.php',
'PDepend\\Metrics\\Analyzer\\NodeLocAnalyzer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Metrics/Analyzer/NodeLocAnalyzer.php',
'PDepend\\ProcessListener' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/ProcessListener.php',
'PDepend\\Report\\CodeAwareGenerator' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Report/CodeAwareGenerator.php',
'PDepend\\Report\\Dependencies\\Xml' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Report/Dependencies/Xml.php',
'PDepend\\Report\\FileAwareGenerator' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Report/FileAwareGenerator.php',
'PDepend\\Report\\Jdepend\\Chart' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Report/Jdepend/Chart.php',
'PDepend\\Report\\Jdepend\\Xml' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Report/Jdepend/Xml.php',
'PDepend\\Report\\NoLogOutputException' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Report/NoLogOutputException.php',
'PDepend\\Report\\Overview\\Pyramid' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Report/Overview/Pyramid.php',
'PDepend\\Report\\ReportGenerator' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Report/ReportGenerator.php',
'PDepend\\Report\\ReportGeneratorFactory' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Report/ReportGeneratorFactory.php',
'PDepend\\Report\\Summary\\Xml' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Report/Summary/Xml.php',
'PDepend\\Source\\ASTVisitor\\ASTVisitListener' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/ASTVisitor/ASTVisitListener.php',
'PDepend\\Source\\ASTVisitor\\ASTVisitor' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/ASTVisitor/ASTVisitor.php',
'PDepend\\Source\\ASTVisitor\\AbstractASTVisitListener' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/ASTVisitor/AbstractASTVisitListener.php',
'PDepend\\Source\\ASTVisitor\\AbstractASTVisitor' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/ASTVisitor/AbstractASTVisitor.php',
'PDepend\\Source\\AST\\ASTAllocationExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTAllocationExpression.php',
'PDepend\\Source\\AST\\ASTAnonymousClass' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTAnonymousClass.php',
'PDepend\\Source\\AST\\ASTArguments' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArguments.php',
'PDepend\\Source\\AST\\ASTArray' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArray.php',
'PDepend\\Source\\AST\\ASTArrayElement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArrayElement.php',
'PDepend\\Source\\AST\\ASTArrayIndexExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArrayIndexExpression.php',
'PDepend\\Source\\AST\\ASTArtifact' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifact.php',
'PDepend\\Source\\AST\\ASTArtifactList' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList.php',
'PDepend\\Source\\AST\\ASTArtifactList\\ArtifactFilter' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList/ArtifactFilter.php',
'PDepend\\Source\\AST\\ASTArtifactList\\CollectionArtifactFilter' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList/CollectionArtifactFilter.php',
'PDepend\\Source\\AST\\ASTArtifactList\\NullArtifactFilter' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList/NullArtifactFilter.php',
'PDepend\\Source\\AST\\ASTArtifactList\\PackageArtifactFilter' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTArtifactList/PackageArtifactFilter.php',
'PDepend\\Source\\AST\\ASTAssignmentExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTAssignmentExpression.php',
'PDepend\\Source\\AST\\ASTBooleanAndExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTBooleanAndExpression.php',
'PDepend\\Source\\AST\\ASTBooleanOrExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTBooleanOrExpression.php',
'PDepend\\Source\\AST\\ASTBreakStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTBreakStatement.php',
'PDepend\\Source\\AST\\ASTCallable' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCallable.php',
'PDepend\\Source\\AST\\ASTCastExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCastExpression.php',
'PDepend\\Source\\AST\\ASTCatchStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCatchStatement.php',
'PDepend\\Source\\AST\\ASTClass' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClass.php',
'PDepend\\Source\\AST\\ASTClassFqnPostfix' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassFqnPostfix.php',
'PDepend\\Source\\AST\\ASTClassOrInterfaceRecursiveInheritanceException' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassOrInterfaceRecursiveInheritanceException.php',
'PDepend\\Source\\AST\\ASTClassOrInterfaceReference' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassOrInterfaceReference.php',
'PDepend\\Source\\AST\\ASTClassOrInterfaceReferenceIterator' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassOrInterfaceReferenceIterator.php',
'PDepend\\Source\\AST\\ASTClassReference' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClassReference.php',
'PDepend\\Source\\AST\\ASTCloneExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCloneExpression.php',
'PDepend\\Source\\AST\\ASTClosure' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTClosure.php',
'PDepend\\Source\\AST\\ASTComment' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTComment.php',
'PDepend\\Source\\AST\\ASTCompilationUnit' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCompilationUnit.php',
'PDepend\\Source\\AST\\ASTCompilationUnitNotFoundException' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCompilationUnitNotFoundException.php',
'PDepend\\Source\\AST\\ASTCompoundExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCompoundExpression.php',
'PDepend\\Source\\AST\\ASTCompoundVariable' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTCompoundVariable.php',
'PDepend\\Source\\AST\\ASTConditionalExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConditionalExpression.php',
'PDepend\\Source\\AST\\ASTConstant' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConstant.php',
'PDepend\\Source\\AST\\ASTConstantDeclarator' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConstantDeclarator.php',
'PDepend\\Source\\AST\\ASTConstantDefinition' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConstantDefinition.php',
'PDepend\\Source\\AST\\ASTConstantPostfix' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTConstantPostfix.php',
'PDepend\\Source\\AST\\ASTContinueStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTContinueStatement.php',
'PDepend\\Source\\AST\\ASTDeclareStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTDeclareStatement.php',
'PDepend\\Source\\AST\\ASTDoWhileStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTDoWhileStatement.php',
'PDepend\\Source\\AST\\ASTEchoStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTEchoStatement.php',
'PDepend\\Source\\AST\\ASTElseIfStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTElseIfStatement.php',
'PDepend\\Source\\AST\\ASTEvalExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTEvalExpression.php',
'PDepend\\Source\\AST\\ASTExitExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTExitExpression.php',
'PDepend\\Source\\AST\\ASTExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTExpression.php',
'PDepend\\Source\\AST\\ASTFieldDeclaration' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFieldDeclaration.php',
'PDepend\\Source\\AST\\ASTFinallyStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFinallyStatement.php',
'PDepend\\Source\\AST\\ASTForInit' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTForInit.php',
'PDepend\\Source\\AST\\ASTForStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTForStatement.php',
'PDepend\\Source\\AST\\ASTForUpdate' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTForUpdate.php',
'PDepend\\Source\\AST\\ASTForeachStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTForeachStatement.php',
'PDepend\\Source\\AST\\ASTFormalParameter' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFormalParameter.php',
'PDepend\\Source\\AST\\ASTFormalParameters' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFormalParameters.php',
'PDepend\\Source\\AST\\ASTFunction' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFunction.php',
'PDepend\\Source\\AST\\ASTFunctionPostfix' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTFunctionPostfix.php',
'PDepend\\Source\\AST\\ASTGlobalStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTGlobalStatement.php',
'PDepend\\Source\\AST\\ASTGotoStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTGotoStatement.php',
'PDepend\\Source\\AST\\ASTHeredoc' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTHeredoc.php',
'PDepend\\Source\\AST\\ASTIdentifier' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIdentifier.php',
'PDepend\\Source\\AST\\ASTIfStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIfStatement.php',
'PDepend\\Source\\AST\\ASTIncludeExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIncludeExpression.php',
'PDepend\\Source\\AST\\ASTIndexExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIndexExpression.php',
'PDepend\\Source\\AST\\ASTInstanceOfExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTInstanceOfExpression.php',
'PDepend\\Source\\AST\\ASTInterface' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTInterface.php',
'PDepend\\Source\\AST\\ASTInvocation' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTInvocation.php',
'PDepend\\Source\\AST\\ASTIssetExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTIssetExpression.php',
'PDepend\\Source\\AST\\ASTLabelStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLabelStatement.php',
'PDepend\\Source\\AST\\ASTListExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTListExpression.php',
'PDepend\\Source\\AST\\ASTLiteral' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLiteral.php',
'PDepend\\Source\\AST\\ASTLogicalAndExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLogicalAndExpression.php',
'PDepend\\Source\\AST\\ASTLogicalOrExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLogicalOrExpression.php',
'PDepend\\Source\\AST\\ASTLogicalXorExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTLogicalXorExpression.php',
'PDepend\\Source\\AST\\ASTMemberPrimaryPrefix' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTMemberPrimaryPrefix.php',
'PDepend\\Source\\AST\\ASTMethod' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTMethod.php',
'PDepend\\Source\\AST\\ASTMethodPostfix' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTMethodPostfix.php',
'PDepend\\Source\\AST\\ASTNamespace' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTNamespace.php',
'PDepend\\Source\\AST\\ASTNode' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTNode.php',
'PDepend\\Source\\AST\\ASTParameter' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTParameter.php',
'PDepend\\Source\\AST\\ASTParentReference' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTParentReference.php',
'PDepend\\Source\\AST\\ASTPostfixExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPostfixExpression.php',
'PDepend\\Source\\AST\\ASTPreDecrementExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPreDecrementExpression.php',
'PDepend\\Source\\AST\\ASTPreIncrementExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPreIncrementExpression.php',
'PDepend\\Source\\AST\\ASTPrintExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPrintExpression.php',
'PDepend\\Source\\AST\\ASTProperty' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTProperty.php',
'PDepend\\Source\\AST\\ASTPropertyPostfix' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTPropertyPostfix.php',
'PDepend\\Source\\AST\\ASTRequireExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTRequireExpression.php',
'PDepend\\Source\\AST\\ASTReturnStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTReturnStatement.php',
'PDepend\\Source\\AST\\ASTScalarType' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTScalarType.php',
'PDepend\\Source\\AST\\ASTScope' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTScope.php',
'PDepend\\Source\\AST\\ASTScopeStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTScopeStatement.php',
'PDepend\\Source\\AST\\ASTSelfReference' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTSelfReference.php',
'PDepend\\Source\\AST\\ASTShiftLeftExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTShiftLeftExpression.php',
'PDepend\\Source\\AST\\ASTShiftRightExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTShiftRightExpression.php',
'PDepend\\Source\\AST\\ASTStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTStatement.php',
'PDepend\\Source\\AST\\ASTStaticReference' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTStaticReference.php',
'PDepend\\Source\\AST\\ASTStaticVariableDeclaration' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTStaticVariableDeclaration.php',
'PDepend\\Source\\AST\\ASTString' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTString.php',
'PDepend\\Source\\AST\\ASTStringIndexExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTStringIndexExpression.php',
'PDepend\\Source\\AST\\ASTSwitchLabel' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTSwitchLabel.php',
'PDepend\\Source\\AST\\ASTSwitchStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTSwitchStatement.php',
'PDepend\\Source\\AST\\ASTThrowStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTThrowStatement.php',
'PDepend\\Source\\AST\\ASTTrait' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTrait.php',
'PDepend\\Source\\AST\\ASTTraitAdaptation' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitAdaptation.php',
'PDepend\\Source\\AST\\ASTTraitAdaptationAlias' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitAdaptationAlias.php',
'PDepend\\Source\\AST\\ASTTraitAdaptationPrecedence' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitAdaptationPrecedence.php',
'PDepend\\Source\\AST\\ASTTraitMethodCollisionException' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitMethodCollisionException.php',
'PDepend\\Source\\AST\\ASTTraitReference' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitReference.php',
'PDepend\\Source\\AST\\ASTTraitUseStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTraitUseStatement.php',
'PDepend\\Source\\AST\\ASTTryStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTryStatement.php',
'PDepend\\Source\\AST\\ASTType' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTType.php',
'PDepend\\Source\\AST\\ASTTypeArray' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTypeArray.php',
'PDepend\\Source\\AST\\ASTTypeCallable' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTypeCallable.php',
'PDepend\\Source\\AST\\ASTTypeIterable' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTTypeIterable.php',
'PDepend\\Source\\AST\\ASTUnaryExpression' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTUnaryExpression.php',
'PDepend\\Source\\AST\\ASTUnsetStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTUnsetStatement.php',
'PDepend\\Source\\AST\\ASTValue' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTValue.php',
'PDepend\\Source\\AST\\ASTVariable' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTVariable.php',
'PDepend\\Source\\AST\\ASTVariableDeclarator' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTVariableDeclarator.php',
'PDepend\\Source\\AST\\ASTVariableVariable' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTVariableVariable.php',
'PDepend\\Source\\AST\\ASTWhileStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTWhileStatement.php',
'PDepend\\Source\\AST\\ASTYieldStatement' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/ASTYieldStatement.php',
'PDepend\\Source\\AST\\AbstractASTArtifact' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTArtifact.php',
'PDepend\\Source\\AST\\AbstractASTCallable' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTCallable.php',
'PDepend\\Source\\AST\\AbstractASTClassOrInterface' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTClassOrInterface.php',
'PDepend\\Source\\AST\\AbstractASTNode' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTNode.php',
'PDepend\\Source\\AST\\AbstractASTType' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/AbstractASTType.php',
'PDepend\\Source\\AST\\State' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/AST/State.php',
'PDepend\\Source\\Builder\\Builder' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Builder/Builder.php',
'PDepend\\Source\\Builder\\BuilderContext' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Builder/BuilderContext.php',
'PDepend\\Source\\Builder\\BuilderContext\\GlobalBuilderContext' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Builder/BuilderContext/GlobalBuilderContext.php',
'PDepend\\Source\\Language\\PHP\\AbstractPHPParser' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/AbstractPHPParser.php',
'PDepend\\Source\\Language\\PHP\\PHPBuilder' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPBuilder.php',
'PDepend\\Source\\Language\\PHP\\PHPParserGeneric' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserGeneric.php',
'PDepend\\Source\\Language\\PHP\\PHPParserVersion53' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion53.php',
'PDepend\\Source\\Language\\PHP\\PHPParserVersion54' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion54.php',
'PDepend\\Source\\Language\\PHP\\PHPParserVersion55' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion55.php',
'PDepend\\Source\\Language\\PHP\\PHPParserVersion56' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion56.php',
'PDepend\\Source\\Language\\PHP\\PHPParserVersion70' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion70.php',
'PDepend\\Source\\Language\\PHP\\PHPParserVersion71' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion71.php',
'PDepend\\Source\\Language\\PHP\\PHPParserVersion72' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion72.php',
'PDepend\\Source\\Language\\PHP\\PHPParserVersion73' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion73.php',
'PDepend\\Source\\Language\\PHP\\PHPParserVersion74' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPParserVersion74.php',
'PDepend\\Source\\Language\\PHP\\PHPTokenizerInternal' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Language/PHP/PHPTokenizerInternal.php',
'PDepend\\Source\\Parser\\InvalidStateException' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Parser/InvalidStateException.php',
'PDepend\\Source\\Parser\\MissingValueException' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Parser/MissingValueException.php',
'PDepend\\Source\\Parser\\NoActiveScopeException' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Parser/NoActiveScopeException.php',
'PDepend\\Source\\Parser\\ParserException' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Parser/ParserException.php',
'PDepend\\Source\\Parser\\SymbolTable' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Parser/SymbolTable.php',
'PDepend\\Source\\Parser\\TokenException' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Parser/TokenException.php',
'PDepend\\Source\\Parser\\TokenStack' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Parser/TokenStack.php',
'PDepend\\Source\\Parser\\TokenStreamEndException' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Parser/TokenStreamEndException.php',
'PDepend\\Source\\Parser\\UnexpectedTokenException' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Parser/UnexpectedTokenException.php',
'PDepend\\Source\\Tokenizer\\FullTokenizer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Tokenizer/FullTokenizer.php',
'PDepend\\Source\\Tokenizer\\Token' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Tokenizer/Token.php',
'PDepend\\Source\\Tokenizer\\Tokenizer' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Tokenizer/Tokenizer.php',
'PDepend\\Source\\Tokenizer\\Tokens' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Source/Tokenizer/Tokens.php',
'PDepend\\TextUI\\Command' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/TextUI/Command.php',
'PDepend\\TextUI\\ResultPrinter' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/TextUI/ResultPrinter.php',
'PDepend\\TextUI\\Runner' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/TextUI/Runner.php',
'PDepend\\Util\\Cache\\CacheDriver' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/Cache/CacheDriver.php',
'PDepend\\Util\\Cache\\CacheFactory' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/Cache/CacheFactory.php',
'PDepend\\Util\\Cache\\Driver\\FileCacheDriver' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/Cache/Driver/FileCacheDriver.php',
'PDepend\\Util\\Cache\\Driver\\File\\FileCacheDirectory' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/Cache/Driver/File/FileCacheDirectory.php',
'PDepend\\Util\\Cache\\Driver\\File\\FileCacheGarbageCollector' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/Cache/Driver/File/FileCacheGarbageCollector.php',
'PDepend\\Util\\Cache\\Driver\\MemoryCacheDriver' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/Cache/Driver/MemoryCacheDriver.php',
'PDepend\\Util\\Configuration' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/Configuration.php',
'PDepend\\Util\\ConfigurationInstance' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/ConfigurationInstance.php',
'PDepend\\Util\\Coverage\\CloverReport' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/Coverage/CloverReport.php',
'PDepend\\Util\\Coverage\\Factory' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/Coverage/Factory.php',
'PDepend\\Util\\Coverage\\Report' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/Coverage/Report.php',
'PDepend\\Util\\FileUtil' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/FileUtil.php',
'PDepend\\Util\\IdBuilder' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/IdBuilder.php',
'PDepend\\Util\\ImageConvert' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/ImageConvert.php',
'PDepend\\Util\\Log' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/Log.php',
'PDepend\\Util\\MathUtil' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/MathUtil.php',
'PDepend\\Util\\Type' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/Type.php',
'PDepend\\Util\\Utf8Util' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/Utf8Util.php',
'PDepend\\Util\\Workarounds' => $vendorDir . '/pdepend/pdepend/src/main/php/PDepend/Util/Workarounds.php',
'PHPMD\\AbstractNode' => $baseDir . '/src/main/php/PHPMD/AbstractNode.php',
'PHPMD\\AbstractRenderer' => $baseDir . '/src/main/php/PHPMD/AbstractRenderer.php',
'PHPMD\\AbstractRule' => $baseDir . '/src/main/php/PHPMD/AbstractRule.php',
'PHPMD\\AbstractWriter' => $baseDir . '/src/main/php/PHPMD/AbstractWriter.php',
'PHPMD\\Exception\\RuleClassFileNotFoundException' => $baseDir . '/src/main/php/PHPMD/Exception/RuleClassFileNotFoundException.php',
'PHPMD\\Exception\\RuleClassNotFoundException' => $baseDir . '/src/main/php/PHPMD/Exception/RuleClassNotFoundException.php',
'PHPMD\\Exception\\RuleSetNotFoundException' => $baseDir . '/src/main/php/PHPMD/Exception/RuleSetNotFoundException.php',
'PHPMD\\Node\\ASTNode' => $baseDir . '/src/main/php/PHPMD/Node/ASTNode.php',
'PHPMD\\Node\\AbstractCallableNode' => $baseDir . '/src/main/php/PHPMD/Node/AbstractCallableNode.php',
'PHPMD\\Node\\AbstractNode' => $baseDir . '/src/main/php/PHPMD/Node/AbstractNode.php',
'PHPMD\\Node\\AbstractTypeNode' => $baseDir . '/src/main/php/PHPMD/Node/AbstractTypeNode.php',
'PHPMD\\Node\\Annotation' => $baseDir . '/src/main/php/PHPMD/Node/Annotation.php',
'PHPMD\\Node\\Annotations' => $baseDir . '/src/main/php/PHPMD/Node/Annotations.php',
'PHPMD\\Node\\ClassNode' => $baseDir . '/src/main/php/PHPMD/Node/ClassNode.php',
'PHPMD\\Node\\FunctionNode' => $baseDir . '/src/main/php/PHPMD/Node/FunctionNode.php',
'PHPMD\\Node\\InterfaceNode' => $baseDir . '/src/main/php/PHPMD/Node/InterfaceNode.php',
'PHPMD\\Node\\MethodNode' => $baseDir . '/src/main/php/PHPMD/Node/MethodNode.php',
'PHPMD\\Node\\TraitNode' => $baseDir . '/src/main/php/PHPMD/Node/TraitNode.php',
'PHPMD\\PHPMD' => $baseDir . '/src/main/php/PHPMD/PHPMD.php',
'PHPMD\\Parser' => $baseDir . '/src/main/php/PHPMD/Parser.php',
'PHPMD\\ParserFactory' => $baseDir . '/src/main/php/PHPMD/ParserFactory.php',
'PHPMD\\ProcessingError' => $baseDir . '/src/main/php/PHPMD/ProcessingError.php',
'PHPMD\\Renderer\\AnsiRenderer' => $baseDir . '/src/main/php/PHPMD/Renderer/AnsiRenderer.php',
'PHPMD\\Renderer\\HTMLRenderer' => $baseDir . '/src/main/php/PHPMD/Renderer/HTMLRenderer.php',
'PHPMD\\Renderer\\JSONRenderer' => $baseDir . '/src/main/php/PHPMD/Renderer/JSONRenderer.php',
'PHPMD\\Renderer\\TextRenderer' => $baseDir . '/src/main/php/PHPMD/Renderer/TextRenderer.php',
'PHPMD\\Renderer\\XMLRenderer' => $baseDir . '/src/main/php/PHPMD/Renderer/XMLRenderer.php',
'PHPMD\\Report' => $baseDir . '/src/main/php/PHPMD/Report.php',
'PHPMD\\Rule' => $baseDir . '/src/main/php/PHPMD/Rule.php',
'PHPMD\\RuleSet' => $baseDir . '/src/main/php/PHPMD/RuleSet.php',
'PHPMD\\RuleSetFactory' => $baseDir . '/src/main/php/PHPMD/RuleSetFactory.php',
'PHPMD\\RuleViolation' => $baseDir . '/src/main/php/PHPMD/RuleViolation.php',
'PHPMD\\Rule\\AbstractLocalVariable' => $baseDir . '/src/main/php/PHPMD/Rule/AbstractLocalVariable.php',
'PHPMD\\Rule\\ClassAware' => $baseDir . '/src/main/php/PHPMD/Rule/ClassAware.php',
'PHPMD\\Rule\\CleanCode\\BooleanArgumentFlag' => $baseDir . '/src/main/php/PHPMD/Rule/CleanCode/BooleanArgumentFlag.php',
'PHPMD\\Rule\\CleanCode\\DuplicatedArrayKey' => $baseDir . '/src/main/php/PHPMD/Rule/CleanCode/DuplicatedArrayKey.php',
'PHPMD\\Rule\\CleanCode\\ElseExpression' => $baseDir . '/src/main/php/PHPMD/Rule/CleanCode/ElseExpression.php',
'PHPMD\\Rule\\CleanCode\\ErrorControlOperator' => $baseDir . '/src/main/php/PHPMD/Rule/CleanCode/ErrorControlOperator.php',
'PHPMD\\Rule\\CleanCode\\IfStatementAssignment' => $baseDir . '/src/main/php/PHPMD/Rule/CleanCode/IfStatementAssignment.php',
'PHPMD\\Rule\\CleanCode\\MissingImport' => $baseDir . '/src/main/php/PHPMD/Rule/CleanCode/MissingImport.php',
'PHPMD\\Rule\\CleanCode\\StaticAccess' => $baseDir . '/src/main/php/PHPMD/Rule/CleanCode/StaticAccess.php',
'PHPMD\\Rule\\CleanCode\\UndefinedVariable' => $baseDir . '/src/main/php/PHPMD/Rule/CleanCode/UndefinedVariable.php',
'PHPMD\\Rule\\Controversial\\CamelCaseClassName' => $baseDir . '/src/main/php/PHPMD/Rule/Controversial/CamelCaseClassName.php',
'PHPMD\\Rule\\Controversial\\CamelCaseMethodName' => $baseDir . '/src/main/php/PHPMD/Rule/Controversial/CamelCaseMethodName.php',
'PHPMD\\Rule\\Controversial\\CamelCaseParameterName' => $baseDir . '/src/main/php/PHPMD/Rule/Controversial/CamelCaseParameterName.php',
'PHPMD\\Rule\\Controversial\\CamelCasePropertyName' => $baseDir . '/src/main/php/PHPMD/Rule/Controversial/CamelCasePropertyName.php',
'PHPMD\\Rule\\Controversial\\CamelCaseVariableName' => $baseDir . '/src/main/php/PHPMD/Rule/Controversial/CamelCaseVariableName.php',
'PHPMD\\Rule\\Controversial\\Superglobals' => $baseDir . '/src/main/php/PHPMD/Rule/Controversial/Superglobals.php',
'PHPMD\\Rule\\CyclomaticComplexity' => $baseDir . '/src/main/php/PHPMD/Rule/CyclomaticComplexity.php',
'PHPMD\\Rule\\Design\\CountInLoopExpression' => $baseDir . '/src/main/php/PHPMD/Rule/Design/CountInLoopExpression.php',
'PHPMD\\Rule\\Design\\CouplingBetweenObjects' => $baseDir . '/src/main/php/PHPMD/Rule/Design/CouplingBetweenObjects.php',
'PHPMD\\Rule\\Design\\DepthOfInheritance' => $baseDir . '/src/main/php/PHPMD/Rule/Design/DepthOfInheritance.php',
'PHPMD\\Rule\\Design\\DevelopmentCodeFragment' => $baseDir . '/src/main/php/PHPMD/Rule/Design/DevelopmentCodeFragment.php',
'PHPMD\\Rule\\Design\\EmptyCatchBlock' => $baseDir . '/src/main/php/PHPMD/Rule/Design/EmptyCatchBlock.php',
'PHPMD\\Rule\\Design\\EvalExpression' => $baseDir . '/src/main/php/PHPMD/Rule/Design/EvalExpression.php',
'PHPMD\\Rule\\Design\\ExitExpression' => $baseDir . '/src/main/php/PHPMD/Rule/Design/ExitExpression.php',
'PHPMD\\Rule\\Design\\GotoStatement' => $baseDir . '/src/main/php/PHPMD/Rule/Design/GotoStatement.php',
'PHPMD\\Rule\\Design\\LongClass' => $baseDir . '/src/main/php/PHPMD/Rule/Design/LongClass.php',
'PHPMD\\Rule\\Design\\LongMethod' => $baseDir . '/src/main/php/PHPMD/Rule/Design/LongMethod.php',
'PHPMD\\Rule\\Design\\LongParameterList' => $baseDir . '/src/main/php/PHPMD/Rule/Design/LongParameterList.php',
'PHPMD\\Rule\\Design\\NpathComplexity' => $baseDir . '/src/main/php/PHPMD/Rule/Design/NpathComplexity.php',
'PHPMD\\Rule\\Design\\NumberOfChildren' => $baseDir . '/src/main/php/PHPMD/Rule/Design/NumberOfChildren.php',
'PHPMD\\Rule\\Design\\TooManyFields' => $baseDir . '/src/main/php/PHPMD/Rule/Design/TooManyFields.php',
'PHPMD\\Rule\\Design\\TooManyMethods' => $baseDir . '/src/main/php/PHPMD/Rule/Design/TooManyMethods.php',
'PHPMD\\Rule\\Design\\TooManyPublicMethods' => $baseDir . '/src/main/php/PHPMD/Rule/Design/TooManyPublicMethods.php',
'PHPMD\\Rule\\Design\\WeightedMethodCount' => $baseDir . '/src/main/php/PHPMD/Rule/Design/WeightedMethodCount.php',
'PHPMD\\Rule\\ExcessivePublicCount' => $baseDir . '/src/main/php/PHPMD/Rule/ExcessivePublicCount.php',
'PHPMD\\Rule\\FunctionAware' => $baseDir . '/src/main/php/PHPMD/Rule/FunctionAware.php',
'PHPMD\\Rule\\InterfaceAware' => $baseDir . '/src/main/php/PHPMD/Rule/InterfaceAware.php',
'PHPMD\\Rule\\MethodAware' => $baseDir . '/src/main/php/PHPMD/Rule/MethodAware.php',
'PHPMD\\Rule\\Naming\\BooleanGetMethodName' => $baseDir . '/src/main/php/PHPMD/Rule/Naming/BooleanGetMethodName.php',
'PHPMD\\Rule\\Naming\\ConstantNamingConventions' => $baseDir . '/src/main/php/PHPMD/Rule/Naming/ConstantNamingConventions.php',
'PHPMD\\Rule\\Naming\\ConstructorWithNameAsEnclosingClass' => $baseDir . '/src/main/php/PHPMD/Rule/Naming/ConstructorWithNameAsEnclosingClass.php',
'PHPMD\\Rule\\Naming\\LongClassName' => $baseDir . '/src/main/php/PHPMD/Rule/Naming/LongClassName.php',
'PHPMD\\Rule\\Naming\\LongVariable' => $baseDir . '/src/main/php/PHPMD/Rule/Naming/LongVariable.php',
'PHPMD\\Rule\\Naming\\ShortClassName' => $baseDir . '/src/main/php/PHPMD/Rule/Naming/ShortClassName.php',
'PHPMD\\Rule\\Naming\\ShortMethodName' => $baseDir . '/src/main/php/PHPMD/Rule/Naming/ShortMethodName.php',
'PHPMD\\Rule\\Naming\\ShortVariable' => $baseDir . '/src/main/php/PHPMD/Rule/Naming/ShortVariable.php',
'PHPMD\\Rule\\UnusedFormalParameter' => $baseDir . '/src/main/php/PHPMD/Rule/UnusedFormalParameter.php',
'PHPMD\\Rule\\UnusedLocalVariable' => $baseDir . '/src/main/php/PHPMD/Rule/UnusedLocalVariable.php',
'PHPMD\\Rule\\UnusedPrivateField' => $baseDir . '/src/main/php/PHPMD/Rule/UnusedPrivateField.php',
'PHPMD\\Rule\\UnusedPrivateMethod' => $baseDir . '/src/main/php/PHPMD/Rule/UnusedPrivateMethod.php',
'PHPMD\\TextUI\\Command' => $baseDir . '/src/main/php/PHPMD/TextUI/Command.php',
'PHPMD\\TextUI\\CommandLineOptions' => $baseDir . '/src/main/php/PHPMD/TextUI/CommandLineOptions.php',
'PHPMD\\Utility\\Strings' => $baseDir . '/src/main/php/PHPMD/Utility/Strings.php',
'PHPMD\\Writer\\StreamWriter' => $baseDir . '/src/main/php/PHPMD/Writer/StreamWriter.php',
'Psr\\Log\\AbstractLogger' => $vendorDir . '/psr/log/Psr/Log/AbstractLogger.php',
'Psr\\Log\\InvalidArgumentException' => $vendorDir . '/psr/log/Psr/Log/InvalidArgumentException.php',
'Psr\\Log\\LogLevel' => $vendorDir . '/psr/log/Psr/Log/LogLevel.php',
'Psr\\Log\\LoggerAwareInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerAwareInterface.php',
'Psr\\Log\\LoggerAwareTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerAwareTrait.php',
'Psr\\Log\\LoggerInterface' => $vendorDir . '/psr/log/Psr/Log/LoggerInterface.php',
'Psr\\Log\\LoggerTrait' => $vendorDir . '/psr/log/Psr/Log/LoggerTrait.php',
'Psr\\Log\\NullLogger' => $vendorDir . '/psr/log/Psr/Log/NullLogger.php',
'Psr\\Log\\Test\\DummyTest' => $vendorDir . '/psr/log/Psr/Log/Test/DummyTest.php',
'Psr\\Log\\Test\\LoggerInterfaceTest' => $vendorDir . '/psr/log/Psr/Log/Test/LoggerInterfaceTest.php',
'Psr\\Log\\Test\\TestLogger' => $vendorDir . '/psr/log/Psr/Log/Test/TestLogger.php',
'Symfony\\Component\\Config\\ConfigCache' => $vendorDir . '/symfony/config/ConfigCache.php',
'Symfony\\Component\\Config\\ConfigCacheFactory' => $vendorDir . '/symfony/config/ConfigCacheFactory.php',
'Symfony\\Component\\Config\\ConfigCacheFactoryInterface' => $vendorDir . '/symfony/config/ConfigCacheFactoryInterface.php',
'Symfony\\Component\\Config\\ConfigCacheInterface' => $vendorDir . '/symfony/config/ConfigCacheInterface.php',
'Symfony\\Component\\Config\\Definition\\ArrayNode' => $vendorDir . '/symfony/config/Definition/ArrayNode.php',
'Symfony\\Component\\Config\\Definition\\BaseNode' => $vendorDir . '/symfony/config/Definition/BaseNode.php',
'Symfony\\Component\\Config\\Definition\\BooleanNode' => $vendorDir . '/symfony/config/Definition/BooleanNode.php',
'Symfony\\Component\\Config\\Definition\\Builder\\ArrayNodeDefinition' => $vendorDir . '/symfony/config/Definition/Builder/ArrayNodeDefinition.php',
'Symfony\\Component\\Config\\Definition\\Builder\\BooleanNodeDefinition' => $vendorDir . '/symfony/config/Definition/Builder/BooleanNodeDefinition.php',
'Symfony\\Component\\Config\\Definition\\Builder\\EnumNodeDefinition' => $vendorDir . '/symfony/config/Definition/Builder/EnumNodeDefinition.php',
'Symfony\\Component\\Config\\Definition\\Builder\\ExprBuilder' => $vendorDir . '/symfony/config/Definition/Builder/ExprBuilder.php',
'Symfony\\Component\\Config\\Definition\\Builder\\FloatNodeDefinition' => $vendorDir . '/symfony/config/Definition/Builder/FloatNodeDefinition.php',
'Symfony\\Component\\Config\\Definition\\Builder\\IntegerNodeDefinition' => $vendorDir . '/symfony/config/Definition/Builder/IntegerNodeDefinition.php',
'Symfony\\Component\\Config\\Definition\\Builder\\MergeBuilder' => $vendorDir . '/symfony/config/Definition/Builder/MergeBuilder.php',
'Symfony\\Component\\Config\\Definition\\Builder\\NodeBuilder' => $vendorDir . '/symfony/config/Definition/Builder/NodeBuilder.php',
'Symfony\\Component\\Config\\Definition\\Builder\\NodeDefinition' => $vendorDir . '/symfony/config/Definition/Builder/NodeDefinition.php',
'Symfony\\Component\\Config\\Definition\\Builder\\NodeParentInterface' => $vendorDir . '/symfony/config/Definition/Builder/NodeParentInterface.php',
'Symfony\\Component\\Config\\Definition\\Builder\\NormalizationBuilder' => $vendorDir . '/symfony/config/Definition/Builder/NormalizationBuilder.php',
'Symfony\\Component\\Config\\Definition\\Builder\\NumericNodeDefinition' => $vendorDir . '/symfony/config/Definition/Builder/NumericNodeDefinition.php',
'Symfony\\Component\\Config\\Definition\\Builder\\ParentNodeDefinitionInterface' => $vendorDir . '/symfony/config/Definition/Builder/ParentNodeDefinitionInterface.php',
'Symfony\\Component\\Config\\Definition\\Builder\\ScalarNodeDefinition' => $vendorDir . '/symfony/config/Definition/Builder/ScalarNodeDefinition.php',
'Symfony\\Component\\Config\\Definition\\Builder\\TreeBuilder' => $vendorDir . '/symfony/config/Definition/Builder/TreeBuilder.php',
'Symfony\\Component\\Config\\Definition\\Builder\\ValidationBuilder' => $vendorDir . '/symfony/config/Definition/Builder/ValidationBuilder.php',
'Symfony\\Component\\Config\\Definition\\Builder\\VariableNodeDefinition' => $vendorDir . '/symfony/config/Definition/Builder/VariableNodeDefinition.php',
'Symfony\\Component\\Config\\Definition\\ConfigurationInterface' => $vendorDir . '/symfony/config/Definition/ConfigurationInterface.php',
'Symfony\\Component\\Config\\Definition\\Dumper\\XmlReferenceDumper' => $vendorDir . '/symfony/config/Definition/Dumper/XmlReferenceDumper.php',
'Symfony\\Component\\Config\\Definition\\Dumper\\YamlReferenceDumper' => $vendorDir . '/symfony/config/Definition/Dumper/YamlReferenceDumper.php',
'Symfony\\Component\\Config\\Definition\\EnumNode' => $vendorDir . '/symfony/config/Definition/EnumNode.php',
'Symfony\\Component\\Config\\Definition\\Exception\\DuplicateKeyException' => $vendorDir . '/symfony/config/Definition/Exception/DuplicateKeyException.php',
'Symfony\\Component\\Config\\Definition\\Exception\\Exception' => $vendorDir . '/symfony/config/Definition/Exception/Exception.php',
'Symfony\\Component\\Config\\Definition\\Exception\\ForbiddenOverwriteException' => $vendorDir . '/symfony/config/Definition/Exception/ForbiddenOverwriteException.php',
'Symfony\\Component\\Config\\Definition\\Exception\\InvalidConfigurationException' => $vendorDir . '/symfony/config/Definition/Exception/InvalidConfigurationException.php',
'Symfony\\Component\\Config\\Definition\\Exception\\InvalidDefinitionException' => $vendorDir . '/symfony/config/Definition/Exception/InvalidDefinitionException.php',
'Symfony\\Component\\Config\\Definition\\Exception\\InvalidTypeException' => $vendorDir . '/symfony/config/Definition/Exception/InvalidTypeException.php',
'Symfony\\Component\\Config\\Definition\\Exception\\UnsetKeyException' => $vendorDir . '/symfony/config/Definition/Exception/UnsetKeyException.php',
'Symfony\\Component\\Config\\Definition\\FloatNode' => $vendorDir . '/symfony/config/Definition/FloatNode.php',
'Symfony\\Component\\Config\\Definition\\IntegerNode' => $vendorDir . '/symfony/config/Definition/IntegerNode.php',
'Symfony\\Component\\Config\\Definition\\NodeInterface' => $vendorDir . '/symfony/config/Definition/NodeInterface.php',
'Symfony\\Component\\Config\\Definition\\NumericNode' => $vendorDir . '/symfony/config/Definition/NumericNode.php',
'Symfony\\Component\\Config\\Definition\\Processor' => $vendorDir . '/symfony/config/Definition/Processor.php',
'Symfony\\Component\\Config\\Definition\\PrototypeNodeInterface' => $vendorDir . '/symfony/config/Definition/PrototypeNodeInterface.php',
'Symfony\\Component\\Config\\Definition\\PrototypedArrayNode' => $vendorDir . '/symfony/config/Definition/PrototypedArrayNode.php',
'Symfony\\Component\\Config\\Definition\\ReferenceDumper' => $vendorDir . '/symfony/config/Definition/ReferenceDumper.php',
'Symfony\\Component\\Config\\Definition\\ScalarNode' => $vendorDir . '/symfony/config/Definition/ScalarNode.php',
'Symfony\\Component\\Config\\Definition\\VariableNode' => $vendorDir . '/symfony/config/Definition/VariableNode.php',
'Symfony\\Component\\Config\\Exception\\FileLoaderImportCircularReferenceException' => $vendorDir . '/symfony/config/Exception/FileLoaderImportCircularReferenceException.php',
'Symfony\\Component\\Config\\Exception\\FileLoaderLoadException' => $vendorDir . '/symfony/config/Exception/FileLoaderLoadException.php',
'Symfony\\Component\\Config\\FileLocator' => $vendorDir . '/symfony/config/FileLocator.php',
'Symfony\\Component\\Config\\FileLocatorInterface' => $vendorDir . '/symfony/config/FileLocatorInterface.php',
'Symfony\\Component\\Config\\Loader\\DelegatingLoader' => $vendorDir . '/symfony/config/Loader/DelegatingLoader.php',
'Symfony\\Component\\Config\\Loader\\FileLoader' => $vendorDir . '/symfony/config/Loader/FileLoader.php',
'Symfony\\Component\\Config\\Loader\\Loader' => $vendorDir . '/symfony/config/Loader/Loader.php',
'Symfony\\Component\\Config\\Loader\\LoaderInterface' => $vendorDir . '/symfony/config/Loader/LoaderInterface.php',
'Symfony\\Component\\Config\\Loader\\LoaderResolver' => $vendorDir . '/symfony/config/Loader/LoaderResolver.php',
'Symfony\\Component\\Config\\Loader\\LoaderResolverInterface' => $vendorDir . '/symfony/config/Loader/LoaderResolverInterface.php',
'Symfony\\Component\\Config\\ResourceCheckerConfigCache' => $vendorDir . '/symfony/config/ResourceCheckerConfigCache.php',
'Symfony\\Component\\Config\\ResourceCheckerConfigCacheFactory' => $vendorDir . '/symfony/config/ResourceCheckerConfigCacheFactory.php',
'Symfony\\Component\\Config\\ResourceCheckerInterface' => $vendorDir . '/symfony/config/ResourceCheckerInterface.php',
'Symfony\\Component\\Config\\Resource\\BCResourceInterfaceChecker' => $vendorDir . '/symfony/config/Resource/BCResourceInterfaceChecker.php',
'Symfony\\Component\\Config\\Resource\\DirectoryResource' => $vendorDir . '/symfony/config/Resource/DirectoryResource.php',
'Symfony\\Component\\Config\\Resource\\FileExistenceResource' => $vendorDir . '/symfony/config/Resource/FileExistenceResource.php',
'Symfony\\Component\\Config\\Resource\\FileResource' => $vendorDir . '/symfony/config/Resource/FileResource.php',
'Symfony\\Component\\Config\\Resource\\ResourceInterface' => $vendorDir . '/symfony/config/Resource/ResourceInterface.php',
'Symfony\\Component\\Config\\Resource\\SelfCheckingResourceChecker' => $vendorDir . '/symfony/config/Resource/SelfCheckingResourceChecker.php',
'Symfony\\Component\\Config\\Resource\\SelfCheckingResourceInterface' => $vendorDir . '/symfony/config/Resource/SelfCheckingResourceInterface.php',
'Symfony\\Component\\Config\\Util\\XmlUtils' => $vendorDir . '/symfony/config/Util/XmlUtils.php',
'Symfony\\Component\\DependencyInjection\\Alias' => $vendorDir . '/symfony/dependency-injection/Alias.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\AnalyzeServiceReferencesPass' => $vendorDir . '/symfony/dependency-injection/Compiler/AnalyzeServiceReferencesPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\AutoAliasServicePass' => $vendorDir . '/symfony/dependency-injection/Compiler/AutoAliasServicePass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\AutowirePass' => $vendorDir . '/symfony/dependency-injection/Compiler/AutowirePass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\CheckCircularReferencesPass' => $vendorDir . '/symfony/dependency-injection/Compiler/CheckCircularReferencesPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\CheckDefinitionValidityPass' => $vendorDir . '/symfony/dependency-injection/Compiler/CheckDefinitionValidityPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\CheckExceptionOnInvalidReferenceBehaviorPass' => $vendorDir . '/symfony/dependency-injection/Compiler/CheckExceptionOnInvalidReferenceBehaviorPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\CheckReferenceValidityPass' => $vendorDir . '/symfony/dependency-injection/Compiler/CheckReferenceValidityPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\Compiler' => $vendorDir . '/symfony/dependency-injection/Compiler/Compiler.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface' => $vendorDir . '/symfony/dependency-injection/Compiler/CompilerPassInterface.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\DecoratorServicePass' => $vendorDir . '/symfony/dependency-injection/Compiler/DecoratorServicePass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\ExtensionCompilerPass' => $vendorDir . '/symfony/dependency-injection/Compiler/ExtensionCompilerPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\InlineServiceDefinitionsPass' => $vendorDir . '/symfony/dependency-injection/Compiler/InlineServiceDefinitionsPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\LoggingFormatter' => $vendorDir . '/symfony/dependency-injection/Compiler/LoggingFormatter.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\MergeExtensionConfigurationPass' => $vendorDir . '/symfony/dependency-injection/Compiler/MergeExtensionConfigurationPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\PassConfig' => $vendorDir . '/symfony/dependency-injection/Compiler/PassConfig.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\RemoveAbstractDefinitionsPass' => $vendorDir . '/symfony/dependency-injection/Compiler/RemoveAbstractDefinitionsPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\RemovePrivateAliasesPass' => $vendorDir . '/symfony/dependency-injection/Compiler/RemovePrivateAliasesPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\RemoveUnusedDefinitionsPass' => $vendorDir . '/symfony/dependency-injection/Compiler/RemoveUnusedDefinitionsPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\RepeatablePassInterface' => $vendorDir . '/symfony/dependency-injection/Compiler/RepeatablePassInterface.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\RepeatedPass' => $vendorDir . '/symfony/dependency-injection/Compiler/RepeatedPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\ReplaceAliasByActualDefinitionPass' => $vendorDir . '/symfony/dependency-injection/Compiler/ReplaceAliasByActualDefinitionPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\ResolveDefinitionTemplatesPass' => $vendorDir . '/symfony/dependency-injection/Compiler/ResolveDefinitionTemplatesPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\ResolveInvalidReferencesPass' => $vendorDir . '/symfony/dependency-injection/Compiler/ResolveInvalidReferencesPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\ResolveParameterPlaceHoldersPass' => $vendorDir . '/symfony/dependency-injection/Compiler/ResolveParameterPlaceHoldersPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\ResolveReferencesToAliasesPass' => $vendorDir . '/symfony/dependency-injection/Compiler/ResolveReferencesToAliasesPass.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\ServiceReferenceGraph' => $vendorDir . '/symfony/dependency-injection/Compiler/ServiceReferenceGraph.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\ServiceReferenceGraphEdge' => $vendorDir . '/symfony/dependency-injection/Compiler/ServiceReferenceGraphEdge.php',
'Symfony\\Component\\DependencyInjection\\Compiler\\ServiceReferenceGraphNode' => $vendorDir . '/symfony/dependency-injection/Compiler/ServiceReferenceGraphNode.php',
'Symfony\\Component\\DependencyInjection\\Container' => $vendorDir . '/symfony/dependency-injection/Container.php',
'Symfony\\Component\\DependencyInjection\\ContainerAware' => $vendorDir . '/symfony/dependency-injection/ContainerAware.php',
'Symfony\\Component\\DependencyInjection\\ContainerAwareInterface' => $vendorDir . '/symfony/dependency-injection/ContainerAwareInterface.php',
'Symfony\\Component\\DependencyInjection\\ContainerAwareTrait' => $vendorDir . '/symfony/dependency-injection/ContainerAwareTrait.php',
'Symfony\\Component\\DependencyInjection\\ContainerBuilder' => $vendorDir . '/symfony/dependency-injection/ContainerBuilder.php',
'Symfony\\Component\\DependencyInjection\\ContainerInterface' => $vendorDir . '/symfony/dependency-injection/ContainerInterface.php',
'Symfony\\Component\\DependencyInjection\\Definition' => $vendorDir . '/symfony/dependency-injection/Definition.php',
'Symfony\\Component\\DependencyInjection\\DefinitionDecorator' => $vendorDir . '/symfony/dependency-injection/DefinitionDecorator.php',
'Symfony\\Component\\DependencyInjection\\Dumper\\Dumper' => $vendorDir . '/symfony/dependency-injection/Dumper/Dumper.php',
'Symfony\\Component\\DependencyInjection\\Dumper\\DumperInterface' => $vendorDir . '/symfony/dependency-injection/Dumper/DumperInterface.php',
'Symfony\\Component\\DependencyInjection\\Dumper\\GraphvizDumper' => $vendorDir . '/symfony/dependency-injection/Dumper/GraphvizDumper.php',
'Symfony\\Component\\DependencyInjection\\Dumper\\PhpDumper' => $vendorDir . '/symfony/dependency-injection/Dumper/PhpDumper.php',
'Symfony\\Component\\DependencyInjection\\Dumper\\XmlDumper' => $vendorDir . '/symfony/dependency-injection/Dumper/XmlDumper.php',
'Symfony\\Component\\DependencyInjection\\Dumper\\YamlDumper' => $vendorDir . '/symfony/dependency-injection/Dumper/YamlDumper.php',
'Symfony\\Component\\DependencyInjection\\Exception\\BadMethodCallException' => $vendorDir . '/symfony/dependency-injection/Exception/BadMethodCallException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/dependency-injection/Exception/ExceptionInterface.php',
'Symfony\\Component\\DependencyInjection\\Exception\\InactiveScopeException' => $vendorDir . '/symfony/dependency-injection/Exception/InactiveScopeException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\InvalidArgumentException' => $vendorDir . '/symfony/dependency-injection/Exception/InvalidArgumentException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\LogicException' => $vendorDir . '/symfony/dependency-injection/Exception/LogicException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\OutOfBoundsException' => $vendorDir . '/symfony/dependency-injection/Exception/OutOfBoundsException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\ParameterCircularReferenceException' => $vendorDir . '/symfony/dependency-injection/Exception/ParameterCircularReferenceException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\ParameterNotFoundException' => $vendorDir . '/symfony/dependency-injection/Exception/ParameterNotFoundException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\RuntimeException' => $vendorDir . '/symfony/dependency-injection/Exception/RuntimeException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\ScopeCrossingInjectionException' => $vendorDir . '/symfony/dependency-injection/Exception/ScopeCrossingInjectionException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\ScopeWideningInjectionException' => $vendorDir . '/symfony/dependency-injection/Exception/ScopeWideningInjectionException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\ServiceCircularReferenceException' => $vendorDir . '/symfony/dependency-injection/Exception/ServiceCircularReferenceException.php',
'Symfony\\Component\\DependencyInjection\\Exception\\ServiceNotFoundException' => $vendorDir . '/symfony/dependency-injection/Exception/ServiceNotFoundException.php',
'Symfony\\Component\\DependencyInjection\\ExpressionLanguage' => $vendorDir . '/symfony/dependency-injection/ExpressionLanguage.php',
'Symfony\\Component\\DependencyInjection\\ExpressionLanguageProvider' => $vendorDir . '/symfony/dependency-injection/ExpressionLanguageProvider.php',
'Symfony\\Component\\DependencyInjection\\Extension\\ConfigurationExtensionInterface' => $vendorDir . '/symfony/dependency-injection/Extension/ConfigurationExtensionInterface.php',
'Symfony\\Component\\DependencyInjection\\Extension\\Extension' => $vendorDir . '/symfony/dependency-injection/Extension/Extension.php',
'Symfony\\Component\\DependencyInjection\\Extension\\ExtensionInterface' => $vendorDir . '/symfony/dependency-injection/Extension/ExtensionInterface.php',
'Symfony\\Component\\DependencyInjection\\Extension\\PrependExtensionInterface' => $vendorDir . '/symfony/dependency-injection/Extension/PrependExtensionInterface.php',
'Symfony\\Component\\DependencyInjection\\IntrospectableContainerInterface' => $vendorDir . '/symfony/dependency-injection/IntrospectableContainerInterface.php',
'Symfony\\Component\\DependencyInjection\\LazyProxy\\Instantiator\\InstantiatorInterface' => $vendorDir . '/symfony/dependency-injection/LazyProxy/Instantiator/InstantiatorInterface.php',
'Symfony\\Component\\DependencyInjection\\LazyProxy\\Instantiator\\RealServiceInstantiator' => $vendorDir . '/symfony/dependency-injection/LazyProxy/Instantiator/RealServiceInstantiator.php',
'Symfony\\Component\\DependencyInjection\\LazyProxy\\PhpDumper\\DumperInterface' => $vendorDir . '/symfony/dependency-injection/LazyProxy/PhpDumper/DumperInterface.php',
'Symfony\\Component\\DependencyInjection\\LazyProxy\\PhpDumper\\NullDumper' => $vendorDir . '/symfony/dependency-injection/LazyProxy/PhpDumper/NullDumper.php',
'Symfony\\Component\\DependencyInjection\\Loader\\ClosureLoader' => $vendorDir . '/symfony/dependency-injection/Loader/ClosureLoader.php',
'Symfony\\Component\\DependencyInjection\\Loader\\DirectoryLoader' => $vendorDir . '/symfony/dependency-injection/Loader/DirectoryLoader.php',
'Symfony\\Component\\DependencyInjection\\Loader\\FileLoader' => $vendorDir . '/symfony/dependency-injection/Loader/FileLoader.php',
'Symfony\\Component\\DependencyInjection\\Loader\\IniFileLoader' => $vendorDir . '/symfony/dependency-injection/Loader/IniFileLoader.php',
'Symfony\\Component\\DependencyInjection\\Loader\\PhpFileLoader' => $vendorDir . '/symfony/dependency-injection/Loader/PhpFileLoader.php',
'Symfony\\Component\\DependencyInjection\\Loader\\XmlFileLoader' => $vendorDir . '/symfony/dependency-injection/Loader/XmlFileLoader.php',
'Symfony\\Component\\DependencyInjection\\Loader\\YamlFileLoader' => $vendorDir . '/symfony/dependency-injection/Loader/YamlFileLoader.php',
'Symfony\\Component\\DependencyInjection\\Parameter' => $vendorDir . '/symfony/dependency-injection/Parameter.php',
'Symfony\\Component\\DependencyInjection\\ParameterBag\\FrozenParameterBag' => $vendorDir . '/symfony/dependency-injection/ParameterBag/FrozenParameterBag.php',
'Symfony\\Component\\DependencyInjection\\ParameterBag\\ParameterBag' => $vendorDir . '/symfony/dependency-injection/ParameterBag/ParameterBag.php',
'Symfony\\Component\\DependencyInjection\\ParameterBag\\ParameterBagInterface' => $vendorDir . '/symfony/dependency-injection/ParameterBag/ParameterBagInterface.php',
'Symfony\\Component\\DependencyInjection\\Reference' => $vendorDir . '/symfony/dependency-injection/Reference.php',
'Symfony\\Component\\DependencyInjection\\ResettableContainerInterface' => $vendorDir . '/symfony/dependency-injection/ResettableContainerInterface.php',
'Symfony\\Component\\DependencyInjection\\Scope' => $vendorDir . '/symfony/dependency-injection/Scope.php',
'Symfony\\Component\\DependencyInjection\\ScopeInterface' => $vendorDir . '/symfony/dependency-injection/ScopeInterface.php',
'Symfony\\Component\\DependencyInjection\\SimpleXMLElement' => $vendorDir . '/symfony/dependency-injection/SimpleXMLElement.php',
'Symfony\\Component\\DependencyInjection\\TaggedContainerInterface' => $vendorDir . '/symfony/dependency-injection/TaggedContainerInterface.php',
'Symfony\\Component\\DependencyInjection\\Variable' => $vendorDir . '/symfony/dependency-injection/Variable.php',
'Symfony\\Component\\Filesystem\\Exception\\ExceptionInterface' => $vendorDir . '/symfony/filesystem/Exception/ExceptionInterface.php',
'Symfony\\Component\\Filesystem\\Exception\\FileNotFoundException' => $vendorDir . '/symfony/filesystem/Exception/FileNotFoundException.php',
'Symfony\\Component\\Filesystem\\Exception\\IOException' => $vendorDir . '/symfony/filesystem/Exception/IOException.php',
'Symfony\\Component\\Filesystem\\Exception\\IOExceptionInterface' => $vendorDir . '/symfony/filesystem/Exception/IOExceptionInterface.php',
'Symfony\\Component\\Filesystem\\Filesystem' => $vendorDir . '/symfony/filesystem/Filesystem.php',
'Symfony\\Component\\Filesystem\\LockHandler' => $vendorDir . '/symfony/filesystem/LockHandler.php',
'Symfony\\Polyfill\\Ctype\\Ctype' => $vendorDir . '/symfony/polyfill-ctype/Ctype.php',
);
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'PHPMD\\' => array($baseDir . '/src/main/php'),
);
Config Component
================
The Config component provides several classes to help you find, load, combine,
autofill and validate configuration values of any kind, whatever their source
may be (YAML, XML, INI files, or for instance a database).
Resources
---------
* [Documentation](https://symfony.com/doc/current/components/config/index.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)
<?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;
/**
* Interface for a ConfigCache factory. This factory creates
* an instance of ConfigCacheInterface and initializes the
* cache if necessary.
*
* @author Matthias Pigulla <mp@webfactory.de>
*/
interface ConfigCacheFactoryInterface
{
/**
* Creates a cache instance and (re-)initializes it if necessary.
*
* @param string $file The absolute cache file path
* @param callable $callable The callable to be executed when the cache needs to be filled (i. e. is not fresh). The cache will be passed as the only parameter to this callback
*
* @return ConfigCacheInterface The cache instance
*/
public function cache($file, $callable);
}
<?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;
/**
* Basic implementation of ConfigCacheFactoryInterface that
* creates an instance of the default ConfigCache.
*
* This factory and/or cache <em>do not</em> support cache validation
* by means of ResourceChecker instances (that is, service-based).
*
* @author Matthias Pigulla <mp@webfactory.de>
*/
class ConfigCacheFactory implements ConfigCacheFactoryInterface
{
private $debug;
/**
* @param bool $debug The debug flag to pass to ConfigCache
*/
public function __construct($debug)
{
$this->debug = $debug;
}
/**
* {@inheritdoc}
*/
public function cache($file, $callback)
{
if (!\is_callable($callback)) {
throw new \InvalidArgumentException(sprintf('Invalid type for callback argument. Expected callable, but got "%s".', \gettype($callback)));
}
$cache = new ConfigCache($file, $this->debug);
if (!$cache->isFresh()) {
\call_user_func($callback, $cache);
}
return $cache;
}
}
<?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;
@trigger_error('The '.__NAMESPACE__.'\ReferenceDumper class is deprecated since Symfony 2.4 and will be removed in 3.0. Use the Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper class instead.', E_USER_DEPRECATED);
use Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper;
/**
* @deprecated since version 2.4, to be removed in 3.0.
* Use {@link \Symfony\Component\Config\Definition\Dumper\YamlReferenceDumper} instead.
*/
class ReferenceDumper extends YamlReferenceDumper
{
}
<?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 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;
public function setDefaultValue($value)
{
$this->defaultValueSet = true;
$this->defaultValue = $value;
}
/**
* {@inheritdoc}
*/
public function hasDefaultValue()
{
return $this->defaultValueSet;
}
/**
* {@inheritdoc}
*/
public function getDefaultValue()
{
$v = $this->defaultValue;
return $v instanceof \Closure ? $v() : $v;
}
/**
* Sets if this node is allowed to have an empty value.
*
* @param bool $boolean True if this entity will accept empty values
*/
public function setAllowEmptyValue($boolean)
{
$this->allowEmptyValue = (bool) $boolean;
}
/**
* {@inheritdoc}
*/
public function setName($name)
{
$this->name = $name;
}
/**
* {@inheritdoc}
*/
protected function validateType($value)
{
}
/**
* {@inheritdoc}
*/
protected function finalizeValue($value)
{
if (!$this->allowEmptyValue && $this->isValueEmpty($value)) {
$ex = new InvalidConfigurationException(sprintf('The path "%s" cannot contain an empty value, but got %s.', $this->getPath(), json_encode($value)));
if ($hint = $this->getInfo()) {
$ex->addHint($hint);
}
$ex->setPath($this->getPath());
throw $ex;
}
return $value;
}
/**
* {@inheritdoc}
*/
protected function normalizeValue($value)
{
return $value;
}
/**
* {@inheritdoc}
*/
protected function mergeValues($leftSide, $rightSide)
{
return $rightSide;
}
/**
* Evaluates if the given value is to be treated as empty.
*
* By default, PHP's empty() function is used to test for emptiness. This
* method may be overridden by subtypes to better match their understanding
* of empty data.
*
* @param mixed $value
*
* @return bool
*/
protected function isValueEmpty($value)
{
return empty($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\ForbiddenOverwriteException;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
/**
* 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 bool If the node is required
*/
public function isRequired();
/**
* Returns true when the node has a default value.
*
* @return bool 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 a value.
*
* @param mixed $value The value to normalize
*
* @return mixed The normalized value
*
* @throws InvalidTypeException if the value type is invalid
*/
public function normalize($value);
/**
* Merges two values together.
*
* @param mixed $leftSide
* @param mixed $rightSide
*
* @return mixed The merged value
*
* @throws ForbiddenOverwriteException if the configuration path cannot be overwritten
* @throws InvalidTypeException if the value type is invalid
*/
public function merge($leftSide, $rightSide);
/**
* Finalizes a value.
*
* @param mixed $value The value to finalize
*
* @return mixed The finalized value
*
* @throws InvalidTypeException if the value type is invalid
* @throws InvalidConfigurationException if the value is invalid configuration
*/
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 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)));
if ($hint = $this->getInfo()) {
$ex->addHint($hint);
}
$ex->setPath($this->getPath());
throw $ex;
}
}
/**
* {@inheritdoc}
*/
protected function isValueEmpty($value)
{
// a boolean value cannot be empty
return false;
}
}
<?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\InvalidDefinitionException;
use Symfony\Component\Config\Definition\NodeInterface;
/**
* 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 = false;
protected $required = false;
protected $merge;
protected $allowEmptyValue = true;
protected $nullEquivalent;
protected $trueEquivalent = true;
protected $falseEquivalent = false;
protected $parent;
protected $attributes = array();
/**
* @param string|null $name The name of the node
* @param NodeParentInterface|null $parent The parent
*/
public function __construct($name, NodeParentInterface $parent = null)
{
$this->parent = $parent;
$this->name = $name;
}
/**
* Sets the parent node.
*
* @return $this
*/
public function setParent(NodeParentInterface $parent)
{
$this->parent = $parent;
return $this;
}
/**
* Sets info message.
*
* @param string $info The info text
*
* @return $this
*/
public function info($info)
{
return $this->attribute('info', $info);
}
/**
* Sets example configuration.
*
* @param string|array $example
*
* @return $this
*/
public function example($example)
{
return $this->attribute('example', $example);
}
/**
* Sets an attribute on the node.
*
* @param string $key
* @param mixed $value
*
* @return $this
*/
public function attribute($key, $value)
{
$this->attributes[$key] = $value;
return $this;
}
/**
* Returns the parent node.
*
* @return NodeParentInterface|NodeBuilder|NodeDefinition|ArrayNodeDefinition|VariableNodeDefinition|null The builder of the parent node
*/
public function end()
{
return $this->parent;
}
/**
* Creates the node.
*
* @param bool $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 $this
*/
public function defaultValue($value)
{
$this->default = true;
$this->defaultValue = $value;
return $this;
}
/**
* Sets the node as required.
*
* @return $this
*/
public function isRequired()
{
$this->required = true;
return $this;
}
/**
* Sets the equivalent value used when the node contains null.
*
* @param mixed $value
*
* @return $this
*/
public function treatNullLike($value)
{
$this->nullEquivalent = $value;
return $this;
}
/**
* Sets the equivalent value used when the node contains true.
*
* @param mixed $value
*
* @return $this
*/
public function treatTrueLike($value)
{
$this->trueEquivalent = $value;
return $this;
}
/**
* Sets the equivalent value used when the node contains false.
*
* @param mixed $value
*
* @return $this
*/
public function treatFalseLike($value)
{
$this->falseEquivalent = $value;
return $this;
}
/**
* Sets null as the default value.
*
* @return $this
*/
public function defaultNull()
{
return $this->defaultValue(null);
}
/**
* Sets true as the default value.
*
* @return $this
*/
public function defaultTrue()
{
return $this->defaultValue(true);
}
/**
* Sets false as the default value.
*
* @return $this
*/
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 $this
*/
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 bool $deny Whether the overwriting is forbidden or not
*
* @return $this
*/
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 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;
/**
* 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;
use Symfony\Component\Config\Definition\ArrayNode;
use Symfony\Component\Config\Definition\Exception\InvalidDefinitionException;
use Symfony\Component\Config\Definition\PrototypedArrayNode;
/**
* 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 = true;
protected $ignoreExtraKeys = false;
protected $removeExtraKeys = true;
protected $children = array();
protected $prototype;
protected $atLeastOne = false;
protected $allowNewKeys = true;
protected $key;
protected $removeKeyItem;
protected $addDefaults = false;
protected $addDefaultChildren = false;
protected $nodeBuilder;
protected $normalizeKeys = true;
/**
* {@inheritdoc}
*/
public function __construct($name, NodeParentInterface $parent = null)
{
parent::__construct($name, $parent);
$this->nullEquivalent = array();
$this->trueEquivalent = array();
}
/**
* {@inheritdoc}
*/
public function setBuilder(NodeBuilder $builder)
{
$this->nodeBuilder = $builder;
}
/**
* {@inheritdoc}
*/
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 $this
*/
public function addDefaultsIfNotSet()
{
$this->addDefaults = true;
return $this;
}
/**
* Adds children with a default value when none are defined.
*
* This method is applicable to prototype nodes only.
*
* @param int|string|array|null $children The number of children|The child name|The children names to be added
*
* @return $this
*/
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 $this
*/
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 $this
*/
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 $this
*/
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 bool $removeKeyItem Whether or not the key item should be removed
*
* @return $this
*/
public function useAttributeAsKey($name, $removeKeyItem = true)
{
$this->key = $name;
$this->removeKeyItem = $removeKeyItem;
return $this;
}
/**
* Sets whether the node can be unset.
*
* @param bool $allow
*
* @return $this
*/
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 $this
*/
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 $this
*/
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 $this
*/
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 and removed from the
* resulting array. 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.
*
* @param bool $remove Whether to remove the extra keys
*
* @return $this
*/
public function ignoreExtraKeys($remove = true)
{
$this->ignoreExtraKeys = true;
$this->removeExtraKeys = $remove;
return $this;
}
/**
* Sets key normalization.
*
* @param bool $bool Whether to enable key normalization
*
* @return $this
*/
public function normalizeKeys($bool)
{
$this->normalizeKeys = (bool) $bool;
return $this;
}
/**
* {@inheritdoc}
*/
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, $this->removeExtraKeys);
$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.
*
* @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.
*
* @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_int($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\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;
}
/**
* {@inheritdoc}
*
* @deprecated Deprecated since version 2.8, to be removed in 3.0.
*/
public function cannotBeEmpty()
{
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
return parent::cannotBeEmpty();
}
/**
* 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;
/**
* Abstract class that contains common code of integer and float node definitions.
*
* @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 $this
*
* @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 $this
*
* @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;
}
/**
* {@inheritdoc}
*
* @deprecated Deprecated since version 2.8, to be removed in 3.0.
*/
public function cannotBeEmpty()
{
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
return parent::cannotBeEmpty();
}
}
<?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 = array();
public function __construct(NodeDefinition $node)
{
$this->node = $node;
}
/**
* Registers a closure to run as normalization or an expression builder to build it if null is provided.
*
* @return ExprBuilder|$this
*/
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\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;
public function __construct(NodeDefinition $node)
{
$this->node = $node;
}
/**
* Marks the expression as being always used.
*
* @return $this
*/
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.
*
* @return $this
*/
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 $this
*/
public function ifString()
{
$this->ifPart = function ($v) { return \is_string($v); };
return $this;
}
/**
* Tests if the value is null.
*
* @return $this
*/
public function ifNull()
{
$this->ifPart = function ($v) { return null === $v; };
return $this;
}
/**
* Tests if the value is an array.
*
* @return $this
*/
public function ifArray()
{
$this->ifPart = function ($v) { return \is_array($v); };
return $this;
}
/**
* Tests if the value is in an array.
*
* @return $this
*/
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.
*
* @return $this
*/
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.
*
* @return $this
*/
public function then(\Closure $closure)
{
$this->thenPart = $closure;
return $this;
}
/**
* Sets a closure returning an empty array.
*
* @return $this
*/
public function thenEmptyArray()
{
$this->thenPart = function ($v) { return array(); };
return $this;
}
/**
* Sets a closure marking the value as invalid at processing time.
*
* if you want to add the value of the node in your message just use a %s placeholder.
*
* @param string $message
*
* @return $this
*
* @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 processing time.
*
* @return $this
*
* @throws UnsetKeyException
*/
public function thenUnset()
{
$this->thenPart = function ($v) { throw new UnsetKeyException('Unsetting key'); };
return $this;
}
/**
* Returns the related node.
*
* @return NodeDefinition|ArrayNodeDefinition|VariableNodeDefinition
*
* @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 self) {
$if = $expr->ifPart;
$then = $expr->thenPart;
$expressions[$k] = function ($v) use ($if, $then) {
return $if($v) ? $then($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;
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;
/**
* This class builds merge conditions.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class MergeBuilder
{
protected $node;
public $allowFalse = false;
public $allowOverwrite = true;
public function __construct(NodeDefinition $node)
{
$this->node = $node;
}
/**
* Sets whether the node can be unset.
*
* @param bool $allow
*
* @return $this
*/
public function allowUnset($allow = true)
{
$this->allowFalse = $allow;
return $this;
}
/**
* Sets whether the node can be overwritten.
*
* @param bool $deny Whether the overwriting is forbidden or not
*
* @return $this
*/
public function denyOverwrite($deny = true)
{
$this->allowOverwrite = !$deny;
return $this;
}
/**
* Returns the related node.
*
* @return NodeDefinition|ArrayNodeDefinition|VariableNodeDefinition
*/
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;
/**
* This class builds normalization conditions.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class NormalizationBuilder
{
protected $node;
public $before = array();
public $remappings = array();
public function __construct(NodeDefinition $node)
{
$this->node = $node;
}
/**
* 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 $this
*/
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.
*
* @return ExprBuilder|$this
*/
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\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;
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.
*
* @return $this
*/
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 NodeDefinition&ParentNodeDefinitionInterface The parent node
*/
public function end()
{
return $this->parent;
}
/**
* Creates a child node.
*
* @param string|null $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()
* ;
*
* @return $this
*/
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 $this
*/
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\EnumNode;
/**
* Enum Node Definition.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class EnumNodeDefinition extends ScalarNodeDefinition
{
private $values;
/**
* @return $this
*/
public function values(array $values)
{
$values = array_unique($values);
if (empty($values)) {
throw new \InvalidArgumentException('->values() must be called with at least one value.');
}
$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;
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\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);
}
$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 nodes which can have children.
*
* @author Victor Berchet <victor@suumit.com>
*/
interface ParentNodeDefinitionInterface
{
/**
* Returns a builder to add children nodes.
*
* @return NodeBuilder
*/
public function children();
/**
* Appends a node definition.
*
* Usage:
*
* $node = $parentNode
* ->children()
* ->scalarNode('foo')->end()
* ->scalarNode('baz')->end()
* ->append($this->getBarNodeDefinition())
* ->end()
* ;
*
* @return $this
*/
public function append(NodeDefinition $node);
/**
* Sets a custom children builder.
*/
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;
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 = array();
protected $children = array();
protected $allowFalse = false;
protected $allowNewKeys = true;
protected $addIfNotSet = false;
protected $performDeepMerging = true;
protected $ignoreExtraKeys = false;
protected $removeExtraKeys = true;
protected $normalizeKeys = true;
public function setNormalizeKeys($normalizeKeys)
{
$this->normalizeKeys = (bool) $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;
}
$normalized = array();
foreach ($value as $k => $v) {
if (false !== strpos($k, '-') && false === strpos($k, '_') && !array_key_exists($normalizedKey = str_replace('-', '_', $k), $value)) {
$normalized[$normalizedKey] = $v;
} else {
$normalized[$k] = $v;
}
}
return $normalized;
}
/**
* 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;
}
/**
* Gets the xml remappings that should be performed.
*
* @return array an array of the form array(array(string, string))
*/
public function getXmlRemappings()
{
return $this->xmlRemappings;
}
/**
* Sets whether to add default values for this array if it has not been
* defined in any of the configuration files.
*
* @param bool $boolean
*/
public function setAddIfNotSet($boolean)
{
$this->addIfNotSet = (bool) $boolean;
}
/**
* Sets whether false is allowed as value indicating that the array should be unset.
*
* @param bool $allow
*/
public function setAllowFalse($allow)
{
$this->allowFalse = (bool) $allow;
}
/**
* Sets whether new keys can be defined in subsequent configurations.
*
* @param bool $allow
*/
public function setAllowNewKeys($allow)
{
$this->allowNewKeys = (bool) $allow;
}
/**
* Sets if deep merging should occur.
*
* @param bool $boolean
*/
public function setPerformDeepMerging($boolean)
{
$this->performDeepMerging = (bool) $boolean;
}
/**
* Whether extra keys should just be ignore without an exception.
*
* @param bool $boolean To allow extra keys
* @param bool $remove To remove extra keys
*/
public function setIgnoreExtraKeys($boolean, $remove = true)
{
$this->ignoreExtraKeys = (bool) $boolean;
$this->removeExtraKeys = $this->ignoreExtraKeys && $remove;
}
/**
* {@inheritdoc}
*/
public function setName($name)
{
$this->name = $name;
}
/**
* {@inheritdoc}
*/
public function hasDefaultValue()
{
return $this->addIfNotSet;
}
/**
* {@inheritdoc}
*/
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.
*
* @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 (!\strlen($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) {
throw new UnsetKeyException(sprintf('Unsetting key for path "%s", value: %s', $this->getPath(), json_encode($value)));
}
foreach ($this->children as $name => $child) {
if (!array_key_exists($name, $value)) {
if ($child->isRequired()) {
$ex = new InvalidConfigurationException(sprintf('The child node "%s" at path "%s" must be configured.', $name, $this->getPath()));
$ex->setPath($this->getPath());
throw $ex;
}
if ($child->hasDefaultValue()) {
$value[$name] = $child->getDefaultValue();
}
continue;
}
try {
$value[$name] = $child->finalize($value[$name]);
} catch (UnsetKeyException $e) {
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)));
if ($hint = $this->getInfo()) {
$ex->addHint($hint);
}
$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 ($value as $name => $val) {
if (isset($this->children[$name])) {
try {
$normalized[$name] = $this->children[$name]->normalize($val);
} catch (UnsetKeyException $e) {
}
unset($value[$name]);
} elseif (!$this->removeExtraKeys) {
$normalized[$name] = $val;
}
}
// if extra fields are present, throw exception
if (\count($value) && !$this->ignoreExtraKeys) {
$ex = new InvalidConfigurationException(sprintf('Unrecognized option%s "%s" under "%s"', 1 === \count($value) ? '' : 's', implode(', ', array_keys($value)), $this->getPath()));
$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;
/**
* 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\Dumper;
use Symfony\Component\Config\Definition\ArrayNode;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\EnumNode;
use Symfony\Component\Config\Definition\NodeInterface;
use Symfony\Component\Config\Definition\PrototypedArrayNode;
/**
* Dumps a XML reference configuration for the given configuration/node instance.
*
* @author Wouter J <waldio.webdesign@gmail.com>
*/
class XmlReferenceDumper
{
private $reference;
public function dump(ConfigurationInterface $configuration, $namespace = null)
{
return $this->dumpNode($configuration->getConfigTreeBuilder()->buildTree(), $namespace);
}
public function dumpNode(NodeInterface $node, $namespace = null)
{
$this->reference = '';
$this->writeNode($node, 0, true, $namespace);
$ref = $this->reference;
$this->reference = null;
return $ref;
}
/**
* @param NodeInterface $node
* @param int $depth
* @param bool $root If the node is the root node
* @param string $namespace The namespace of the node
*/
private function writeNode(NodeInterface $node, $depth = 0, $root = false, $namespace = null)
{
$rootName = ($root ? 'config' : $node->getName());
$rootNamespace = ($namespace ?: ($root ? 'http://example.org/schema/dic/'.$node->getName() : null));
// xml remapping
if ($node->getParent()) {
$remapping = array_filter($node->getParent()->getXmlRemappings(), function ($mapping) use ($rootName) {
return $rootName === $mapping[1];
});
if (\count($remapping)) {
list($singular) = current($remapping);
$rootName = $singular;
}
}
$rootName = str_replace('_', '-', $rootName);
$rootAttributes = array();
$rootAttributeComments = array();
$rootChildren = array();
$rootComments = array();
if ($node instanceof ArrayNode) {
$children = $node->getChildren();
// comments about the root node
if ($rootInfo = $node->getInfo()) {
$rootComments[] = $rootInfo;
}
if ($rootNamespace) {
$rootComments[] = 'Namespace: '.$rootNamespace;
}
// render prototyped nodes
if ($node instanceof PrototypedArrayNode) {
$prototype = $node->getPrototype();
$info = 'prototype';
if (null !== $prototype->getInfo()) {
$info .= ': '.$prototype->getInfo();
}
array_unshift($rootComments, $info);
if ($key = $node->getKeyAttribute()) {
$rootAttributes[$key] = str_replace('-', ' ', $rootName).' '.$key;
}
if ($prototype instanceof ArrayNode) {
$children = $prototype->getChildren();
} else {
if ($prototype->hasDefaultValue()) {
$prototypeValue = $prototype->getDefaultValue();
} else {
switch (\get_class($prototype)) {
case 'Symfony\Component\Config\Definition\ScalarNode':
$prototypeValue = 'scalar value';
break;
case 'Symfony\Component\Config\Definition\FloatNode':
case 'Symfony\Component\Config\Definition\IntegerNode':
$prototypeValue = 'numeric value';
break;
case 'Symfony\Component\Config\Definition\BooleanNode':
$prototypeValue = 'true|false';
break;
case 'Symfony\Component\Config\Definition\EnumNode':
$prototypeValue = implode('|', array_map('json_encode', $prototype->getValues()));
break;
default:
$prototypeValue = 'value';
}
}
}
}
// get attributes and elements
foreach ($children as $child) {
if (!$child instanceof ArrayNode) {
// get attributes
// metadata
$name = str_replace('_', '-', $child->getName());
$value = '%%%%not_defined%%%%'; // use a string which isn't used in the normal world
// comments
$comments = array();
if ($info = $child->getInfo()) {
$comments[] = $info;
}
if ($example = $child->getExample()) {
$comments[] = 'Example: '.$example;
}
if ($child->isRequired()) {
$comments[] = 'Required';
}
if ($child instanceof EnumNode) {
$comments[] = 'One of '.implode('; ', array_map('json_encode', $child->getValues()));
}
if (\count($comments)) {
$rootAttributeComments[$name] = implode(";\n", $comments);
}
// default values
if ($child->hasDefaultValue()) {
$value = $child->getDefaultValue();
}
// append attribute
$rootAttributes[$name] = $value;
} else {
// get elements
$rootChildren[] = $child;
}
}
}
// render comments
// root node comment
if (\count($rootComments)) {
foreach ($rootComments as $comment) {
$this->writeLine('<!-- '.$comment.' -->', $depth);
}
}
// attribute comments
if (\count($rootAttributeComments)) {
foreach ($rootAttributeComments as $attrName => $comment) {
$commentDepth = $depth + 4 + \strlen($attrName) + 2;
$commentLines = explode("\n", $comment);
$multiline = (\count($commentLines) > 1);
$comment = implode(PHP_EOL.str_repeat(' ', $commentDepth), $commentLines);
if ($multiline) {
$this->writeLine('<!--', $depth);
$this->writeLine($attrName.': '.$comment, $depth + 4);
$this->writeLine('-->', $depth);
} else {
$this->writeLine('<!-- '.$attrName.': '.$comment.' -->', $depth);
}
}
}
// render start tag + attributes
$rootIsVariablePrototype = isset($prototypeValue);
$rootIsEmptyTag = (0 === \count($rootChildren) && !$rootIsVariablePrototype);
$rootOpenTag = '<'.$rootName;
if (1 >= ($attributesCount = \count($rootAttributes))) {
if (1 === $attributesCount) {
$rootOpenTag .= sprintf(' %s="%s"', current(array_keys($rootAttributes)), $this->writeValue(current($rootAttributes)));
}
$rootOpenTag .= $rootIsEmptyTag ? ' />' : '>';
if ($rootIsVariablePrototype) {
$rootOpenTag .= $prototypeValue.'</'.$rootName.'>';
}
$this->writeLine($rootOpenTag, $depth);
} else {
$this->writeLine($rootOpenTag, $depth);
$i = 1;
foreach ($rootAttributes as $attrName => $attrValue) {
$attr = sprintf('%s="%s"', $attrName, $this->writeValue($attrValue));
$this->writeLine($attr, $depth + 4);
if ($attributesCount === $i++) {
$this->writeLine($rootIsEmptyTag ? '/>' : '>', $depth);
if ($rootIsVariablePrototype) {
$rootOpenTag .= $prototypeValue.'</'.$rootName.'>';
}
}
}
}
// render children tags
foreach ($rootChildren as $child) {
$this->writeLine('');
$this->writeNode($child, $depth + 4);
}
// render end tag
if (!$rootIsEmptyTag && !$rootIsVariablePrototype) {
$this->writeLine('');
$rootEndTag = '</'.$rootName.'>';
$this->writeLine($rootEndTag, $depth);
}
}
/**
* 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).PHP_EOL;
}
/**
* Renders the string conversion of the value.
*
* @param mixed $value
*
* @return string
*/
private function writeValue($value)
{
if ('%%%%not_defined%%%%' === $value) {
return '';
}
if (\is_string($value) || is_numeric($value)) {
return $value;
}
if (false === $value) {
return 'false';
}
if (true === $value) {
return 'true';
}
if (null === $value) {
return 'null';
}
if (empty($value)) {
return '';
}
if (\is_array($value)) {
return implode(',', $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\Dumper;
use Symfony\Component\Config\Definition\ArrayNode;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\EnumNode;
use Symfony\Component\Config\Definition\NodeInterface;
use Symfony\Component\Config\Definition\PrototypedArrayNode;
use Symfony\Component\Yaml\Inline;
/**
* Dumps a Yaml reference configuration for the given configuration/node instance.
*
* @author Kevin Bond <kevinbond@gmail.com>
*/
class YamlReferenceDumper
{
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 int $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()) {
$keyNodeClass = 'Symfony\Component\Config\Definition\\'.($prototype instanceof ArrayNode ? 'ArrayNode' : 'ScalarNode');
$keyNode = new $keyNodeClass($key, $node);
$info = 'Prototype';
if (null !== $prototype->getInfo()) {
$info .= ': '.$prototype->getInfo();
}
$keyNode->setInfo($info);
// 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 = '[]';
}
}
} elseif ($node instanceof EnumNode) {
$comments[] = 'One of '.implode('; ', array_map('json_encode', $node->getValues()));
$default = $node->hasDefaultValue() ? Inline::dump($node->getDefaultValue()) : '~';
} else {
$default = '~';
if ($node->hasDefaultValue()) {
$default = $node->getDefaultValue();
if (\is_array($default)) {
if (\count($defaultArray = $node->getDefaultValue())) {
$default = '';
} elseif (!\is_array($example)) {
$default = '[]';
}
} else {
$default = Inline::dump($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('%-21s%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 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)));
if ($hint = $this->getInfo()) {
$ex->addHint($hint);
}
$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\InvalidConfigurationException;
/**
* 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 (empty($values)) {
throw new \InvalidArgumentException('$values must contain at least one element.');
}
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;
}
}
<?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\DuplicateKeyException;
use Symfony\Component\Config\Definition\Exception\Exception;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\Definition\Exception\UnsetKeyException;
/**
* 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 = false;
protected $minNumberOfElements = 0;
protected $defaultValue = array();
protected $defaultChildren;
/**
* @var NodeInterface[] An array of the prototypes of the simplified value children
*/
private $valuePrototypes = array();
/**
* Sets the minimum number of elements that a prototype based node must
* contain. By default this is zero, meaning no elements.
*
* @param int $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 bool $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;
}
/**
* {@inheritdoc}
*/
public function hasDefaultValue()
{
return true;
}
/**
* Adds default children when none are set.
*
* @param int|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_int($children) && $children > 0 ? range(1, $children) : (array) $children;
}
}
/**
* {@inheritdoc}
*
* The default value could be either explicited or derived from the prototype
* 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.
*/
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.
*
* @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) {
throw new UnsetKeyException(sprintf('Unsetting key for path "%s", value: %s', $this->getPath(), json_encode($value)));
}
foreach ($value as $k => $v) {
$prototype = $this->getPrototypeForChild($k);
try {
$value[$k] = $prototype->finalize($v);
} catch (UnsetKeyException $e) {
unset($value[$k]);
}
}
if (\count($value) < $this->minNumberOfElements) {
$ex = new InvalidConfigurationException(sprintf('The path "%s" should have at least %d element(s) defined.', $this->getPath(), $this->minNumberOfElements));
$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) {
$ex = new InvalidConfigurationException(sprintf('The attribute "%s" must be set for path "%s".', $this->keyAttribute, $this->getPath()));
$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 (array_keys($v) === array('value')) {
$v = $v['value'];
if ($this->prototype instanceof ArrayNode && ($children = $this->prototype->getChildren()) && array_key_exists('value', $children)) {
$valuePrototype = current($this->valuePrototypes) ?: clone $children['value'];
$valuePrototype->parent = $this;
$originalClosures = $this->prototype->normalizationClosures;
if (\is_array($originalClosures)) {
$valuePrototypeClosures = $valuePrototype->normalizationClosures;
$valuePrototype->normalizationClosures = \is_array($valuePrototypeClosures) ? array_merge($originalClosures, $valuePrototypeClosures) : $originalClosures;
}
$this->valuePrototypes[$k] = $valuePrototype;
}
}
}
if (array_key_exists($k, $normalized)) {
$ex = new DuplicateKeyException(sprintf('Duplicate key "%s" for path "%s".', $k, $this->getPath()));
$ex->setPath($this->getPath());
throw $ex;
}
}
$prototype = $this->getPrototypeForChild($k);
if (null !== $this->keyAttribute || $isAssoc) {
$normalized[$k] = $prototype->normalize($v);
} else {
$normalized[] = $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;
}
$prototype = $this->getPrototypeForChild($k);
$leftSide[$k] = $prototype->merge($leftSide[$k], $v);
}
return $leftSide;
}
/**
* Returns a prototype for the child node that is associated to $key in the value array.
* For general child nodes, this will be $this->prototype.
* But if $this->removeKeyAttribute is true and there are only two keys in the child node:
* one is same as this->keyAttribute and the other is 'value', then the prototype will be different.
*
* For example, assume $this->keyAttribute is 'name' and the value array is as follows:
*
* array(
* array(
* 'name' => 'name001',
* 'value' => 'value001'
* )
* )
*
* Now, the key is 0 and the child node is:
*
* array(
* 'name' => 'name001',
* 'value' => 'value001'
* )
*
* When normalizing the value array, the 'name' element will removed from the child node
* and its value becomes the new key of the child node:
*
* array(
* 'name001' => array('value' => 'value001')
* )
*
* Now only 'value' element is left in the child node which can be further simplified into a string:
*
* array('name001' => 'value001')
*
* Now, the key becomes 'name001' and the child node becomes 'value001' and
* the prototype of child node 'name001' should be a ScalarNode instead of an ArrayNode instance.
*
* @param string $key The key of the child node
*
* @return mixed The prototype instance
*/
private function getPrototypeForChild($key)
{
$prototype = isset($this->valuePrototypes[$key]) ? $this->valuePrototypes[$key] : $this->prototype;
$prototype->setName($key);
return $prototype;
}
}
<?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)));
if ($hint = $this->getInfo()) {
$ex->addHint($hint);
}
$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\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 or equal to %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 or equal to %s', $value, $this->getPath(), $this->max);
}
if (isset($errorMsg)) {
$ex = new InvalidConfigurationException($errorMsg);
$ex->setPath($this->getPath());
throw $ex;
}
return $value;
}
/**
* {@inheritdoc}
*/
protected function isValueEmpty($value)
{
// a numeric value cannot be empty
return false;
}
}
<?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 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)));
if ($hint = $this->getInfo()) {
$ex->addHint($hint);
}
$ex->setPath($this->getPath());
throw $ex;
}
}
/**
* {@inheritdoc}
*/
protected function isValueEmpty($value)
{
return null === $value || '' === $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\Exception;
use Symfony\Component\Config\Definition\Exception\ForbiddenOverwriteException;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\Definition\Exception\InvalidTypeException;
/**
* The base node class.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
abstract class BaseNode implements NodeInterface
{
protected $name;
protected $parent;
protected $normalizationClosures = array();
protected $finalValidationClosures = array();
protected $allowOverwrite = true;
protected $required = false;
protected $equivalentValues = array();
protected $attributes = array();
/**
* @param string|null $name The name of the node
* @param NodeInterface|null $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 = (string) $name, '.')) {
throw new \InvalidArgumentException('The name must not contain ".".');
}
$this->name = $name;
$this->parent = $parent;
}
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 bool $boolean Required node
*/
public function setRequired($boolean)
{
$this->required = (bool) $boolean;
}
/**
* Sets if this node can be overridden.
*
* @param bool $allow
*/
public function setAllowOverwrite($allow)
{
$this->allowOverwrite = (bool) $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;
}
/**
* {@inheritdoc}
*/
public function isRequired()
{
return $this->required;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return $this->name;
}
/**
* {@inheritdoc}
*/
public function getPath()
{
$path = $this->name;
if (null !== $this->parent) {
$path = $this->parent->getPath().'.'.$path;
}
return $path;
}
/**
* {@inheritdoc}
*/
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);
}
/**
* {@inheritdoc}
*/
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 The normalized array value
*/
protected function preNormalize($value)
{
return $value;
}
/**
* Returns parent node for this node.
*
* @return NodeInterface|null
*/
public function getParent()
{
return $this->parent;
}
/**
* {@inheritdoc}
*/
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 $e) {
throw $e;
} catch (\Exception $e) {
throw new InvalidConfigurationException(sprintf('Invalid configuration for path "%s": %s', $this->getPath(), $e->getMessage()), $e->getCode(), $e);
}
}
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\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\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;
/**
* 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;
private $containsHints = false;
public function setPath($path)
{
$this->path = $path;
}
public function getPath()
{
return $this->path;
}
/**
* Adds extra information that is suffixed to the original exception message.
*
* @param string $hint
*/
public function addHint($hint)
{
if (!$this->containsHints) {
$this->message .= "\nHint: ".$hint;
$this->containsHints = true;
} else {
$this->message .= ', '.$hint;
}
}
}
<?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;
/**
* 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 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;
/**
* 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;
/**
* A ConfigCacheFactory implementation that validates the
* cache with an arbitrary set of ResourceCheckers.
*
* @author Matthias Pigulla <mp@webfactory.de>
*/
class ResourceCheckerConfigCacheFactory implements ConfigCacheFactoryInterface
{
/**
* @var ResourceCheckerInterface[]
*/
private $resourceCheckers = array();
/**
* @param ResourceCheckerInterface[] $resourceCheckers
*/
public function __construct(array $resourceCheckers = array())
{
$this->resourceCheckers = $resourceCheckers;
}
/**
* {@inheritdoc}
*/
public function cache($file, $callback)
{
if (!\is_callable($callback)) {
throw new \InvalidArgumentException(sprintf('Invalid type for callback argument. Expected callable, but got "%s".', \gettype($callback)));
}
$cache = new ResourceCheckerConfigCache($file, $this->resourceCheckers);
if (!$cache->isFresh()) {
\call_user_func($callback, $cache);
}
return $cache;
}
}
Copyright (c) 2004-2018 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\Resource;
/**
* Interface for Resources that can check for freshness autonomously,
* without special support from external services.
*
* @author Matthias Pigulla <mp@webfactory.de>
*/
interface SelfCheckingResourceInterface extends ResourceInterface
{
/**
* Returns true if the resource has not been updated since the given timestamp.
*
* @param int $timestamp The last time the resource was loaded
*
* @return bool True if the resource has not been updated, false otherwise
*/
public function isFresh($timestamp);
}
<?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;
use Symfony\Component\Config\ResourceCheckerInterface;
/**
* Resource checker for instances of SelfCheckingResourceInterface.
*
* As these resources perform the actual check themselves, we can provide
* this class as a standard way of validating them.
*
* @author Matthias Pigulla <mp@webfactory.de>
*/
class SelfCheckingResourceChecker implements ResourceCheckerInterface
{
public function supports(ResourceInterface $metadata)
{
return $metadata instanceof SelfCheckingResourceInterface;
}
public function isFresh(ResourceInterface $resource, $timestamp)
{
/* @var SelfCheckingResourceInterface $resource */
return $resource->isFresh($timestamp);
}
}
<?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;
/**
* FileExistenceResource represents a resource stored on the filesystem.
* Freshness is only evaluated against resource creation or deletion.
*
* The resource can be a file or a directory.
*
* @author Charles-Henri Bruyand <charleshenri.bruyand@gmail.com>
*/
class FileExistenceResource implements SelfCheckingResourceInterface, \Serializable
{
private $resource;
private $exists;
/**
* @param string $resource The file path to the resource
*/
public function __construct($resource)
{
$this->resource = (string) $resource;
$this->exists = file_exists($resource);
}
/**
* {@inheritdoc}
*/
public function __toString()
{
return $this->resource;
}
/**
* {@inheritdoc}
*/
public function getResource()
{
return $this->resource;
}
/**
* {@inheritdoc}
*/
public function isFresh($timestamp)
{
return file_exists($this->resource) === $this->exists;
}
/**
* {@inheritdoc}
*/
public function serialize()
{
return serialize(array($this->resource, $this->exists));
}
/**
* {@inheritdoc}
*/
public function unserialize($serialized)
{
list($this->resource, $this->exists) = 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 SelfCheckingResourceInterface, \Serializable
{
/**
* @var string|false
*/
private $resource;
/**
* @param string $resource The file path to the resource
*/
public function __construct($resource)
{
$this->resource = realpath($resource) ?: (file_exists($resource) ? $resource : false);
}
/**
* {@inheritdoc}
*/
public function __toString()
{
return (string) $this->resource;
}
/**
* {@inheritdoc}
*/
public function getResource()
{
return $this->resource;
}
/**
* {@inheritdoc}
*/
public function isFresh($timestamp)
{
if (false === $this->resource || !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);
}
}
<?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;
/**
* Resource checker for the ResourceInterface. Exists for BC.
*
* @author Matthias Pigulla <mp@webfactory.de>
*
* @deprecated since 2.8, to be removed in 3.0.
*/
class BCResourceInterfaceChecker extends SelfCheckingResourceChecker
{
public function supports(ResourceInterface $metadata)
{
/* As all resources must be instanceof ResourceInterface,
we support them all. */
return true;
}
public function isFresh(ResourceInterface $resource, $timestamp)
{
@trigger_error(sprintf('The class "%s" is performing resource checking through ResourceInterface::isFresh(), which is deprecated since Symfony 2.8 and will be removed in 3.0', \get_class($resource)), E_USER_DEPRECATED);
return parent::isFresh($resource, $timestamp); // For now, $metadata features the isFresh() method, so off we go (quack quack)
}
}
<?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 SelfCheckingResourceInterface, \Serializable
{
private $resource;
private $pattern;
/**
* @param string $resource The file path to the resource
* @param string|null $pattern A pattern to restrict monitored files
*/
public function __construct($resource, $pattern = null)
{
$this->resource = $resource;
$this->pattern = $pattern;
}
/**
* {@inheritdoc}
*/
public function __toString()
{
return md5(serialize(array($this->resource, $this->pattern)));
}
/**
* {@inheritdoc}
*/
public function getResource()
{
return $this->resource;
}
/**
* Returns the pattern to restrict monitored files.
*
* @return string|null
*/
public function getPattern()
{
return $this->pattern;
}
/**
* {@inheritdoc}
*/
public function isFresh($timestamp)
{
if (!is_dir($this->resource)) {
return false;
}
if ($timestamp < filemtime($this->resource)) {
return false;
}
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;
}
// for broken links
try {
$fileMTime = $file->getMTime();
} catch (\RuntimeException $e) {
continue;
}
// early return if a file's mtime exceeds the passed timestamp
if ($timestamp < $fileMTime) {
return false;
}
}
return true;
}
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;
/**
* 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.
*
* This method is necessary to allow for resource de-duplication, for example by means
* of array_unique(). The string returned need not have a particular meaning, but has
* to be identical for different ResourceInterface instances referring to the same
* resource; and it should be unlikely to collide with that of other, unrelated
* resource instances.
*
* @return string A string representation unique to the underlying Resource
*/
public function __toString();
/**
* Returns true if the resource has not been updated since the given timestamp.
*
* @param int $timestamp The last time the resource was loaded
*
* @return bool True if the resource has not been updated, false otherwise
*
* @deprecated since 2.8, to be removed in 3.0. If your resource can check itself for
* freshness implement the SelfCheckingResourceInterface instead.
*/
public function isFresh($timestamp);
/**
* Returns the tied resource.
*
* @return mixed The resource
*
* @deprecated since 2.8, to be removed in 3.0. As there are many different kinds of resource,
* a single getResource() method does not make sense at the interface level. You
* can still call getResource() on implementing classes, probably after performing
* a type check. If you know the concrete type of Resource at hand, the return value
* of this method may make sense to you.
*/
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;
/**
* FileLocator uses an array of pre-defined paths to find files.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class FileLocator implements FileLocatorInterface
{
protected $paths;
/**
* @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;
}
/**
* {@inheritdoc}
*/
public function locate($name, $currentPath = null, $first = true)
{
if ('' == $name) {
throw new \InvalidArgumentException('An empty file name is not valid to be located.');
}
if ($this->isAbsolutePath($name)) {
if (!file_exists($name)) {
throw new \InvalidArgumentException(sprintf('The file "%s" does not exist.', $name));
}
return $name;
}
$paths = $this->paths;
if (null !== $currentPath) {
array_unshift($paths, $currentPath);
}
$paths = array_unique($paths);
$filepaths = array();
foreach ($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).', $name, implode(', ', $paths)));
}
return $filepaths;
}
/**
* Returns whether the file path is an absolute path.
*
* @param string $file A file path
*
* @return bool
*/
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;
}
}
CHANGELOG
=========
2.8.0
-----
The edge case of defining just one value for nodes of type Enum is now allowed:
```php
$rootNode
->children()
->enumNode('variable')
->values(array('value'))
->end()
->end()
;
```
Before: `InvalidArgumentException` (variable must contain at least two
distinct elements).
After: the code will work as expected and it will restrict the values of the
`variable` option to just `value`.
* deprecated the `ResourceInterface::isFresh()` method. If you implement custom resource types and they
can be validated that way, make them implement the new `SelfCheckingResourceInterface`.
* deprecated the getResource() method in ResourceInterface. You can still call this method
on concrete classes implementing the interface, but it does not make sense at the interface
level as you need to know about the particular type of resource at hand to understand the
semantics of the returned value.
2.7.0
-----
* added `ConfigCacheInterface`, `ConfigCacheFactoryInterface` and a basic `ConfigCacheFactory`
implementation to delegate creation of ConfigCache instances
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
{
"name": "symfony/config",
"type": "library",
"description": "Symfony Config Component",
"keywords": [],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=5.3.9",
"symfony/filesystem": "~2.3|~3.0.0",
"symfony/polyfill-ctype": "~1.8"
},
"require-dev": {
"symfony/yaml": "~2.7|~3.0.0"
},
"suggest": {
"symfony/yaml": "To use the yaml reference dumper"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Config\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "2.8-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\Config;
/**
* @author Fabien Potencier <fabien@symfony.com>
*/
interface FileLocatorInterface
{
/**
* Returns a full path for a given file name.
*
* @param string $name The file name to locate
* @param string|null $currentPath The current path
* @param bool $first Whether to return the first occurrence or an array of filenames
*
* @return string|array The full path to the file or 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\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 = array();
/**
* @param LoaderInterface[] $loaders An array of loaders
*/
public function __construct(array $loaders = array())
{
foreach ($loaders as $loader) {
$this->addLoader($loader);
}
}
/**
* {@inheritdoc}
*/
public function resolve($resource, $type = null)
{
foreach ($this->loaders as $loader) {
if ($loader->supports($resource, $type)) {
return $loader;
}
}
return false;
}
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;
use Symfony\Component\Config\Exception\FileLoaderImportCircularReferenceException;
use Symfony\Component\Config\Exception\FileLoaderLoadException;
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 Loader
{
protected static $loading = array();
protected $locator;
private $currentDir;
public function __construct(FileLocatorInterface $locator)
{
$this->locator = $locator;
}
/**
* Sets the current directory.
*
* @param string $dir
*/
public function setCurrentDir($dir)
{
$this->currentDir = $dir;
}
/**
* Returns the file locator used by this loader.
*
* @return FileLocatorInterface
*/
public function getLocator()
{
return $this->locator;
}
/**
* Imports a resource.
*
* @param mixed $resource A Resource
* @param string|null $type The resource type or null if unknown
* @param bool $ignoreErrors Whether to ignore import errors or not
* @param string|null $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 self && null !== $this->currentDir) {
// we fallback to the current locator to keep BC
// as some some loaders do not call the parent __construct()
// @deprecated should be removed in 3.0
$locator = $loader->getLocator();
if (null === $locator) {
@trigger_error('Not calling the parent constructor in '.\get_class($loader).' which extends '.__CLASS__.' is deprecated since Symfony 2.7 and will not be supported anymore in 3.0.', E_USER_DEPRECATED);
$locator = $this->locator;
}
$resource = $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;
try {
$ret = $loader->load($resource, $type);
} catch (\Exception $e) {
unset(self::$loading[$resource]);
throw $e;
} catch (\Throwable $e) {
unset(self::$loading[$resource]);
throw $e;
}
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\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|null $type The resource type or null if unknown
*
* @return LoaderInterface|false The loader or false if none is able to load the resource
*/
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;
/**
* 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
{
public function __construct(LoaderResolverInterface $resolver)
{
$this->resolver = $resolver;
}
/**
* {@inheritdoc}
*/
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);
}
}
<?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|null $type The resource type or null if unknown
*
* @throws \Exception If something went wrong
*/
public function load($resource, $type = null);
/**
* Returns whether this class supports the given resource.
*
* @param mixed $resource A resource
* @param string|null $type The resource type or null if unknown
*
* @return bool 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.
*/
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;
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;
/**
* {@inheritdoc}
*/
public function getResolver()
{
return $this->resolver;
}
/**
* {@inheritdoc}
*/
public function setResolver(LoaderResolverInterface $resolver)
{
$this->resolver = $resolver;
}
/**
* Imports a resource.
*
* @param mixed $resource A resource
* @param string|null $type The resource type or null if unknown
*
* @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|null $type The resource type or null if unknown
*
* @return $this|LoaderInterface
*
* @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\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|null $schemaOrCallable An XSD schema file path, a callable, or null to disable validation
*
* @return \DOMDocument
*
* @throws \InvalidArgumentException When loading of XML file returns error
* @throws \RuntimeException When DOM extension is missing
*/
public static function loadFile($file, $schemaOrCallable = null)
{
if (!\extension_loaded('dom')) {
throw new \RuntimeException('Extension DOM is required.');
}
$content = @file_get_contents($file);
if ('' === trim($content)) {
throw new \InvalidArgumentException(sprintf('File %s does not contain valid XML, it is empty.', $file));
}
$internalErrors = libxml_use_internal_errors(true);
$disableEntities = libxml_disable_entity_loader(true);
libxml_clear_errors();
$dom = new \DOMDocument();
$dom->validateOnParse = true;
if (!$dom->loadXML($content, 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 (XML_DOCUMENT_TYPE_NODE === $child->nodeType) {
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)) {
$schemaSource = file_get_contents((string) $schemaOrCallable);
$valid = @$dom->schemaValidateSource($schemaSource);
} 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_clear_errors();
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 bool $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;
case ctype_digit($value):
$raw = $value;
$cast = (int) $value;
return '0' == $value[0] ? octdec($value) : (((string) $raw === (string) $cast) ? $cast : $raw);
case isset($value[1]) && '-' === $value[0] && ctype_digit(substr($value, 1)):
$raw = $value;
$cast = (int) $value;
return '0' == $value[1] ? octdec($value) : (((string) $raw === (string) $cast) ? $cast : $raw);
case 'true' === $lowercaseValue:
return true;
case 'false' === $lowercaseValue:
return false;
case isset($value[1]) && '0b' == $value[0].$value[1]:
return bindec($value);
case is_numeric($value):
return '0x' === $value[0].$value[1] ? hexdec($value) : (float) $value;
case preg_match('/^0x[0-9a-f]++$/i', $value):
return hexdec($value);
case preg_match('/^(-|\+)?[0-9]+(\.[0-9]+)?$/', $value):
return (float) $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 ?: '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;
use Symfony\Component\Config\Resource\ResourceInterface;
/**
* Interface for ResourceCheckers.
*
* When a ResourceCheckerConfigCache instance is checked for freshness, all its associated
* metadata resources are passed to ResourceCheckers. The ResourceCheckers
* can then inspect the resources and decide whether the cache can be considered
* fresh or not.
*
* @author Matthias Pigulla <mp@webfactory.de>
* @author Benjamin Klotz <bk@webfactory.de>
*/
interface ResourceCheckerInterface
{
/**
* Queries the ResourceChecker whether it can validate a given
* resource or not.
*
* @param ResourceInterface $metadata The resource to be checked for freshness
*
* @return bool True if the ResourceChecker can handle this resource type, false if not
*/
public function supports(ResourceInterface $metadata);
/**
* Validates the resource.
*
* @param ResourceInterface $resource The resource to be validated
* @param int $timestamp The timestamp at which the cache associated with this resource was created
*
* @return bool True if the resource has not changed since the given timestamp, false otherwise
*/
public function isFresh(ResourceInterface $resource, $timestamp);
}
<?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\BCResourceInterfaceChecker;
use Symfony\Component\Config\Resource\SelfCheckingResourceChecker;
/**
* ConfigCache caches arbitrary content in files on disk.
*
* When in debug mode, those metadata resources that implement
* \Symfony\Component\Config\Resource\SelfCheckingResourceInterface will
* be used to check cache freshness.
*
* During a transition period, also instances of
* \Symfony\Component\Config\Resource\ResourceInterface will be checked
* by means of the isFresh() method. This behaviour is deprecated since 2.8
* and will be removed in 3.0.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Matthias Pigulla <mp@webfactory.de>
*/
class ConfigCache extends ResourceCheckerConfigCache
{
private $debug;
/**
* @param string $file The absolute cache path
* @param bool $debug Whether debugging is enabled or not
*/
public function __construct($file, $debug)
{
parent::__construct($file, array(
new SelfCheckingResourceChecker(),
new BCResourceInterfaceChecker(),
));
$this->debug = (bool) $debug;
}
/**
* Gets the cache file path.
*
* @return string The cache file path
*
* @deprecated since 2.7, to be removed in 3.0. Use getPath() instead.
*/
public function __toString()
{
@trigger_error('ConfigCache::__toString() is deprecated since Symfony 2.7 and will be removed in 3.0. Use the getPath() method instead.', E_USER_DEPRECATED);
return $this->getPath();
}
/**
* Checks if the cache is still fresh.
*
* This implementation always returns true when debug is off and the
* cache file exists.
*
* @return bool true if the cache is fresh, false otherwise
*/
public function isFresh()
{
if (!$this->debug && is_file($this->getPath())) {
return true;
}
return parent::isFresh();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"
failOnRisky="true"
failOnWarning="true"
>
<php>
<ini name="error_reporting" value="-1" />
</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;
use Symfony\Component\Config\Resource\ResourceInterface;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Filesystem;
/**
* ResourceCheckerConfigCache uses instances of ResourceCheckerInterface
* to check whether cached data is still fresh.
*
* @author Matthias Pigulla <mp@webfactory.de>
*/
class ResourceCheckerConfigCache implements ConfigCacheInterface
{
/**
* @var string
*/
private $file;
/**
* @var ResourceCheckerInterface[]
*/
private $resourceCheckers;
/**
* @param string $file The absolute cache path
* @param ResourceCheckerInterface[] $resourceCheckers The ResourceCheckers to use for the freshness check
*/
public function __construct($file, array $resourceCheckers = array())
{
$this->file = $file;
$this->resourceCheckers = $resourceCheckers;
}
/**
* {@inheritdoc}
*/
public function getPath()
{
return $this->file;
}
/**
* Checks if the cache is still fresh.
*
* This implementation will make a decision solely based on the ResourceCheckers
* passed in the constructor.
*
* The first ResourceChecker that supports a given resource is considered authoritative.
* Resources with no matching ResourceChecker will silently be ignored and considered fresh.
*
* @return bool true if the cache is fresh, false otherwise
*/
public function isFresh()
{
if (!is_file($this->file)) {
return false;
}
if (!$this->resourceCheckers) {
return true; // shortcut - if we don't have any checkers we don't need to bother with the meta file at all
}
$metadata = $this->getMetaFile();
if (!is_file($metadata)) {
return false;
}
$e = null;
$meta = false;
$time = filemtime($this->file);
$signalingException = new \UnexpectedValueException();
$prevUnserializeHandler = ini_set('unserialize_callback_func', '');
$prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context) use (&$prevErrorHandler, $signalingException) {
if (E_WARNING === $type && 'Class __PHP_Incomplete_Class has no unserializer' === $msg) {
throw $signalingException;
}
return $prevErrorHandler ? $prevErrorHandler($type, $msg, $file, $line, $context) : false;
});
try {
$meta = unserialize(file_get_contents($metadata));
} catch (\Error $e) {
} catch (\Exception $e) {
}
restore_error_handler();
ini_set('unserialize_callback_func', $prevUnserializeHandler);
if (null !== $e && $e !== $signalingException) {
throw $e;
}
if (false === $meta) {
return false;
}
foreach ($meta as $resource) {
/* @var ResourceInterface $resource */
foreach ($this->resourceCheckers as $checker) {
if (!$checker->supports($resource)) {
continue; // next checker
}
if ($checker->isFresh($resource, $time)) {
break; // no need to further check this resource
}
return false; // cache is stale
}
// no suitable checker found, ignore this resource
}
return true;
}
/**
* Writes cache.
*
* @param string $content The content to write in the cache
* @param ResourceInterface[] $metadata An array of metadata
*
* @throws \RuntimeException When cache file can't be written
*/
public function write($content, array $metadata = null)
{
$mode = 0666;
$umask = umask();
$filesystem = new Filesystem();
$filesystem->dumpFile($this->file, $content, null);
try {
$filesystem->chmod($this->file, $mode, $umask);
} catch (IOException $e) {
// discard chmod failure (some filesystem may not support it)
}
if (null !== $metadata) {
$filesystem->dumpFile($this->getMetaFile(), serialize($metadata), null);
try {
$filesystem->chmod($this->getMetaFile(), $mode, $umask);
} catch (IOException $e) {
// discard chmod failure (some filesystem may not support it)
}
}
if (\function_exists('opcache_invalidate') && filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN)) {
@opcache_invalidate($this->file, true);
}
}
/**
* Gets the meta file path.
*
* @return string The meta file path
*/
private function getMetaFile()
{
return $this->file.'.meta';
}
}
<?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 int $code The error code
* @param \Exception $previous A previous exception
*/
public function __construct($resource, $sourceResource = null, $code = null, $previous = null)
{
$message = '';
if ($previous) {
// Include the previous exception, to help the user see what might be the underlying cause
// Trim the trailing period of the previous message. We only want 1 period remove so no rtrim...
if ('.' === substr($previous->getMessage(), -1)) {
$trimmedMessage = substr($previous->getMessage(), 0, -1);
$message .= sprintf('%s', $trimmedMessage).' in ';
} else {
$message .= sprintf('%s', $previous->getMessage()).' in ';
}
$message .= $resource.' ';
// show tweaked trace to complete the human readable sentence
if (null === $sourceResource) {
$message .= sprintf('(which is loaded in resource "%s")', $this->varToString($resource));
} else {
$message .= sprintf('(which is being imported from "%s")', $this->varToString($sourceResource));
}
$message .= '.';
// if there's no previous message, present it the default way
} elseif (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);
$message .= sprintf(' If the bundle is registered, make sure the bundle path "%s" is not empty.', $resource);
}
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\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]);
\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;
use Symfony\Component\Config\Resource\ResourceInterface;
/**
* Interface for ConfigCache.
*
* @author Matthias Pigulla <mp@webfactory.de>
*/
interface ConfigCacheInterface
{
/**
* Gets the cache file path.
*
* @return string The cache file path
*/
public function getPath();
/**
* Checks if the cache is still fresh.
*
* This check should take the metadata passed to the write() method into consideration.
*
* @return bool Whether the cache is still fresh
*/
public function isFresh();
/**
* Writes the given content into the cache file. Metadata will be stored
* independently and can be used to check cache freshness at a later time.
*
* @param string $content The content to write into the cache
* @param ResourceInterface[]|null $metadata An array of ResourceInterface instances
*
* @throws \RuntimeException When the cache file cannot be written
*/
public function write($content, array $metadata = null);
}
Filesystem Component
====================
The Filesystem component provides basic utilities for the filesystem.
Resources
---------
* [Documentation](https://symfony.com/doc/current/components/filesystem/index.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)
<?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\FileNotFoundException;
use Symfony\Component\Filesystem\Exception\IOException;
/**
* Provides basic utility to manipulate the file system.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Filesystem
{
private static $lastError;
/**
* Copies a file.
*
* If the target file is older than the origin file, it's always overwritten.
* If the target file is newer, it is overwritten only when the
* $overwriteNewerFiles option is set to true.
*
* @param string $originFile The original filename
* @param string $targetFile The target filename
* @param bool $overwriteNewerFiles If true, target files newer than origin files are overwritten
*
* @throws FileNotFoundException When originFile doesn't exist
* @throws IOException When copy fails
*/
public function copy($originFile, $targetFile, $overwriteNewerFiles = false)
{
$originIsLocal = stream_is_local($originFile) || 0 === stripos($originFile, 'file://');
if ($originIsLocal && !is_file($originFile)) {
throw new FileNotFoundException(sprintf('Failed to copy "%s" because file does not exist.', $originFile), 0, null, $originFile);
}
$this->mkdir(\dirname($targetFile));
$doCopy = true;
if (!$overwriteNewerFiles && null === parse_url($originFile, PHP_URL_HOST) && is_file($targetFile)) {
$doCopy = filemtime($originFile) > filemtime($targetFile);
}
if ($doCopy) {
// https://bugs.php.net/bug.php?id=64634
if (false === $source = @fopen($originFile, 'r')) {
throw new IOException(sprintf('Failed to copy "%s" to "%s" because source file could not be opened for reading.', $originFile, $targetFile), 0, null, $originFile);
}
// Stream context created to allow files overwrite when using FTP stream wrapper - disabled by default
if (false === $target = @fopen($targetFile, 'w', null, stream_context_create(array('ftp' => array('overwrite' => true))))) {
throw new IOException(sprintf('Failed to copy "%s" to "%s" because target file could not be opened for writing.', $originFile, $targetFile), 0, null, $originFile);
}
$bytesCopied = 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), 0, null, $originFile);
}
if ($originIsLocal) {
// Like `cp`, preserve executable permission bits
@chmod($targetFile, fileperms($targetFile) | (fileperms($originFile) & 0111));
if ($bytesCopied !== $bytesOrigin = filesize($originFile)) {
throw new IOException(sprintf('Failed to copy the whole content of "%s" to "%s" (%g of %g bytes copied).', $originFile, $targetFile, $bytesCopied, $bytesOrigin), 0, null, $originFile);
}
}
}
}
/**
* Creates a directory recursively.
*
* @param string|iterable $dirs The directory path
* @param int $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 (!self::box('mkdir', $dir, $mode, true)) {
if (!is_dir($dir)) {
// The directory was not created by a concurrent process. Let's throw an exception with a developer friendly error message if we have one
if (self::$lastError) {
throw new IOException(sprintf('Failed to create "%s": %s.', $dir, self::$lastError), 0, null, $dir);
}
throw new IOException(sprintf('Failed to create "%s"', $dir), 0, null, $dir);
}
}
}
}
/**
* Checks the existence of files or directories.
*
* @param string|iterable $files A filename, an array of files, or a \Traversable instance to check
*
* @return bool true if the file exists, false otherwise
*/
public function exists($files)
{
$maxPathLength = PHP_MAXPATHLEN - 2;
foreach ($this->toIterator($files) as $file) {
if (\strlen($file) > $maxPathLength) {
throw new IOException(sprintf('Could not check if file exist because path length exceeds %d characters.', $maxPathLength), 0, null, $file);
}
if (!file_exists($file)) {
return false;
}
}
return true;
}
/**
* Sets access and modification time of file.
*
* @param string|iterable $files A filename, an array of files, or a \Traversable instance to create
* @param int $time The touch time as a Unix timestamp
* @param int $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), 0, null, $file);
}
}
}
/**
* Removes files or directories.
*
* @param string|iterable $files A filename, an array of files, or a \Traversable instance to remove
*
* @throws IOException When removal fails
*/
public function remove($files)
{
if ($files instanceof \Traversable) {
$files = iterator_to_array($files, false);
} elseif (!\is_array($files)) {
$files = array($files);
}
$files = array_reverse($files);
foreach ($files as $file) {
if (is_link($file)) {
// See https://bugs.php.net/52176
if (!(self::box('unlink', $file) || '\\' !== \DIRECTORY_SEPARATOR || self::box('rmdir', $file)) && file_exists($file)) {
throw new IOException(sprintf('Failed to remove symlink "%s": %s.', $file, self::$lastError));
}
} elseif (is_dir($file)) {
$this->remove(new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS));
if (!self::box('rmdir', $file) && file_exists($file)) {
throw new IOException(sprintf('Failed to remove directory "%s": %s.', $file, self::$lastError));
}
} elseif (!self::box('unlink', $file) && file_exists($file)) {
throw new IOException(sprintf('Failed to remove file "%s": %s.', $file, self::$lastError));
}
}
}
/**
* Change mode for an array of files or directories.
*
* @param string|iterable $files A filename, an array of files, or a \Traversable instance to change mode
* @param int $mode The new mode (octal)
* @param int $umask The mode mask (octal)
* @param bool $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 (true !== @chmod($file, $mode & ~$umask)) {
throw new IOException(sprintf('Failed to chmod file "%s".', $file), 0, null, $file);
}
if ($recursive && is_dir($file) && !is_link($file)) {
$this->chmod(new \FilesystemIterator($file), $mode, $umask, true);
}
}
}
/**
* Change the owner of an array of files or directories.
*
* @param string|iterable $files A filename, an array of files, or a \Traversable instance to change owner
* @param string $user The new owner user name
* @param bool $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), 0, null, $file);
}
} else {
if (true !== @chown($file, $user)) {
throw new IOException(sprintf('Failed to chown file "%s".', $file), 0, null, $file);
}
}
}
}
/**
* Change the group of an array of files or directories.
*
* @param string|iterable $files A filename, an array of files, or a \Traversable instance to change group
* @param string $group The group name
* @param bool $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) || (\defined('HHVM_VERSION') && !posix_getgrnam($group))) {
throw new IOException(sprintf('Failed to chgrp file "%s".', $file), 0, null, $file);
}
} else {
if (true !== @chgrp($file, $group)) {
throw new IOException(sprintf('Failed to chgrp file "%s".', $file), 0, null, $file);
}
}
}
}
/**
* Renames a file or a directory.
*
* @param string $origin The origin filename or directory
* @param string $target The new filename or directory
* @param bool $overwrite Whether to overwrite the target if it already exists
*
* @throws IOException When target file or directory 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 && $this->isReadable($target)) {
throw new IOException(sprintf('Cannot rename because the target "%s" already exists.', $target), 0, null, $target);
}
if (true !== @rename($origin, $target)) {
if (is_dir($origin)) {
// See https://bugs.php.net/bug.php?id=54097 & http://php.net/manual/en/function.rename.php#113943
$this->mirror($origin, $target, null, array('override' => $overwrite, 'delete' => $overwrite));
$this->remove($origin);
return;
}
throw new IOException(sprintf('Cannot rename "%s" to "%s".', $origin, $target), 0, null, $target);
}
}
/**
* Tells whether a file exists and is readable.
*
* @param string $filename Path to the file
*
* @return bool
*
* @throws IOException When windows path is longer than 258 characters
*/
private function isReadable($filename)
{
$maxPathLength = PHP_MAXPATHLEN - 2;
if (\strlen($filename) > $maxPathLength) {
throw new IOException(sprintf('Could not check if file is readable because path length exceeds %d characters.', $maxPathLength), 0, null, $filename);
}
return is_readable($filename);
}
/**
* Creates a symbolic link or copy a directory.
*
* @param string $originDir The origin directory path
* @param string $targetDir The symbolic link name
* @param bool $copyOnWindows Whether to copy files if on Windows
*
* @throws IOException When symlink fails
*/
public function symlink($originDir, $targetDir, $copyOnWindows = false)
{
if ('\\' === \DIRECTORY_SEPARATOR) {
$originDir = strtr($originDir, '/', '\\');
$targetDir = strtr($targetDir, '/', '\\');
if ($copyOnWindows) {
$this->mirror($originDir, $targetDir);
return;
}
}
$this->mkdir(\dirname($targetDir));
if (is_link($targetDir)) {
if (readlink($targetDir) === $originDir) {
return;
}
$this->remove($targetDir);
}
if (!self::box('symlink', $originDir, $targetDir)) {
if (null !== self::$lastError) {
if ('\\' === \DIRECTORY_SEPARATOR && false !== strpos(self::$lastError, '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?', 0, null, $targetDir);
}
}
throw new IOException(sprintf('Failed to create symbolic link from "%s" to "%s".', $originDir, $targetDir), 0, null, $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 ('\\' === \DIRECTORY_SEPARATOR) {
$endPath = str_replace('\\', '/', $endPath);
$startPath = str_replace('\\', '/', $startPath);
}
$stripDriveLetter = function ($path) {
if (\strlen($path) > 2 && ':' === $path[1] && '/' === $path[2] && ctype_alpha($path[0])) {
return substr($path, 2);
}
return $path;
};
$endPath = $stripDriveLetter($endPath);
$startPath = $stripDriveLetter($startPath);
// Split the paths into arrays
$startPathArr = explode('/', trim($startPath, '/'));
$endPathArr = explode('/', trim($endPath, '/'));
$normalizePathArray = function ($pathSegments, $absolute) {
$result = array();
foreach ($pathSegments as $segment) {
if ('..' === $segment && ($absolute || \count($result))) {
array_pop($result);
} elseif ('.' !== $segment) {
$result[] = $segment;
}
}
return $result;
};
$startPathArr = $normalizePathArray($startPathArr, static::isAbsolutePath($startPath));
$endPathArr = $normalizePathArray($endPathArr, static::isAbsolutePath($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)
if (1 === \count($startPathArr) && '' === $startPathArr[0]) {
$depth = 0;
} else {
$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.('' !== $endPathRemainder ? $endPathRemainder.'/' : '');
return '' === $relativePath ? './' : $relativePath;
}
/**
* Mirrors a directory to another.
*
* Copies files and directories from the origin directory into the target directory. By default:
*
* - existing files in the target directory will be overwritten, except if they are newer (see the `override` option)
* - files in the target directory that do not exist in the source directory will not be deleted (see the `delete` option)
*
* @param string $originDir The origin directory
* @param string $targetDir The target directory
* @param \Traversable $iterator Iterator that filters which files and directories to copy
* @param array $options An array of boolean options
* Valid options are:
* - $options['override'] If true, target files newer than origin files are overwritten (see copy(), defaults to false)
* - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see symlink(), defaults to false)
* - $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, '/\\');
$originDirLen = \strlen($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);
}
$targetDirLen = \strlen($targetDir);
foreach ($deleteIterator as $file) {
$origin = $originDir.substr($file->getPathname(), $targetDirLen);
if (!$this->exists($origin)) {
$this->remove($file);
}
}
}
$copyOnWindows = false;
if (isset($options['copy_on_windows'])) {
$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);
}
if ($this->exists($originDir)) {
$this->mkdir($targetDir);
}
foreach ($iterator as $file) {
$target = $targetDir.substr($file->getPathname(), $originDirLen);
if ($copyOnWindows) {
if (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), 0, null, $file);
}
} else {
if (is_link($file)) {
$this->symlink($file->getLinkTarget(), $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), 0, null, $file);
}
}
}
}
/**
* Returns whether the file path is an absolute path.
*
* @param string $file A file path
*
* @return bool
*/
public function isAbsolutePath($file)
{
return 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)
;
}
/**
* Creates a temporary file with support for custom stream wrappers.
*
* @param string $dir The directory where the temporary filename will be created
* @param string $prefix The prefix of the generated temporary filename
* Note: Windows uses only the first three characters of prefix
*
* @return string The new temporary filename (with path), or throw an exception on failure
*/
public function tempnam($dir, $prefix)
{
list($scheme, $hierarchy) = $this->getSchemeAndHierarchy($dir);
// If no scheme or scheme is "file" or "gs" (Google Cloud) create temp file in local filesystem
if (null === $scheme || 'file' === $scheme || 'gs' === $scheme) {
$tmpFile = @tempnam($hierarchy, $prefix);
// If tempnam failed or no scheme return the filename otherwise prepend the scheme
if (false !== $tmpFile) {
if (null !== $scheme && 'gs' !== $scheme) {
return $scheme.'://'.$tmpFile;
}
return $tmpFile;
}
throw new IOException('A temporary file could not be created.');
}
// Loop until we create a valid temp file or have reached 10 attempts
for ($i = 0; $i < 10; ++$i) {
// Create a unique filename
$tmpFile = $dir.'/'.$prefix.uniqid(mt_rand(), true);
// Use fopen instead of file_exists as some streams do not support stat
// Use mode 'x+' to atomically check existence and create to avoid a TOCTOU vulnerability
$handle = @fopen($tmpFile, 'x+');
// If unsuccessful restart the loop
if (false === $handle) {
continue;
}
// Close the file if it was successfully opened
@fclose($handle);
return $tmpFile;
}
throw new IOException('A temporary file could not be created.');
}
/**
* 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 int|null $mode The file mode (octal). If null, file permissions are not modified
* Deprecated since version 2.3.12, to be removed in 3.0.
*
* @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);
}
if (!is_writable($dir)) {
throw new IOException(sprintf('Unable to write to the "%s" directory.', $dir), 0, null, $dir);
}
$tmpFile = $this->tempnam($dir, basename($filename));
if (false === @file_put_contents($tmpFile, $content)) {
throw new IOException(sprintf('Failed to write file "%s".', $filename), 0, null, $filename);
}
if (null !== $mode) {
if (\func_num_args() > 2) {
@trigger_error('Support for modifying file permissions is deprecated since Symfony 2.3.12 and will be removed in 3.0.', E_USER_DEPRECATED);
}
$this->chmod($tmpFile, $mode);
} elseif (file_exists($filename)) {
@chmod($tmpFile, fileperms($filename));
}
$this->rename($tmpFile, $filename, true);
}
/**
* @param mixed $files
*
* @return \Traversable
*/
private function toIterator($files)
{
if (!$files instanceof \Traversable) {
$files = new \ArrayObject(\is_array($files) ? $files : array($files));
}
return $files;
}
/**
* Gets a 2-tuple of scheme (may be null) and hierarchical part of a filename (e.g. file:///tmp -> array(file, tmp)).
*
* @param string $filename The filename to be parsed
*
* @return array The filename scheme and hierarchical part
*/
private function getSchemeAndHierarchy($filename)
{
$components = explode('://', $filename, 2);
return 2 === \count($components) ? array($components[0], $components[1]) : array(null, $components[0]);
}
private static function box($func)
{
self::$lastError = null;
\set_error_handler(__CLASS__.'::handleError');
try {
$result = \call_user_func_array($func, \array_slice(\func_get_args(), 1));
\restore_error_handler();
return $result;
} catch (\Throwable $e) {
} catch (\Exception $e) {
}
\restore_error_handler();
throw $e;
}
/**
* @internal
*/
public static function handleError($type, $msg)
{
self::$lastError = $msg;
}
}
Copyright (c) 2004-2018 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\Filesystem;
use Symfony\Component\Filesystem\Exception\IOException;
/**
* LockHandler class provides a simple abstraction to lock anything by means of
* a file lock.
*
* A locked file is created based on the lock name when calling lock(). Other
* lock handlers will not be able to lock the same name until it is released
* (explicitly by calling release() or implicitly when the instance holding the
* lock is destroyed).
*
* @author Grégoire Pineau <lyrixx@lyrixx.info>
* @author Romain Neutron <imprec@gmail.com>
* @author Nicolas Grekas <p@tchwork.com>
*/
class LockHandler
{
private $file;
private $handle;
/**
* @param string $name The lock name
* @param string|null $lockPath The directory to store the lock. Default values will use temporary directory
*
* @throws IOException If the lock directory could not be created or is not writable
*/
public function __construct($name, $lockPath = null)
{
$lockPath = $lockPath ?: sys_get_temp_dir();
if (!is_dir($lockPath)) {
$fs = new Filesystem();
$fs->mkdir($lockPath);
}
if (!is_writable($lockPath)) {
throw new IOException(sprintf('The directory "%s" is not writable.', $lockPath), 0, null, $lockPath);
}
$this->file = sprintf('%s/sf.%s.%s.lock', $lockPath, preg_replace('/[^a-z0-9\._-]+/i', '-', $name), hash('sha256', $name));
}
/**
* Lock the resource.
*
* @param bool $blocking Wait until the lock is released
*
* @return bool Returns true if the lock was acquired, false otherwise
*
* @throws IOException If the lock file could not be created or opened
*/
public function lock($blocking = false)
{
if ($this->handle) {
return true;
}
$error = null;
// Silence error reporting
set_error_handler(function ($errno, $msg) use (&$error) {
$error = $msg;
});
if (!$this->handle = fopen($this->file, 'r+') ?: fopen($this->file, 'r')) {
if ($this->handle = fopen($this->file, 'x')) {
chmod($this->file, 0666);
} elseif (!$this->handle = fopen($this->file, 'r+') ?: fopen($this->file, 'r')) {
usleep(100); // Give some time for chmod() to complete
$this->handle = fopen($this->file, 'r+') ?: fopen($this->file, 'r');
}
}
restore_error_handler();
if (!$this->handle) {
throw new IOException($error, 0, null, $this->file);
}
// On Windows, even if PHP doc says the contrary, LOCK_NB works, see
// https://bugs.php.net/54129
if (!flock($this->handle, LOCK_EX | ($blocking ? 0 : LOCK_NB))) {
fclose($this->handle);
$this->handle = null;
return false;
}
return true;
}
/**
* Release the resource.
*/
public function release()
{
if ($this->handle) {
flock($this->handle, LOCK_UN | LOCK_NB);
fclose($this->handle);
$this->handle = null;
}
}
}
CHANGELOG
=========
2.8.0
-----
* added tempnam() a stream aware version of PHP's native tempnam()
2.6.0
-----
* added LockHandler
2.3.12
------
* deprecated dumpFile() file mode argument.
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
{
"name": "symfony/filesystem",
"type": "library",
"description": "Symfony Filesystem Component",
"keywords": [],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=5.3.9",
"symfony/polyfill-ctype": "~1.8"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Filesystem\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "2.8-dev"
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"
failOnRisky="true"
failOnWarning="true"
>
<php>
<ini name="error_reporting" value="-1" />
</php>
<testsuites>
<testsuite name="Symfony Filesystem Component Test Suite">
<directory>./Tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./</directory>
<exclude>
<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\Filesystem\Exception;
/**
* IOException interface for file and input/output stream related exceptions thrown by the component.
*
* @author Christian Gärtner <christiangaertner.film@googlemail.com>
*/
interface IOExceptionInterface extends ExceptionInterface
{
/**
* Returns the associated path for the exception.
*
* @return string The path
*/
public function getPath();
}
<?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>
*/
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\Exception;
/**
* Exception class thrown when a filesystem operation failure happens.
*
* @author Romain Neutron <imprec@gmail.com>
* @author Christian Gärtner <christiangaertner.film@googlemail.com>
* @author Fabien Potencier <fabien@symfony.com>
*/
class IOException extends \RuntimeException implements IOExceptionInterface
{
private $path;
public function __construct($message, $code = 0, \Exception $previous = null, $path = null)
{
$this->path = $path;
parent::__construct($message, $code, $previous);
}
/**
* {@inheritdoc}
*/
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\Filesystem\Exception;
/**
* Exception class thrown when a file couldn't be found.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Christian Gärtner <christiangaertner.film@googlemail.com>
*/
class FileNotFoundException extends IOException
{
public function __construct($message = null, $code = 0, \Exception $previous = null, $path = null)
{
if (null === $message) {
if (null === $path) {
$message = 'File could not be found.';
} else {
$message = sprintf('File "%s" could not be found.', $path);
}
}
parent::__construct($message, $code, $previous, $path);
}
}
DependencyInjection Component
=============================
The DependencyInjection component allows you to standardize and centralize the
way objects are constructed in your application.
Resources
---------
* [Documentation](https://symfony.com/doc/current/components/dependency_injection/index.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)
<?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;
@trigger_error('The '.__NAMESPACE__.'\SimpleXMLElement class is deprecated since Symfony 2.5 and will be removed in 3.0.', E_USER_DEPRECATED);
use Symfony\Component\Config\Util\XmlUtils;
use Symfony\Component\ExpressionLanguage\Expression;
/**
* SimpleXMLElement class.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since version 2.5, to be removed in 3.0.
*/
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 bool $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 'expression':
$arguments[$key] = new Expression((string) $arg);
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\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);
}
<?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\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\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.
*
* @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.
*
* @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;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\OutOfBoundsException;
/**
* This definition decorates another definition.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class DefinitionDecorator extends Definition
{
private $parent;
private $changes = array();
/**
* @param string $parent The id of Definition instance to decorate
*/
public function __construct($parent)
{
parent::__construct();
$this->parent = $parent;
}
/**
* Returns the Definition being decorated.
*
* @return string
*/
public function getParent()
{
return $this->parent;
}
/**
* Returns all changes tracked for the Definition object.
*
* @return array An array of changes for this Definition
*/
public function getChanges()
{
return $this->changes;
}
/**
* {@inheritdoc}
*/
public function setClass($class)
{
$this->changes['class'] = true;
return parent::setClass($class);
}
/**
* {@inheritdoc}
*/
public function setFactory($callable)
{
$this->changes['factory'] = true;
return parent::setFactory($callable);
}
/**
* {@inheritdoc}
*/
public function setFactoryClass($class)
{
$this->changes['factory_class'] = true;
return parent::setFactoryClass($class);
}
/**
* {@inheritdoc}
*/
public function setFactoryMethod($method)
{
$this->changes['factory_method'] = true;
return parent::setFactoryMethod($method);
}
/**
* {@inheritdoc}
*/
public function setFactoryService($service, $triggerDeprecationError = true)
{
$this->changes['factory_service'] = true;
return parent::setFactoryService($service, $triggerDeprecationError);
}
/**
* {@inheritdoc}
*/
public function setConfigurator($callable)
{
$this->changes['configurator'] = true;
return parent::setConfigurator($callable);
}
/**
* {@inheritdoc}
*/
public function setFile($file)
{
$this->changes['file'] = true;
return parent::setFile($file);
}
/**
* {@inheritdoc}
*/
public function setPublic($boolean)
{
$this->changes['public'] = true;
return parent::setPublic($boolean);
}
/**
* {@inheritdoc}
*/
public function setLazy($boolean)
{
$this->changes['lazy'] = true;
return parent::setLazy($boolean);
}
/**
* {@inheritdoc}
*/
public function setDecoratedService($id, $renamedId = null, $priority = 0)
{
$this->changes['decorated_service'] = true;
return parent::setDecoratedService($id, $renamedId, $priority);
}
/**
* {@inheritdoc}
*/
public function setDeprecated($boolean = true, $template = null)
{
$this->changes['deprecated'] = true;
return parent::setDeprecated($boolean, $template);
}
/**
* {@inheritdoc}
*/
public function setAutowired($autowired)
{
$this->changes['autowire'] = true;
return parent::setAutowired($autowired);
}
/**
* 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 int $index
*
* @return mixed The argument value
*
* @throws OutOfBoundsException When the argument does not exist
*/
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 int $index
* @param mixed $value
*
* @return $this
*
* @throws InvalidArgumentException when $index isn't an integer
*/
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;
/**
* TaggedContainerInterface is the interface implemented when a container knows how to deals with tags.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface TaggedContainerInterface extends ContainerInterface
{
/**
* Returns service ids for a given tag.
*
* @param string $name The tag name
*
* @return array An array of tags
*/
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;
/**
* Scope class.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
class Scope implements ScopeInterface
{
private $name;
private $parentName;
public function __construct($name, $parentName = ContainerInterface::SCOPE_CONTAINER)
{
$this->name = $name;
$this->parentName = $parentName;
}
public function getName()
{
return $this->name;
}
public function getParentName()
{
return $this->parentName;
}
}
<?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\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
/**
* 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 can also be defined by creating a method named
* getXXXService(), where XXX is the camelized version of the id:
*
* * request -> getRequestService()
* * mysql_session_storage -> getMysqlSessionStorageService()
* * symfony.mysql_session_storage -> getSymfony_MysqlSessionStorageService()
*
* 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>
*/
class Container implements IntrospectableContainerInterface, ResettableContainerInterface
{
protected $parameterBag;
protected $services = array();
protected $methodMap = array();
protected $aliases = array();
protected $scopes = array();
protected $scopeChildren = array();
protected $scopedServices = array();
protected $scopeStacks = array();
protected $loading = array();
private $underscoreMap = array('_' => '', '.' => '_', '\\' => '_');
public function __construct(ParameterBagInterface $parameterBag = null)
{
$this->parameterBag = $parameterBag ?: new ParameterBag();
}
/**
* Compiles the container.
*
* This method does two things:
*
* * Parameter values are resolved;
* * The parameter bag is frozen.
*/
public function compile()
{
$this->parameterBag->resolve();
$this->parameterBag = new FrozenParameterBag($this->parameterBag->all());
}
/**
* Returns true if the container parameter bag are frozen.
*
* @return bool true if the container parameter bag are frozen, false otherwise
*/
public function isFrozen()
{
return $this->parameterBag instanceof FrozenParameterBag;
}
/**
* Gets the service container parameter bag.
*
* @return ParameterBagInterface A ParameterBagInterface instance
*/
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
*/
public function getParameter($name)
{
return $this->parameterBag->get($name);
}
/**
* Checks if a parameter exists.
*
* @param string $name The parameter name
*
* @return bool The presence of parameter in container
*/
public function hasParameter($name)
{
return $this->parameterBag->has($name);
}
/**
* Sets a parameter.
*
* @param string $name The parameter name
* @param mixed $value The parameter value
*/
public function setParameter($name, $value)
{
$this->parameterBag->set($name, $value);
}
/**
* Sets a service.
*
* Setting a service to null resets the service: has() returns false and get()
* behaves in the same way as if the service was never created.
*
* Note: The $scope parameter is deprecated since version 2.8 and will be removed in 3.0.
*
* @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
*/
public function set($id, $service, $scope = self::SCOPE_CONTAINER)
{
if (!\in_array($scope, array('container', 'request')) || ('request' === $scope && 'request' !== $id)) {
@trigger_error('The concept of container scopes is deprecated since Symfony 2.8 and will be removed in 3.0. Omit the third parameter.', E_USER_DEPRECATED);
}
if (self::SCOPE_PROTOTYPE === $scope) {
throw new InvalidArgumentException(sprintf('You cannot set service "%s" of scope "prototype".', $id));
}
$id = strtolower($id);
if ('service_container' === $id) {
// BC: 'service_container' is no longer a self-reference but always
// $this, so ignore this call.
// @todo Throw InvalidArgumentException in next major release.
return;
}
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;
}
if (isset($this->aliases[$id])) {
unset($this->aliases[$id]);
}
$this->services[$id] = $service;
if (method_exists($this, $method = 'synchronize'.strtr($id, $this->underscoreMap).'Service')) {
$this->$method();
}
if (null === $service) {
if (self::SCOPE_CONTAINER !== $scope) {
unset($this->scopedServices[$scope][$id]);
}
unset($this->services[$id]);
}
}
/**
* Returns true if the given service is defined.
*
* @param string $id The service identifier
*
* @return bool true if the service is defined, false otherwise
*/
public function has($id)
{
for ($i = 2;;) {
if ('service_container' === $id
|| isset($this->aliases[$id])
|| isset($this->services[$id])
|| array_key_exists($id, $this->services)
) {
return true;
}
if (--$i && $id !== $lcId = strtolower($id)) {
$id = $lcId;
} else {
return method_exists($this, 'get'.strtr($id, $this->underscoreMap).'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 int $invalidBehavior The behavior when the service does not exist
*
* @return object The associated service
*
* @throws ServiceCircularReferenceException When a circular reference is detected
* @throws ServiceNotFoundException When the service is not defined
* @throws \Exception if an exception has been thrown when the service has been resolved
*
* @see Reference
*/
public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE)
{
// Attempt to retrieve the service by checking first aliases then
// available services. Service IDs are case insensitive, however since
// this method can be called thousands of times during a request, avoid
// calling strtolower() unless necessary.
for ($i = 2;;) {
if (isset($this->aliases[$id])) {
$id = $this->aliases[$id];
}
// Re-use shared service instance if it exists.
if (isset($this->services[$id]) || array_key_exists($id, $this->services)) {
return $this->services[$id];
}
if ('service_container' === $id) {
return $this;
}
if (isset($this->loading[$id])) {
throw new ServiceCircularReferenceException($id, array_keys($this->loading));
}
if (isset($this->methodMap[$id])) {
$method = $this->methodMap[$id];
} elseif (--$i && $id !== $lcId = strtolower($id)) {
$id = $lcId;
continue;
} elseif (method_exists($this, $method = 'get'.strtr($id, $this->underscoreMap).'Service')) {
// $method is set to the right value, proceed
} else {
if (self::EXCEPTION_ON_INVALID_REFERENCE === $invalidBehavior) {
if (!$id) {
throw new ServiceNotFoundException($id);
}
$alternatives = array();
foreach ($this->getServiceIds() as $knownId) {
$lev = levenshtein($id, $knownId);
if ($lev <= \strlen($id) / 3 || false !== strpos($knownId, $id)) {
$alternatives[] = $knownId;
}
}
throw new ServiceNotFoundException($id, null, null, $alternatives);
}
return;
}
$this->loading[$id] = true;
try {
$service = $this->$method();
} catch (\Exception $e) {
unset($this->loading[$id]);
unset($this->services[$id]);
if ($e instanceof InactiveScopeException && self::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
return;
}
throw $e;
} catch (\Throwable $e) {
unset($this->loading[$id]);
unset($this->services[$id]);
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 bool true if service has already been initialized, false otherwise
*/
public function initialized($id)
{
$id = strtolower($id);
if (isset($this->aliases[$id])) {
$id = $this->aliases[$id];
}
if ('service_container' === $id) {
// BC: 'service_container' was a synthetic service previously.
// @todo Change to false in next major release.
return true;
}
return isset($this->services[$id]) || array_key_exists($id, $this->services);
}
/**
* {@inheritdoc}
*/
public function reset()
{
if (!empty($this->scopedServices)) {
throw new LogicException('Resetting the container is not allowed when a scope is active.');
}
$this->services = array();
}
/**
* Gets all service ids.
*
* @return array An array of all defined service ids
*/
public function getServiceIds()
{
$ids = array();
foreach (get_class_methods($this) as $method) {
if (preg_match('/^get(.+)Service$/', $method, $match)) {
$ids[] = self::underscore($match[1]);
}
}
$ids[] = 'service_container';
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
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function enterScope($name)
{
if ('request' !== $name) {
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
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
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function leaveScope($name)
{
if ('request' !== $name) {
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
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])) {
$services[] = $this->scopedServices[$child];
unset($this->scopedServices[$child]);
}
}
// update global map
$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;
if ($this->scopeStacks[$name]->isEmpty()) {
unset($this->scopeStacks[$name]);
}
foreach ($services as $array) {
foreach ($array as $id => $service) {
$this->set($id, $service, $name);
}
}
}
}
/**
* Adds a scope to the container.
*
* @throws InvalidArgumentException
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function addScope(ScopeInterface $scope)
{
$name = $scope->getName();
$parentScope = $scope->getParentName();
if ('request' !== $name) {
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
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 (self::SCOPE_CONTAINER !== $parentScope) {
$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 bool
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function hasScope($name)
{
if ('request' !== $name) {
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
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 bool
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function isScopeActive($name)
{
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
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 strtr(ucwords(strtr($id, array('_' => ' ', '.' => '_ ', '\\' => '_ '))), array(' ' => ''));
}
/**
* 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'), str_replace('_', '.', $id)));
}
private function __clone()
{
}
}
<?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>
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
interface ScopeInterface
{
public function getName();
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;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Config\Resource\ResourceInterface;
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\Exception\ServiceCircularReferenceException;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\InstantiatorInterface;
use Symfony\Component\DependencyInjection\LazyProxy\Instantiator\RealServiceInstantiator;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
/**
* ContainerBuilder is a DI container that provides an API to easily describe services.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
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 $aliasDefinitions = array();
/**
* @var ResourceInterface[]
*/
private $resources = array();
private $extensionConfigs = array();
/**
* @var Compiler
*/
private $compiler;
private $trackResources;
/**
* @var InstantiatorInterface|null
*/
private $proxyInstantiator;
/**
* @var ExpressionLanguage|null
*/
private $expressionLanguage;
/**
* @var ExpressionFunctionProviderInterface[]
*/
private $expressionLanguageProviders = array();
public function __construct(ParameterBagInterface $parameterBag = null)
{
parent::__construct($parameterBag);
$this->trackResources = interface_exists('Symfony\Component\Config\Resource\ResourceInterface');
}
/**
* @var string[] with tag names used by findTaggedServiceIds
*/
private $usedTags = array();
/**
* 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 bool $track True if you want to track resources, false otherwise
*/
public function setResourceTracking($track)
{
$this->trackResources = (bool) $track;
}
/**
* Checks if resources are tracked.
*
* @return bool true If resources are tracked, false otherwise
*/
public function isTrackingResources()
{
return $this->trackResources;
}
/**
* Sets the instantiator to be used when fetching proxies.
*/
public function setProxyInstantiator(InstantiatorInterface $proxyInstantiator)
{
$this->proxyInstantiator = $proxyInstantiator;
}
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
*/
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
*/
public function getExtensions()
{
return $this->extensions;
}
/**
* Checks if we have an extension.
*
* @param string $name The name of the extension
*
* @return bool If the extension exists
*/
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
*/
public function getResources()
{
return array_unique($this->resources);
}
/**
* @return $this
*/
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 $this
*/
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 $this
*/
public function addObjectResource($object)
{
if ($this->trackResources) {
$this->addClassResource(new \ReflectionClass($object));
}
return $this;
}
/**
* Adds the given class hierarchy as resources.
*
* @return $this
*/
public function addClassResource(\ReflectionClass $class)
{
if (!$this->trackResources) {
return $this;
}
do {
if (is_file($class->getFileName())) {
$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 $this
*
* @throws BadMethodCallException When this ContainerBuilder is frozen
* @throws \LogicException if the container is frozen
*/
public function loadFromExtension($extension, array $values = null)
{
if ($this->isFrozen()) {
throw new BadMethodCallException('Cannot load from an extension on a frozen container.');
}
if (\func_num_args() < 2) {
$values = array();
}
$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 $this
*/
public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION)
{
$this->getCompiler()->addPass($pass, $type);
$this->addObjectResource($pass);
return $this;
}
/**
* Returns the compiler pass config which can then be modified.
*
* @return PassConfig The compiler pass config
*/
public function getCompilerPassConfig()
{
return $this->getCompiler()->getPassConfig();
}
/**
* Returns the compiler.
*
* @return Compiler The compiler
*/
public function getCompiler()
{
if (null === $this->compiler) {
$this->compiler = new Compiler();
}
return $this->compiler;
}
/**
* Returns all Scopes.
*
* @return array An array of scopes
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function getScopes($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return $this->scopes;
}
/**
* Returns all Scope children.
*
* @return array An array of scope children
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function getScopeChildren($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return $this->scopeChildren;
}
/**
* Sets a service.
*
* Note: The $scope parameter is deprecated since version 2.8 and will be removed in 3.0.
*
* @param string $id The service identifier
* @param object $service The service instance
* @param string $scope The scope
*
* @throws BadMethodCallException When this ContainerBuilder is frozen
*/
public function set($id, $service, $scope = self::SCOPE_CONTAINER)
{
$id = strtolower($id);
$set = isset($this->definitions[$id]);
if ($this->isFrozen() && ($set || isset($this->obsoleteDefinitions[$id])) && !$this->{$set ? 'definitions' : 'obsoleteDefinitions'}[$id]->isSynthetic()) {
// setting a synthetic service on a frozen container is alright
throw new BadMethodCallException(sprintf('Setting service "%s" on a frozen container is not allowed.', $id));
}
if ($set) {
$this->obsoleteDefinitions[$id] = $this->definitions[$id];
}
unset($this->definitions[$id], $this->aliasDefinitions[$id]);
parent::set($id, $service, $scope);
if (isset($this->obsoleteDefinitions[$id]) && $this->obsoleteDefinitions[$id]->isSynchronized(false)) {
$this->synchronize($id);
}
}
/**
* Removes a service definition.
*
* @param string $id The service identifier
*/
public function removeDefinition($id)
{
unset($this->definitions[strtolower($id)]);
}
/**
* Returns true if the given service is defined.
*
* @param string $id The service identifier
*
* @return bool true if the service is defined, false otherwise
*/
public function has($id)
{
$id = strtolower($id);
return isset($this->definitions[$id]) || isset($this->aliasDefinitions[$id]) || parent::has($id);
}
/**
* 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 when no definitions are available
* @throws ServiceCircularReferenceException When a circular reference is detected
* @throws ServiceNotFoundException When the service is not defined
* @throws \Exception
*
* @see Reference
*/
public function get($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
{
$id = strtolower($id);
if ($service = parent::get($id, ContainerInterface::NULL_ON_INVALID_REFERENCE)) {
return $service;
}
if (!array_key_exists($id, $this->definitions) && isset($this->aliasDefinitions[$id])) {
return $this->get((string) $this->aliasDefinitions[$id], $invalidBehavior);
}
try {
$definition = $this->getDefinition($id);
} catch (ServiceNotFoundException $e) {
if (ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
return;
}
throw $e;
}
$this->loading[$id] = true;
try {
$service = $this->createService($definition, new \SplObjectStorage(), $id);
} catch (\Exception $e) {
unset($this->loading[$id]);
if ($e instanceof InactiveScopeException && self::EXCEPTION_ON_INVALID_REFERENCE !== $invalidBehavior) {
return;
}
throw $e;
} catch (\Throwable $e) {
unset($this->loading[$id]);
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(new ParameterBag(array('foo' => 'bar')));
* $loader = new LoaderXXX($container);
* $loader->load('resource_name');
* $container->register('foo', '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.
*
* @throws BadMethodCallException When this ContainerBuilder is frozen
*/
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
*/
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.
*/
public function compile()
{
$compiler = $this->getCompiler();
if ($this->trackResources) {
foreach ($compiler->getPassConfig()->getPasses() as $pass) {
$this->addObjectResource($pass);
}
}
$compiler->compile($this);
if ($this->trackResources) {
foreach ($this->definitions as $definition) {
if ($definition->isLazy() && ($class = $definition->getClass()) && class_exists($class)) {
$this->addClassResource(new \ReflectionClass($class));
}
}
}
$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->aliasDefinitions), parent::getServiceIds()));
}
/**
* Adds the service aliases.
*/
public function addAliases(array $aliases)
{
foreach ($aliases as $alias => $id) {
$this->setAlias($alias, $id);
}
}
/**
* Sets the service aliases.
*/
public function setAliases(array $aliases)
{
$this->aliasDefinitions = 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
*/
public function setAlias($alias, $id)
{
$alias = strtolower($alias);
if ('' === $alias || '\\' === substr($alias, -1) || \strlen($alias) !== strcspn($alias, "\0\r\n'")) {
throw new InvalidArgumentException(sprintf('Invalid alias id: "%s"', $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 === (string) $id) {
throw new InvalidArgumentException(sprintf('An alias can not reference itself, got a circular reference on "%s".', $alias));
}
unset($this->definitions[$alias]);
$this->aliasDefinitions[$alias] = $id;
}
/**
* Removes an alias.
*
* @param string $alias The alias to remove
*/
public function removeAlias($alias)
{
unset($this->aliasDefinitions[strtolower($alias)]);
}
/**
* Returns true if an alias exists under the given identifier.
*
* @param string $id The service identifier
*
* @return bool true if the alias exists, false otherwise
*/
public function hasAlias($id)
{
return isset($this->aliasDefinitions[strtolower($id)]);
}
/**
* Gets all defined aliases.
*
* @return Alias[] An array of aliases
*/
public function getAliases()
{
return $this->aliasDefinitions;
}
/**
* Gets an alias.
*
* @param string $id The service identifier
*
* @return Alias An Alias instance
*
* @throws InvalidArgumentException if the alias does not exist
*/
public function getAlias($id)
{
$id = strtolower($id);
if (!isset($this->aliasDefinitions[$id])) {
throw new InvalidArgumentException(sprintf('The service alias "%s" does not exist.', $id));
}
return $this->aliasDefinitions[$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|null The service class
*
* @return Definition A Definition instance
*/
public function register($id, $class = null)
{
return $this->setDefinition($id, new Definition($class));
}
/**
* Adds the service definitions.
*
* @param Definition[] $definitions An array of service definitions
*/
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
*/
public function setDefinitions(array $definitions)
{
$this->definitions = array();
$this->addDefinitions($definitions);
}
/**
* Gets all service definitions.
*
* @return Definition[] An array of Definition instances
*/
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
*/
public function setDefinition($id, Definition $definition)
{
if ($this->isFrozen()) {
throw new BadMethodCallException('Adding definition to a frozen container is not allowed');
}
$id = strtolower($id);
if ('' === $id || '\\' === substr($id, -1) || \strlen($id) !== strcspn($id, "\0\r\n'")) {
throw new InvalidArgumentException(sprintf('Invalid service id: "%s"', $id));
}
unset($this->aliasDefinitions[$id]);
return $this->definitions[$id] = $definition;
}
/**
* Returns true if a service definition exists under the given identifier.
*
* @param string $id The service identifier
*
* @return bool true if the service definition exists, false otherwise
*/
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 ServiceNotFoundException if the service definition does not exist
*/
public function getDefinition($id)
{
$id = strtolower($id);
if (!array_key_exists($id, $this->definitions)) {
throw new ServiceNotFoundException($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 ServiceNotFoundException if the service definition does not exist
*/
public function findDefinition($id)
{
$id = strtolower($id);
while (isset($this->aliasDefinitions[$id])) {
$id = (string) $this->aliasDefinitions[$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 bool $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, \SplObjectStorage $inlinedDefinitions, $id = null, $tryProxy = true)
{
if (null === $id && isset($inlinedDefinitions[$definition])) {
return $inlinedDefinitions[$definition];
}
if ($definition instanceof DefinitionDecorator) {
throw new RuntimeException(sprintf('Constructing service "%s" from a parent definition is not supported at build time.', $id));
}
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 ($definition->isDeprecated()) {
@trigger_error($definition->getDeprecationMessage($id), E_USER_DEPRECATED);
}
if ($tryProxy && $definition->isLazy()) {
$container = $this;
$proxy = $this
->getProxyInstantiator()
->instantiateProxy(
$container,
$definition,
$id, function () use ($definition, $inlinedDefinitions, $id, $container) {
return $container->createService($definition, $inlinedDefinitions, $id, false);
}
);
$this->shareService($definition, $proxy, $id, $inlinedDefinitions);
return $proxy;
}
$parameterBag = $this->getParameterBag();
if (null !== $definition->getFile()) {
require_once $parameterBag->resolveValue($definition->getFile());
}
$arguments = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())), $inlinedDefinitions);
if (null !== $factory = $definition->getFactory()) {
if (\is_array($factory)) {
$factory = array($this->doResolveServices($parameterBag->resolveValue($factory[0]), $inlinedDefinitions), $factory[1]);
} elseif (!\is_string($factory)) {
throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id));
}
$service = \call_user_func_array($factory, $arguments);
if (!$definition->isDeprecated() && \is_array($factory) && \is_string($factory[0])) {
$r = new \ReflectionClass($factory[0]);
if (0 < strpos($r->getDocComment(), "\n * @deprecated ")) {
@trigger_error(sprintf('The "%s" service relies on the deprecated "%s" factory class. It should either be deprecated or its factory upgraded.', $id, $r->name), E_USER_DEPRECATED);
}
}
} elseif (null !== $definition->getFactoryMethod(false)) {
if (null !== $definition->getFactoryClass(false)) {
$factory = $parameterBag->resolveValue($definition->getFactoryClass(false));
} elseif (null !== $definition->getFactoryService(false)) {
$factory = $this->get($parameterBag->resolveValue($definition->getFactoryService(false)));
} 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(false)), $arguments);
} else {
$r = new \ReflectionClass($parameterBag->resolveValue($definition->getClass()));
$service = null === $r->getConstructor() ? $r->newInstance() : $r->newInstanceArgs($arguments);
if (!$definition->isDeprecated() && 0 < strpos($r->getDocComment(), "\n * @deprecated ")) {
@trigger_error(sprintf('The "%s" service relies on the deprecated "%s" class. It should either be deprecated or its implementation upgraded.', $id, $r->name), E_USER_DEPRECATED);
}
}
if ($tryProxy || !$definition->isLazy()) {
// share only if proxying failed, or if not a proxy
$this->shareService($definition, $service, $id, $inlinedDefinitions);
}
$properties = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties())), $inlinedDefinitions);
foreach ($properties as $name => $value) {
$service->$name = $value;
}
foreach ($definition->getMethodCalls() as $call) {
$this->callMethod($service, $call, $inlinedDefinitions);
}
if ($callable = $definition->getConfigurator()) {
if (\is_array($callable)) {
$callable[0] = $parameterBag->resolveValue($callable[0]);
if ($callable[0] instanceof Reference) {
$callable[0] = $this->get((string) $callable[0], $callable[0]->getInvalidBehavior());
} elseif ($callable[0] instanceof Definition) {
$callable[0] = $this->createService($callable[0], $inlinedDefinitions);
}
}
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 and evaluates expressions.
*
* @param mixed $value A value
*
* @return mixed The same value with all service references replaced by
* the real service instances and all expressions evaluated
*/
public function resolveServices($value)
{
return $this->doResolveServices($value, new \SplObjectStorage());
}
private function doResolveServices($value, \SplObjectStorage $inlinedDefinitions)
{
if (\is_array($value)) {
foreach ($value as $k => $v) {
$value[$k] = $this->doResolveServices($v, $inlinedDefinitions);
}
} elseif ($value instanceof Reference) {
$value = $this->get((string) $value, $value->getInvalidBehavior());
} elseif ($value instanceof Definition) {
$value = $this->createService($value, $inlinedDefinitions);
} elseif ($value instanceof Expression) {
$value = $this->getExpressionLanguage()->evaluate($value, array('container' => $this));
}
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
*/
public function findTaggedServiceIds($name)
{
$this->usedTags[] = $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 all tags not queried by findTaggedServiceIds.
*
* @return string[] An array of tags
*/
public function findUnusedTags()
{
return array_values(array_diff($this->findTags(), $this->usedTags));
}
public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
{
$this->expressionLanguageProviders[] = $provider;
}
/**
* @return ExpressionFunctionProviderInterface[]
*/
public function getExpressionLanguageProviders()
{
return $this->expressionLanguageProviders;
}
/**
* 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 && ContainerInterface::IGNORE_ON_INVALID_REFERENCE === $value->getInvalidBehavior()) {
$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
*
* @deprecated since version 2.7, will be removed in 3.0.
*/
private function synchronize($id)
{
if ('request' !== $id) {
@trigger_error('The '.__METHOD__.' method is deprecated in version 2.7 and will be removed in version 3.0.', E_USER_DEPRECATED);
}
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, new \SplObjectStorage());
}
}
}
}
}
private function callMethod($service, $call, \SplObjectStorage $inlinedDefinitions)
{
$services = self::getServiceConditionals($call[1]);
foreach ($services as $s) {
if (!$this->has($s)) {
return;
}
}
\call_user_func_array(array($service, $call[0]), $this->doResolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])), $inlinedDefinitions));
}
/**
* Shares a given service in the container.
*
* @param Definition $definition
* @param mixed $service
* @param string|null $id
*
* @throws InactiveScopeException
*/
private function shareService(Definition $definition, $service, $id, \SplObjectStorage $inlinedDefinitions)
{
if (!$definition->isShared() || self::SCOPE_PROTOTYPE === $scope = $definition->getScope(false)) {
return;
}
if (null === $id) {
$inlinedDefinitions[$definition] = $service;
} else {
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;
}
}
}
private function getExpressionLanguage()
{
if (null === $this->expressionLanguage) {
if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
}
$this->expressionLanguage = new ExpressionLanguage(null, $this->expressionLanguageProviders);
}
return $this->expressionLanguage;
}
}
Copyright (c) 2004-2018 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\ExpressionLanguage\ExpressionLanguage as BaseExpressionLanguage;
use Symfony\Component\ExpressionLanguage\ParserCache\ParserCacheInterface;
/**
* Adds some function to the default ExpressionLanguage.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @see ExpressionLanguageProvider
*/
class ExpressionLanguage extends BaseExpressionLanguage
{
public function __construct(ParserCacheInterface $cache = null, array $providers = array())
{
// prepend the default provider to let users override it easily
array_unshift($providers, new ExpressionLanguageProvider());
parent::__construct($cache, $providers);
}
}
<?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>
*/
class Reference
{
private $id;
private $invalidBehavior;
private $strict;
/**
* Note: The $strict parameter is deprecated since version 2.8 and will be removed in 3.0.
*
* @param string $id The service identifier
* @param int $invalidBehavior The behavior when the service does not exist
* @param bool $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;
}
/**
* @return string The service identifier
*/
public function __toString()
{
return $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 bool
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function isStrict($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
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\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>
*
* @deprecated since version 2.8, to be merged with ContainerInterface in 3.0.
*/
interface IntrospectableContainerInterface extends ContainerInterface
{
/**
* Check for whether or not a service has been initialized.
*
* @param string $id
*
* @return bool true if the service has been initialized, false otherwise
*/
public function initialized($id);
}
CHANGELOG
=========
2.8.0
-----
* deprecated the abstract ContainerAware class in favor of ContainerAwareTrait
* deprecated IntrospectableContainerInterface, to be merged with ContainerInterface in 3.0
* allowed specifying a directory to recursively load all configuration files it contains
* deprecated the concept of scopes
* added `Definition::setShared()` and `Definition::isShared()`
* added ResettableContainerInterface to be able to reset the container to release memory on shutdown
* added a way to define the priority of service decoration
* added support for service autowiring
2.7.0
-----
* deprecated synchronized services
2.6.0
-----
* added new factory syntax and deprecated the old one
2.5.0
-----
* added DecoratorServicePass and a way to override a service definition (Definition::setDecoratedService())
* deprecated SimpleXMLElement class.
2.4.0
-----
* added support for expressions in service definitions
* added ContainerAwareTrait to add default container aware behavior to a class
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>
*/
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.
*
* Note: The $scope parameter is deprecated since version 2.8 and will be removed in 3.0.
*
* @param string $id The service identifier
* @param object $service The service instance
* @param string $scope The scope of the service
*/
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 ServiceCircularReferenceException When a circular reference is detected
* @throws ServiceNotFoundException When the service is not defined
*
* @see Reference
*/
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 bool true if the service is defined, false otherwise
*/
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
*/
public function getParameter($name);
/**
* Checks if a parameter exists.
*
* @param string $name The parameter name
*
* @return bool The presence of parameter in container
*/
public function hasParameter($name);
/**
* Sets a parameter.
*
* @param string $name The parameter name
* @param mixed $value The parameter value
*/
public function setParameter($name, $value);
/**
* Enters the given scope.
*
* @param string $name
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function enterScope($name);
/**
* Leaves the current scope, and re-enters the parent scope.
*
* @param string $name
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function leaveScope($name);
/**
* Adds a scope to the container.
*
* @param ScopeInterface $scope
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function addScope(ScopeInterface $scope);
/**
* Whether this container has the given scope.
*
* @param string $name
*
* @return bool
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
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 bool
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function isScopeActive($name);
}
{
"name": "symfony/dependency-injection",
"type": "library",
"description": "Symfony DependencyInjection Component",
"keywords": [],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=5.3.9"
},
"require-dev": {
"symfony/yaml": "~2.3.42|~2.7.14|~2.8.7|~3.0.7",
"symfony/config": "~2.2|~3.0.0",
"symfony/expression-language": "~2.6|~3.0.0"
},
"conflict": {
"symfony/expression-language": "<2.6"
},
"suggest": {
"symfony/yaml": "",
"symfony/config": "",
"symfony/expression-language": "For using expressions in service container configuration",
"symfony/proxy-manager-bridge": "Generate service proxies to lazy load them"
},
"autoload": {
"psr-4": { "Symfony\\Component\\DependencyInjection\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "2.8-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\Dumper;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
use Symfony\Component\DependencyInjection\ExpressionLanguage;
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface as ProxyDumper;
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Variable;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
use Symfony\Component\HttpKernel\Kernel;
/**
* PhpDumper dumps a service container as a PHP class.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class PhpDumper extends Dumper
{
/**
* Characters that might appear in the generated variable name as first character.
*/
const FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz';
/**
* Characters that might appear in the generated variable name as any but the first character.
*/
const NON_FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789_';
private $inlinedDefinitions;
private $definitionVariables;
private $referenceVariables;
private $variableCount;
private $reservedVariables = array('instance', 'class');
private $expressionLanguage;
private $targetDirRegex;
private $targetDirMaxMatches;
private $docStar;
/**
* @var ExpressionFunctionProviderInterface[]
*/
private $expressionLanguageProviders = array();
/**
* @var ProxyDumper
*/
private $proxyDumper;
/**
* {@inheritdoc}
*/
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.
*/
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
* * namespace: The class namespace
*
* @return string A PHP class representing of the service container
*/
public function dump(array $options = array())
{
$this->targetDirRegex = null;
$options = array_merge(array(
'class' => 'ProjectServiceContainer',
'base_class' => 'Container',
'namespace' => '',
'debug' => true,
), $options);
$this->docStar = $options['debug'] ? '*' : '';
if (!empty($options['file']) && is_dir($dir = \dirname($options['file']))) {
// Build a regexp where the first root dirs are mandatory,
// but every other sub-dir is optional up to the full path in $dir
// Mandate at least 2 root dirs and not more that 5 optional dirs.
$dir = explode(\DIRECTORY_SEPARATOR, realpath($dir));
$i = \count($dir);
if (3 <= $i) {
$regex = '';
$lastOptionalDir = $i > 8 ? $i - 5 : 3;
$this->targetDirMaxMatches = $i - $lastOptionalDir;
while (--$i >= $lastOptionalDir) {
$regex = sprintf('(%s%s)?', preg_quote(\DIRECTORY_SEPARATOR.$dir[$i], '#'), $regex);
}
do {
$regex = preg_quote(\DIRECTORY_SEPARATOR.$dir[$i], '#').$regex;
} while (0 < --$i);
$this->targetDirRegex = '#'.preg_quote($dir[0], '#').$regex.'#';
}
}
$code = $this->startClass($options['class'], $options['base_class'], $options['namespace']);
if ($this->container->isFrozen()) {
$code .= $this->addFrozenConstructor();
$code .= $this->addFrozenCompile();
$code .= $this->addIsFrozenMethod();
} else {
$code .= $this->addConstructor();
}
$code .=
$this->addServices().
$this->addDefaultParametersMethod().
$this->endClass().
$this->addProxyClasses()
;
$this->targetDirRegex = null;
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);
$this->getServiceCallsFromArguments(array($iDefinition->getConfigurator()), $calls, $behavior);
$this->getServiceCallsFromArguments(array($iDefinition->getFactory()), $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 $definitions Definition[] */
$definitions = array_filter(
$this->container->getDefinitions(),
array($this->getProxyDumper(), 'isProxyCandidate')
);
$code = '';
$strip = '' === $this->docStar && method_exists('Symfony\Component\HttpKernel\Kernel', 'stripComments');
foreach ($definitions as $definition) {
if ("\n" === $proxyCode = "\n".$this->getProxyDumper()->getProxyCode($definition)) {
continue;
}
if ($strip) {
$proxyCode = "<?php\n".$proxyCode;
$proxyCode = substr(Kernel::stripComments($proxyCode), 5);
}
$code .= $proxyCode;
}
return $code;
}
/**
* Generates the require_once statement for service includes.
*
* @return string
*/
private function addServiceInclude(Definition $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 $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->addServiceProperties($sDefinition, $name);
$code .= $this->addServiceMethodCalls($sDefinition, $name);
$code .= $this->addServiceConfigurator($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 $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 $definition)
{
$class = $this->dumpValue($definition->getClass());
if (0 === strpos($class, "'") && !preg_match('/^\'(?:\\\{2})?[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 && $definition->isShared() && ContainerInterface::SCOPE_CONTAINER === $definition->getScope(false)) {
$instantiation = sprintf('$this->services[%s] = %s', var_export($id, true), $simple ? '' : '$instance');
} elseif (!$isProxyCandidate && $definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $scope = $definition->getScope(false)) {
$instantiation = sprintf('$this->services[%s] = $this->scopedServices[%s][%1$s] = %s', var_export($id, true), var_export($scope, true), $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 bool
*/
private function isSimpleInstance($id, Definition $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 Definition $definition
* @param string $variableName
*
* @return string
*/
private function addServiceMethodCalls(Definition $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(Definition $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
*
* @throws ServiceCircularReferenceException when the container contains a circular reference
*/
private function addServiceInlinedDefinitionsSetup($id, Definition $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;
}
// if the instance is simple, the return statement has already been generated
// so, the only possible way to get there is because of a circular reference
if ($this->isSimpleInstance($id, $definition)) {
throw new ServiceCircularReferenceException($id, array($id));
}
$name = (string) $this->definitionVariables->offsetGet($iDefinition);
$code .= $this->addServiceProperties($iDefinition, $name);
$code .= $this->addServiceMethodCalls($iDefinition, $name);
$code .= $this->addServiceConfigurator($iDefinition, $name);
}
if ('' !== $code) {
$code .= "\n";
}
return $code;
}
/**
* Adds configurator definition.
*
* @param Definition $definition
* @param string $variableName
*
* @return string
*/
private function addServiceConfigurator(Definition $definition, $variableName = 'instance')
{
if (!$callable = $definition->getConfigurator()) {
return '';
}
if (\is_array($callable)) {
if ($callable[0] instanceof Reference
|| ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) {
return sprintf(" %s->%s(\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
}
$class = $this->dumpValue($callable[0]);
// If the class is a string we can optimize call_user_func away
if (0 === strpos($class, "'")) {
return sprintf(" %s::%s(\$%s);\n", $this->dumpLiteralClass($class), $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 $definition)
{
$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(0 === strpos($class, '%') ? '@return object A %1$s instance' : '@return \%s', ltrim($class, '\\'));
} elseif ($definition->getFactory()) {
$factory = $definition->getFactory();
if (\is_string($factory)) {
$return[] = sprintf('@return object An instance returned by %s()', $factory);
} elseif (\is_array($factory) && (\is_string($factory[0]) || $factory[0] instanceof Definition || $factory[0] instanceof Reference)) {
if (\is_string($factory[0]) || $factory[0] instanceof Reference) {
$return[] = sprintf('@return object An instance returned by %s::%s()', (string) $factory[0], $factory[1]);
} elseif ($factory[0] instanceof Definition) {
$return[] = sprintf('@return object An instance returned by %s::%s()', $factory[0]->getClass(), $factory[1]);
}
}
} elseif ($definition->getFactoryClass(false)) {
$return[] = sprintf('@return object An instance returned by %s::%s()', $definition->getFactoryClass(false), $definition->getFactoryMethod(false));
} elseif ($definition->getFactoryService(false)) {
$return[] = sprintf('@return object An instance returned by %s::%s()', $definition->getFactoryService(false), $definition->getFactoryMethod(false));
}
$scope = $definition->getScope(false);
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);
}
if ($definition->isDeprecated()) {
if ($return && 0 === strpos($return[\count($return) - 1], '@return')) {
$return[] = '';
}
$return[] = sprintf('@deprecated %s', $definition->getDeprecationMessage($id));
}
$return = str_replace("\n * \n", "\n *\n", implode("\n * ", $return));
$shared = $definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $scope ? ' shared' : '';
$public = $definition->isPublic() ? 'public' : 'private';
$autowired = $definition->isAutowired() ? ' autowired' : '';
if ($definition->isLazy()) {
$lazyInitialization = '$lazyLoad = true';
} else {
$lazyInitialization = '';
}
// 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
/*{$this->docStar}
* Gets the $public '$id'$shared$autowired service.
*
* $return
EOF;
$code = str_replace('*/', ' ', $code).<<<EOF
*/
{$visibility} function get{$this->camelize($id)}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({$this->export($id)}, '$scope');
}
EOF;
}
if ($definition->isSynthetic()) {
$code .= sprintf(" throw new RuntimeException(%s);\n }\n", var_export("You have requested a synthetic service (\"$id\"). The DIC does not know how to construct this service.", true));
} else {
if ($definition->isDeprecated()) {
$code .= sprintf(" @trigger_error(%s, E_USER_DEPRECATED);\n\n", var_export($definition->getDeprecationMessage($id), true));
}
$code .=
$this->addServiceInclude($definition).
$this->addServiceLocalTempVariables($id, $definition).
$this->addServiceInlinedDefinitions($id, $definition).
$this->addServiceInstance($id, $definition).
$this->addServiceInlinedDefinitionsSetup($id, $definition).
$this->addServiceProperties($definition).
$this->addServiceMethodCalls($definition).
$this->addServiceConfigurator($definition).
$this->addServiceReturn($id, $definition)
;
}
$this->definitionVariables = null;
$this->referenceVariables = null;
return $code;
}
/**
* Adds multiple services.
*
* @return string
*/
private function addServices()
{
$publicServices = $privateServices = $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);
}
return $publicServices.$synchronizers.$privateServices;
}
/**
* Adds synchronizer methods.
*
* @param string $id A service identifier
* @param Definition $definition A Definition instance
*
* @return string|null
*
* @deprecated since version 2.7, will be removed in 3.0.
*/
private function addServiceSynchronizer($id, Definition $definition)
{
if (!$definition->isSynchronized(false)) {
return;
}
if ('request' !== $id) {
@trigger_error('Synchronized services were deprecated in version 2.7 and won\'t work anymore in 3.0.', E_USER_DEPRECATED);
}
$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);
}
$definitionId = var_export($definitionId, true);
$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;
}
return <<<EOF
/*{$this->docStar}
* Updates the '$id' service.
*/
protected function synchronize{$this->camelize($id)}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->getFactory()) {
$callable = $definition->getFactory();
if (\is_array($callable)) {
if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $callable[1])) {
throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s)', $callable[1] ?: 'n/a'));
}
if ($callable[0] instanceof Reference
|| ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) {
return sprintf(" $return{$instantiation}%s->%s(%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? implode(', ', $arguments) : '');
}
$class = $this->dumpValue($callable[0]);
// If the class is a string we can optimize call_user_func away
if (0 === strpos($class, "'")) {
return sprintf(" $return{$instantiation}%s::%s(%s);\n", $this->dumpLiteralClass($class), $callable[1], $arguments ? implode(', ', $arguments) : '');
}
return sprintf(" $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($callable[0]), $callable[1], $arguments ? ', '.implode(', ', $arguments) : '');
}
return sprintf(" $return{$instantiation}\\%s(%s);\n", $callable, $arguments ? implode(', ', $arguments) : '');
} elseif (null !== $definition->getFactoryMethod(false)) {
if (null !== $definition->getFactoryClass(false)) {
$class = $this->dumpValue($definition->getFactoryClass(false));
// If the class is a string we can optimize call_user_func away
if (0 === strpos($class, "'")) {
return sprintf(" $return{$instantiation}%s::%s(%s);\n", $this->dumpLiteralClass($class), $definition->getFactoryMethod(false), $arguments ? implode(', ', $arguments) : '');
}
return sprintf(" $return{$instantiation}call_user_func(array(%s, '%s')%s);\n", $this->dumpValue($definition->getFactoryClass(false)), $definition->getFactoryMethod(false), $arguments ? ', '.implode(', ', $arguments) : '');
}
if (null !== $definition->getFactoryService(false)) {
return sprintf(" $return{$instantiation}%s->%s(%s);\n", $this->getServiceCall($definition->getFactoryService(false)), $definition->getFactoryMethod(false), 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", $this->dumpLiteralClass($class), implode(', ', $arguments));
}
/**
* Adds the class headers.
*
* @param string $class Class name
* @param string $baseClass The name of the base class
* @param string $namespace The class namespace
*
* @return string
*/
private function startClass($class, $baseClass, $namespace)
{
$bagClass = $this->container->isFrozen() ? 'use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;' : 'use Symfony\Component\DependencyInjection\ParameterBag\\ParameterBag;';
$namespaceLine = $namespace ? "\nnamespace $namespace;\n" : '';
return <<<EOF
<?php
$namespaceLine
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;
$bagClass
/*{$this->docStar}
* This class has been auto-generated
* by the Symfony Dependency Injection Component.
*/
class $class extends $baseClass
{
private \$parameters;
private \$targetDirs = array();
EOF;
}
/**
* Adds the constructor.
*
* @return string
*/
private function addConstructor()
{
$targetDirs = $this->exportTargetDirs();
$arguments = $this->container->getParameterBag()->all() ? 'new ParameterBag($this->getDefaultParameters())' : null;
$code = <<<EOF
public function __construct()
{{$targetDirs}
parent::__construct($arguments);
EOF;
if (\count($scopes = $this->container->getScopes(false)) > 0) {
$code .= "\n";
$code .= ' $this->scopes = '.$this->dumpValue($scopes).";\n";
$code .= ' $this->scopeChildren = '.$this->dumpValue($this->container->getScopeChildren(false)).";\n";
}
$code .= $this->addMethodMap();
$code .= $this->addAliases();
$code .= <<<'EOF'
}
EOF;
return $code;
}
/**
* Adds the constructor for a frozen container.
*
* @return string
*/
private function addFrozenConstructor()
{
$targetDirs = $this->exportTargetDirs();
$code = <<<EOF
public function __construct()
{{$targetDirs}
EOF;
if ($this->container->getParameterBag()->all()) {
$code .= "\n \$this->parameters = \$this->getDefaultParameters();\n";
}
$code .= <<<'EOF'
$this->services =
$this->scopedServices =
$this->scopeStacks = array();
EOF;
$code .= "\n";
if (\count($scopes = $this->container->getScopes(false)) > 0) {
$code .= ' $this->scopes = '.$this->dumpValue($scopes).";\n";
$code .= ' $this->scopeChildren = '.$this->dumpValue($this->container->getScopeChildren(false)).";\n";
} else {
$code .= " \$this->scopes = array();\n";
$code .= " \$this->scopeChildren = array();\n";
}
$code .= $this->addMethodMap();
$code .= $this->addAliases();
$code .= <<<'EOF'
}
EOF;
return $code;
}
/**
* Adds the constructor for a frozen container.
*
* @return string
*/
private function addFrozenCompile()
{
return <<<EOF
/*{$this->docStar}
* {@inheritdoc}
*/
public function compile()
{
throw new LogicException('You cannot compile a dumped frozen container.');
}
EOF;
}
/**
* Adds the isFrozen method for a frozen container.
*
* @return string
*/
private function addIsFrozenMethod()
{
return <<<EOF
/*{$this->docStar}
* {@inheritdoc}
*/
public function isFrozen()
{
return true;
}
EOF;
}
/**
* Adds the methodMap property definition.
*
* @return string
*/
private function addMethodMap()
{
if (!$definitions = $this->container->getDefinitions()) {
return '';
}
$code = " \$this->methodMap = array(\n";
ksort($definitions);
foreach ($definitions as $id => $definition) {
$code .= ' '.var_export($id, true).' => '.var_export('get'.$this->camelize($id).'Service', true).",\n";
}
return $code." );\n";
}
/**
* Adds the aliases property definition.
*
* @return string
*/
private function addAliases()
{
if (!$aliases = $this->container->getAliases()) {
return $this->container->isFrozen() ? "\n \$this->aliases = array();\n" : '';
}
$code = " \$this->aliases = array(\n";
ksort($aliases);
foreach ($aliases as $alias => $id) {
$id = (string) $id;
while (isset($aliases[$id])) {
$id = (string) $aliases[$id];
}
$code .= ' '.var_export($alias, true).' => '.var_export($id, true).",\n";
}
return $code." );\n";
}
/**
* 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;
if ('' === $this->docStar) {
$code = str_replace('/**', '/*', $code);
}
}
$code .= <<<EOF
/*{$this->docStar}
* 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 int $indent
*
* @return string
*
* @throws InvalidArgumentException
*/
private function exportParameters(array $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));
} elseif ($value instanceof Expression) {
throw new InvalidArgumentException(sprintf('You cannot dump a container with parameters that contain expressions. Expression "%s" found in "%s".', $value, $path.'/'.$key));
} else {
$value = $this->export($value);
}
$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)', var_export($service, true));
}
// 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.
*/
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];
}
}
}
/**
* Returns the inline 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->getDefinitionsFromArguments(array($definition->getConfigurator())),
$this->getDefinitionsFromArguments(array($definition->getFactory()))
);
$this->inlinedDefinitions->offsetSet($definition, $definitions);
return $definitions;
}
return $this->inlinedDefinitions->offsetGet($definition);
}
/**
* Gets the definition from 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 bool $deep
* @param array $visited
*
* @return bool
*/
private function hasReference($id, array $arguments, $deep = false, array &$visited = array())
{
foreach ($arguments as $argument) {
if (\is_array($argument)) {
if ($this->hasReference($id, $argument, $deep, $visited)) {
return true;
}
} elseif ($argument instanceof Reference) {
$argumentId = (string) $argument;
if ($id === $argumentId) {
return true;
}
if ($deep && !isset($visited[$argumentId]) && 'service_container' !== $argumentId) {
$visited[$argumentId] = true;
$service = $this->container->getDefinition($argumentId);
// if the proxy manager is enabled, disable searching for references in lazy services,
// as these services will be instantiated lazily and don't have direct related references.
if ($service->isLazy() && !$this->getProxyDumper() instanceof NullDumper) {
continue;
}
$arguments = array_merge($service->getMethodCalls(), $service->getArguments(), $service->getProperties());
if ($this->hasReference($id, $arguments, $deep, $visited)) {
return true;
}
}
}
}
return false;
}
/**
* Dumps values.
*
* @param mixed $value
* @param bool $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 ($value->getMethodCalls()) {
throw new RuntimeException('Cannot dump definitions which have method calls.');
}
if ($value->getProperties()) {
throw new RuntimeException('Cannot dump definitions which have properties.');
}
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);
}
if (null !== $value->getFactory()) {
$factory = $value->getFactory();
if (\is_string($factory)) {
return sprintf('\\%s(%s)', $factory, implode(', ', $arguments));
}
if (\is_array($factory)) {
if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $factory[1])) {
throw new RuntimeException(sprintf('Cannot dump definition because of invalid factory method (%s)', $factory[1] ?: 'n/a'));
}
if (\is_string($factory[0])) {
return sprintf('%s::%s(%s)', $this->dumpLiteralClass($this->dumpValue($factory[0])), $factory[1], implode(', ', $arguments));
}
if ($factory[0] instanceof Definition) {
return sprintf("call_user_func(array(%s, '%s')%s)", $this->dumpValue($factory[0]), $factory[1], \count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
}
if ($factory[0] instanceof Reference) {
return sprintf('%s->%s(%s)', $this->dumpValue($factory[0]), $factory[1], implode(', ', $arguments));
}
}
throw new RuntimeException('Cannot dump definition because of invalid factory');
}
if (null !== $value->getFactoryMethod(false)) {
if (null !== $value->getFactoryClass(false)) {
return sprintf("call_user_func(array(%s, '%s')%s)", $this->dumpValue($value->getFactoryClass(false)), $value->getFactoryMethod(false), \count($arguments) > 0 ? ', '.implode(', ', $arguments) : '');
} elseif (null !== $value->getFactoryService(false)) {
$service = $this->dumpValue($value->getFactoryService(false));
return sprintf('%s->%s(%s)', 0 === strpos($service, '$') ? sprintf('$this->get(%s)', $service) : $this->getServiceCall($value->getFactoryService(false)), $value->getFactoryMethod(false), implode(', ', $arguments));
}
throw new RuntimeException('Cannot dump definitions which have factory method without factory service or factory class.');
}
$class = $value->getClass();
if (null === $class) {
throw new RuntimeException('Cannot dump definitions which have no class nor factory.');
}
return sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), 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 Expression) {
return $this->getExpressionLanguage()->compile((string) $value, array('this' => 'container'));
} 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, $this->export($value)));
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.');
}
return $this->export($value);
}
/**
* Dumps a string to a literal (aka PHP Code) class value.
*
* @param string $class
*
* @return string
*
* @throws RuntimeException
*/
private function dumpLiteralClass($class)
{
if (false !== strpos($class, '$')) {
throw new RuntimeException('Cannot dump definitions which have a variable class name.');
}
if (0 !== strpos($class, "'") || !preg_match('/^\'(?:\\\{2})?[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 RuntimeException(sprintf('Cannot dump definition because of invalid class name (%s)', $class ?: 'n/a'));
}
$class = substr(str_replace('\\\\', '\\', $class), 1, -1);
return 0 === strpos($class, '\\') ? $class : '\\'.$class;
}
/**
* Dumps a parameter.
*
* @param string $name
*
* @return string
*/
public function dumpParameter($name)
{
$name = (string) $name;
if ($this->container->isFrozen() && $this->container->hasParameter($name)) {
return $this->dumpValue($this->container->getParameter($name), false);
}
return sprintf('$this->getParameter(%s)', var_export($name, true));
}
/**
* @deprecated since version 2.6.2, to be removed in 3.0.
* Use \Symfony\Component\DependencyInjection\ContainerBuilder::addExpressionLanguageProvider instead.
*
* @param ExpressionFunctionProviderInterface $provider
*/
public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
{
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.6.2 and will be removed in 3.0. Use the Symfony\Component\DependencyInjection\ContainerBuilder::addExpressionLanguageProvider method instead.', E_USER_DEPRECATED);
$this->expressionLanguageProviders[] = $provider;
}
/**
* Gets a service call.
*
* @param string $id
* @param Reference $reference
*
* @return string
*/
private function getServiceCall($id, Reference $reference = null)
{
while ($this->container->hasAlias($id)) {
$id = (string) $this->container->getAlias($id);
}
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)', var_export($id, true));
}
return sprintf('$this->get(%s)', var_export($id, true));
}
/**
* Convert a service id to a valid PHP method name.
*
* @param string $id
*
* @return string
*
* @throws InvalidArgumentException
*/
private function camelize($id)
{
$name = Container::camelize($id);
if (!preg_match('/^[a-zA-Z0-9_\x7f-\xff]+$/', $name)) {
throw new InvalidArgumentException(sprintf('Service id "%s" cannot be converted to a valid PHP method name.', $id));
}
return $name;
}
/**
* 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 = (int) ($i / $firstCharsLength);
}
while ($i > 0) {
--$i;
$name .= $nonFirstChars[$i % $nonFirstCharsLength];
$i = (int) ($i / $nonFirstCharsLength);
}
++$this->variableCount;
// check that the name is not reserved
if (\in_array($name, $this->reservedVariables, true)) {
continue;
}
return $name;
}
}
private function getExpressionLanguage()
{
if (null === $this->expressionLanguage) {
if (!class_exists('Symfony\Component\ExpressionLanguage\ExpressionLanguage')) {
throw new RuntimeException('Unable to use expressions as the Symfony ExpressionLanguage component is not installed.');
}
$providers = array_merge($this->container->getExpressionLanguageProviders(), $this->expressionLanguageProviders);
$this->expressionLanguage = new ExpressionLanguage(null, $providers);
if ($this->container->isTrackingResources()) {
foreach ($providers as $provider) {
$this->container->addObjectResource($provider);
}
}
}
return $this->expressionLanguage;
}
private function exportTargetDirs()
{
return null === $this->targetDirRegex ? '' : <<<EOF
\$dir = __DIR__;
for (\$i = 1; \$i <= {$this->targetDirMaxMatches}; ++\$i) {
\$this->targetDirs[\$i] = \$dir = dirname(\$dir);
}
EOF;
}
private function export($value)
{
if (null !== $this->targetDirRegex && \is_string($value) && preg_match($this->targetDirRegex, $value, $matches, PREG_OFFSET_CAPTURE)) {
$prefix = $matches[0][1] ? var_export(substr($value, 0, $matches[0][1]), true).'.' : '';
$suffix = $matches[0][1] + \strlen($matches[0][0]);
$suffix = isset($value[$suffix]) ? '.'.var_export(substr($value, $suffix), true) : '';
$dirname = '__DIR__';
if (0 < $offset = 1 + $this->targetDirMaxMatches - \count($matches)) {
$dirname = sprintf('$this->targetDirs[%d]', $offset);
}
if ($prefix || $suffix) {
return sprintf('(%s%s%s)', $prefix, $dirname, $suffix);
}
return $dirname;
}
if (\is_string($value) && false !== strpos($value, "\n")) {
$cleanParts = explode("\n", $value);
$cleanParts = array_map(function ($part) { return var_export($part, true); }, $cleanParts);
return implode('."\n".', $cleanParts);
}
return var_export($value, 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\DependencyInjection\Dumper;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\ExpressionLanguage\Expression;
/**
* XmlDumper dumps a service container as an XML string.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Martin Hasoň <martin.hason@gmail.com>
*/
class XmlDumper extends Dumper
{
/**
* @var \DOMDocument
*/
private $document;
/**
* Dumps the service container as an XML string.
*
* @return string An xml string representing of the service container
*/
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;
}
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);
}
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 ($class = $definition->getClass()) {
if ('\\' === substr($class, 0, 1)) {
$class = substr($class, 1);
}
$service->setAttribute('class', $class);
}
if ($definition->getFactoryMethod(false)) {
$service->setAttribute('factory-method', $definition->getFactoryMethod(false));
}
if ($definition->getFactoryClass(false)) {
$service->setAttribute('factory-class', $definition->getFactoryClass(false));
}
if ($definition->getFactoryService(false)) {
$service->setAttribute('factory-service', $definition->getFactoryService(false));
}
if (!$definition->isShared()) {
$service->setAttribute('shared', 'false');
}
if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope(false)) {
$service->setAttribute('scope', $scope);
}
if (!$definition->isPublic()) {
$service->setAttribute('public', 'false');
}
if ($definition->isSynthetic()) {
$service->setAttribute('synthetic', 'true');
}
if ($definition->isSynchronized(false)) {
$service->setAttribute('synchronized', 'true');
}
if ($definition->isLazy()) {
$service->setAttribute('lazy', 'true');
}
if (null !== $decorated = $definition->getDecoratedService()) {
list($decorated, $renamedId, $priority) = $decorated;
$service->setAttribute('decorates', $decorated);
if (null !== $renamedId) {
$service->setAttribute('decoration-inner-name', $renamedId);
}
if (0 !== $priority) {
$service->setAttribute('decoration-priority', $priority);
}
}
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->getFactory()) {
$factory = $this->document->createElement('factory');
if (\is_array($callable) && $callable[0] instanceof Definition) {
$this->addService($callable[0], null, $factory);
$factory->setAttribute('method', $callable[1]);
} elseif (\is_array($callable)) {
$factory->setAttribute($callable[0] instanceof Reference ? 'service' : 'class', $callable[0]);
$factory->setAttribute('method', $callable[1]);
} else {
$factory->setAttribute('function', $callable);
}
$service->appendChild($factory);
}
if ($definition->isDeprecated()) {
$deprecated = $this->document->createElement('deprecated');
$deprecated->appendChild($this->document->createTextNode($definition->getDeprecationMessage('%service_id%')));
$service->appendChild($deprecated);
}
if ($definition->isAutowired()) {
$service->setAttribute('autowire', 'true');
}
foreach ($definition->getAutowiringTypes() as $autowiringTypeValue) {
$autowiringType = $this->document->createElement('autowiring-type');
$autowiringType->appendChild($this->document->createTextNode($autowiringTypeValue));
$service->appendChild($autowiringType);
}
if ($definition->isAbstract()) {
$service->setAttribute('abstract', 'true');
}
if ($callable = $definition->getConfigurator()) {
$configurator = $this->document->createElement('configurator');
if (\is_array($callable) && $callable[0] instanceof Definition) {
$this->addService($callable[0], null, $configurator);
$configurator->setAttribute('method', $callable[1]);
} elseif (\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 Alias $id
* @param \DOMElement $parent
*/
private function addServiceAlias($alias, 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);
}
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);
}
$aliases = $this->container->getAliases();
foreach ($aliases as $alias => $id) {
while (isset($aliases[(string) $id])) {
$id = $aliases[(string) $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(array $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 (ContainerInterface::NULL_ON_INVALID_REFERENCE == $behaviour) {
$element->setAttribute('on-invalid', 'null');
} elseif (ContainerInterface::IGNORE_ON_INVALID_REFERENCE == $behaviour) {
$element->setAttribute('on-invalid', 'ignore');
}
if (!$value->isStrict(false)) {
$element->setAttribute('strict', 'false');
}
} elseif ($value instanceof Definition) {
$element->setAttribute('type', 'service');
$this->addService($value, null, $element);
} elseif ($value instanceof Expression) {
$element->setAttribute('type', 'expression');
$text = $this->document->createTextNode(self::phpToXml((string) $value));
$element->appendChild($text);
} 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.
*
* @return array
*/
private function escape(array $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\DependencyInjection\ContainerBuilder;
/**
* Dumper is the abstract class for all built-in dumpers.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class Dumper implements DumperInterface
{
protected $container;
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\Alias;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\Yaml\Dumper as YmlDumper;
/**
* YamlDumper dumps a service container as a YAML string.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class YamlDumper extends Dumper
{
private $dumper;
/**
* Dumps the service container as an YAML string.
*
* @return string A YAML string representing of the service container
*/
public function dump(array $options = array())
{
if (!class_exists('Symfony\Component\Yaml\Dumper')) {
throw new RuntimeException('Unable to dump the container as the Symfony Yaml Component is not installed.');
}
if (null === $this->dumper) {
$this->dumper = new YmlDumper();
}
return $this->addParameters()."\n".$this->addServices();
}
/**
* Adds a service.
*
* @param string $id
* @param Definition $definition
*
* @return string
*/
private function addService($id, Definition $definition)
{
$code = " $id:\n";
if ($class = $definition->getClass()) {
if ('\\' === substr($class, 0, 1)) {
$class = substr($class, 1);
}
$code .= sprintf(" class: %s\n", $this->dumper->dump($class));
}
if (!$definition->isPublic()) {
$code .= " public: false\n";
}
$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", $this->dumper->dump($definition->getFile()));
}
if ($definition->isSynthetic()) {
$code .= " synthetic: true\n";
}
if ($definition->isSynchronized(false)) {
$code .= " synchronized: true\n";
}
if ($definition->isDeprecated()) {
$code .= sprintf(" deprecated: %s\n", $this->dumper->dump($definition->getDeprecationMessage('%service_id%')));
}
if ($definition->isAutowired()) {
$code .= " autowire: true\n";
}
$autowiringTypesCode = '';
foreach ($definition->getAutowiringTypes() as $autowiringType) {
$autowiringTypesCode .= sprintf(" - %s\n", $this->dumper->dump($autowiringType));
}
if ($autowiringTypesCode) {
$code .= sprintf(" autowiring_types:\n%s", $autowiringTypesCode);
}
if ($definition->getFactoryClass(false)) {
$code .= sprintf(" factory_class: %s\n", $this->dumper->dump($definition->getFactoryClass(false)));
}
if ($definition->isAbstract()) {
$code .= " abstract: true\n";
}
if ($definition->isLazy()) {
$code .= " lazy: true\n";
}
if ($definition->getFactoryMethod(false)) {
$code .= sprintf(" factory_method: %s\n", $this->dumper->dump($definition->getFactoryMethod(false)));
}
if ($definition->getFactoryService(false)) {
$code .= sprintf(" factory_service: %s\n", $this->dumper->dump($definition->getFactoryService(false)));
}
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 (!$definition->isShared()) {
$code .= " shared: false\n";
}
if (ContainerInterface::SCOPE_CONTAINER !== $scope = $definition->getScope(false)) {
$code .= sprintf(" scope: %s\n", $this->dumper->dump($scope));
}
if (null !== $decorated = $definition->getDecoratedService()) {
list($decorated, $renamedId, $priority) = $decorated;
$code .= sprintf(" decorates: %s\n", $decorated);
if (null !== $renamedId) {
$code .= sprintf(" decoration_inner_name: %s\n", $renamedId);
}
if (0 !== $priority) {
$code .= sprintf(" decoration_priority: %s\n", $priority);
}
}
if ($callable = $definition->getFactory()) {
$code .= sprintf(" factory: %s\n", $this->dumper->dump($this->dumpCallable($callable), 0));
}
if ($callable = $definition->getConfigurator()) {
$code .= sprintf(" configurator: %s\n", $this->dumper->dump($this->dumpCallable($callable), 0));
}
return $code;
}
/**
* Adds a service alias.
*
* @param string $alias
* @param Alias $id
*
* @return string
*/
private function addServiceAlias($alias, Alias $id)
{
if ($id->isPublic()) {
return sprintf(" %s: '@%s'\n", $alias, $id);
}
return sprintf(" %s:\n alias: %s\n public: false\n", $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);
}
$aliases = $this->container->getAliases();
foreach ($aliases as $alias => $id) {
while (isset($aliases[(string) $id])) {
$id = $aliases[(string) $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 callable to YAML format.
*
* @param callable $callable
*
* @return callable
*/
private function dumpCallable($callable)
{
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]);
}
}
return $callable;
}
/**
* 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 ($value instanceof Expression) {
return $this->getExpressionCall((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);
}
private function getExpressionCall($expression)
{
return sprintf('@=%s', $expression);
}
/**
* Prepares parameters.
*
* @param array $parameters
* @param bool $escape
*
* @return array
*/
private function prepareParameters(array $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.
*
* @return array
*/
private function escape(array $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\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Scope;
/**
* 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
*
* @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 bool $required
* @param string $name
*
* @return array An array of edges
*/
private function findEdges($id, array $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) {
$class = $definition->getClass();
if ('\\' === substr($class, 0, 1)) {
$class = substr($class, 1);
}
try {
$class = $this->container->getParameterBag()->resolveValue($class);
} catch (ParameterNotFoundException $e) {
}
$nodes[$id] = array('class' => str_replace('\\', '\\\\', $class), 'attributes' => array_merge($this->options['node.definition'], array('style' => $definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope(false) ? 'filled' : 'dotted')));
$container->setDefinition($id, new Definition('stdClass'));
}
foreach ($container->getServiceIds() as $id) {
$service = $container->get($id);
if (array_key_exists($id, $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(false) as $scope => $parentScope) {
$container->addScope(new Scope($scope, $parentScope));
}
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(array $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(array $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>
*/
interface DumperInterface
{
/**
* Dumps the service container.
*
* @param array $options An array of options
*
* @return string The representation of the service container
*/
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;
/**
* 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;
/**
* @param string $name
*/
public function __construct($name)
{
$this->name = $name;
}
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\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 within the file to change the container.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class PhpFileLoader extends FileLoader
{
/**
* {@inheritdoc}
*/
public function load($resource, $type = null)
{
// the container and loader variables are exposed to the included file below
$container = $this->container;
$loader = $this;
$path = $this->locator->locate($resource);
$this->setCurrentDir(\dirname($path));
$this->container->addResource(new FileResource($path));
include $path;
}
/**
* {@inheritdoc}
*/
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\Loader;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\Config\Util\XmlUtils;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\ExpressionLanguage\Expression;
/**
* XmlFileLoader loads XML files service definitions.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class XmlFileLoader extends FileLoader
{
const NS = 'http://symfony.com/schema/dic/services';
/**
* {@inheritdoc}
*/
public function load($resource, $type = null)
{
$path = $this->locator->locate($resource);
$xml = $this->parseFileToDOM($path);
$this->container->addResource(new FileResource($path));
// anonymous services
$this->processAnonymousServices($xml, $path);
// imports
$this->parseImports($xml, $path);
// parameters
$this->parseParameters($xml);
// extensions
$this->loadFromExtensions($xml);
// services
$this->parseDefinitions($xml, $path);
}
/**
* {@inheritdoc}
*/
public function supports($resource, $type = null)
{
return \is_string($resource) && 'xml' === pathinfo($resource, PATHINFO_EXTENSION);
}
/**
* Parses parameters.
*
* @param \DOMDocument $xml
*/
private function parseParameters(\DOMDocument $xml)
{
if ($parameters = $this->getChildren($xml->documentElement, 'parameters')) {
$this->container->getParameterBag()->add($this->getArgumentsAsPhp($parameters[0], 'parameter'));
}
}
/**
* Parses imports.
*
* @param \DOMDocument $xml
* @param string $file
*/
private function parseImports(\DOMDocument $xml, $file)
{
$xpath = new \DOMXPath($xml);
$xpath->registerNamespace('container', self::NS);
if (false === $imports = $xpath->query('//container:imports/container:import')) {
return;
}
$defaultDirectory = \dirname($file);
foreach ($imports as $import) {
$this->setCurrentDir($defaultDirectory);
$this->import($import->getAttribute('resource'), null, (bool) XmlUtils::phpize($import->getAttribute('ignore-errors')), $file);
}
}
/**
* Parses multiple definitions.
*
* @param \DOMDocument $xml
* @param string $file
*/
private function parseDefinitions(\DOMDocument $xml, $file)
{
$xpath = new \DOMXPath($xml);
$xpath->registerNamespace('container', self::NS);
if (false === $services = $xpath->query('//container:services/container:service')) {
return;
}
foreach ($services as $service) {
if (null !== $definition = $this->parseDefinition($service, $file)) {
$this->container->setDefinition((string) $service->getAttribute('id'), $definition);
}
}
}
/**
* Parses an individual Definition.
*
* @param \DOMElement $service
* @param string $file
*
* @return Definition|null
*/
private function parseDefinition(\DOMElement $service, $file)
{
if ($alias = $service->getAttribute('alias')) {
$public = true;
if ($publicAttr = $service->getAttribute('public')) {
$public = XmlUtils::phpize($publicAttr);
}
$this->container->setAlias((string) $service->getAttribute('id'), new Alias($alias, $public));
return;
}
if ($parent = $service->getAttribute('parent')) {
$definition = new DefinitionDecorator($parent);
} else {
$definition = new Definition();
}
foreach (array('class', 'shared', 'public', 'factory-class', 'factory-method', 'factory-service', 'synthetic', 'lazy', 'abstract') as $key) {
if ($value = $service->getAttribute($key)) {
if (\in_array($key, array('factory-class', 'factory-method', 'factory-service'))) {
@trigger_error(sprintf('The "%s" attribute of service "%s" in file "%s" is deprecated since Symfony 2.6 and will be removed in 3.0. Use the "factory" element instead.', $key, (string) $service->getAttribute('id'), $file), E_USER_DEPRECATED);
}
$method = 'set'.str_replace('-', '', $key);
$definition->$method(XmlUtils::phpize($value));
}
}
if ($value = $service->getAttribute('autowire')) {
$definition->setAutowired(XmlUtils::phpize($value));
}
if ($value = $service->getAttribute('scope')) {
$triggerDeprecation = 'request' !== (string) $service->getAttribute('id');
if ($triggerDeprecation) {
@trigger_error(sprintf('The "scope" attribute of service "%s" in file "%s" is deprecated since Symfony 2.8 and will be removed in 3.0.', (string) $service->getAttribute('id'), $file), E_USER_DEPRECATED);
}
$definition->setScope(XmlUtils::phpize($value), false);
}
if ($value = $service->getAttribute('synchronized')) {
$triggerDeprecation = 'request' !== (string) $service->getAttribute('id');
if ($triggerDeprecation) {
@trigger_error(sprintf('The "synchronized" attribute of service "%s" in file "%s" is deprecated since Symfony 2.7 and will be removed in 3.0.', (string) $service->getAttribute('id'), $file), E_USER_DEPRECATED);
}
$definition->setSynchronized(XmlUtils::phpize($value), $triggerDeprecation);
}
if ($files = $this->getChildren($service, 'file')) {
$definition->setFile($files[0]->nodeValue);
}
if ($deprecated = $this->getChildren($service, 'deprecated')) {
$definition->setDeprecated(true, $deprecated[0]->nodeValue ?: null);
}
$definition->setArguments($this->getArgumentsAsPhp($service, 'argument'));
$definition->setProperties($this->getArgumentsAsPhp($service, 'property'));
if ($factories = $this->getChildren($service, 'factory')) {
$factory = $factories[0];
if ($function = $factory->getAttribute('function')) {
$definition->setFactory($function);
} else {
$factoryService = $this->getChildren($factory, 'service');
if (isset($factoryService[0])) {
$class = $this->parseDefinition($factoryService[0], $file);
} elseif ($childService = $factory->getAttribute('service')) {
$class = new Reference($childService, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false);
} else {
$class = $factory->getAttribute('class');
}
$definition->setFactory(array($class, $factory->getAttribute('method')));
}
}
if ($configurators = $this->getChildren($service, 'configurator')) {
$configurator = $configurators[0];
if ($function = $configurator->getAttribute('function')) {
$definition->setConfigurator($function);
} else {
$configuratorService = $this->getChildren($configurator, 'service');
if (isset($configuratorService[0])) {
$class = $this->parseDefinition($configuratorService[0], $file);
} elseif ($childService = $configurator->getAttribute('service')) {
$class = new Reference($childService, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false);
} else {
$class = $configurator->getAttribute('class');
}
$definition->setConfigurator(array($class, $configurator->getAttribute('method')));
}
}
foreach ($this->getChildren($service, 'call') as $call) {
$definition->addMethodCall($call->getAttribute('method'), $this->getArgumentsAsPhp($call, 'argument'));
}
foreach ($this->getChildren($service, 'tag') as $tag) {
$parameters = array();
foreach ($tag->attributes as $name => $node) {
if ('name' === $name) {
continue;
}
if (false !== strpos($name, '-') && false === strpos($name, '_') && !array_key_exists($normalizedName = str_replace('-', '_', $name), $parameters)) {
$parameters[$normalizedName] = XmlUtils::phpize($node->nodeValue);
}
// keep not normalized key for BC too
$parameters[$name] = XmlUtils::phpize($node->nodeValue);
}
if ('' === $tag->getAttribute('name')) {
throw new InvalidArgumentException(sprintf('The tag name for service "%s" in %s must be a non-empty string.', (string) $service->getAttribute('id'), $file));
}
$definition->addTag($tag->getAttribute('name'), $parameters);
}
foreach ($this->getChildren($service, 'autowiring-type') as $type) {
$definition->addAutowiringType($type->textContent);
}
if ($value = $service->getAttribute('decorates')) {
$renameId = $service->hasAttribute('decoration-inner-name') ? $service->getAttribute('decoration-inner-name') : null;
$priority = $service->hasAttribute('decoration-priority') ? $service->getAttribute('decoration-priority') : 0;
$definition->setDecoratedService($value, $renameId, $priority);
}
return $definition;
}
/**
* Parses a XML file to a \DOMDocument.
*
* @param string $file Path to a file
*
* @return \DOMDocument
*
* @throws InvalidArgumentException When loading of XML file returns error
*/
private function parseFileToDOM($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 $dom;
}
/**
* Processes anonymous services.
*
* @param \DOMDocument $xml
* @param string $file
*/
private function processAnonymousServices(\DOMDocument $xml, $file)
{
$definitions = array();
$count = 0;
$xpath = new \DOMXPath($xml);
$xpath->registerNamespace('container', self::NS);
// anonymous services as arguments/properties
if (false !== $nodes = $xpath->query('//container:argument[@type="service"][not(@id)]|//container:property[@type="service"][not(@id)]')) {
foreach ($nodes as $node) {
// give it a unique name
$id = sprintf('%s_%d', hash('sha256', $file), ++$count);
$node->setAttribute('id', $id);
if ($services = $this->getChildren($node, 'service')) {
$definitions[$id] = array($services[0], $file, false);
$services[0]->setAttribute('id', $id);
// anonymous services are always private
// we could not use the constant false here, because of XML parsing
$services[0]->setAttribute('public', 'false');
}
}
}
// anonymous services "in the wild"
if (false !== $nodes = $xpath->query('//container:services/container:service[not(@id)]')) {
foreach ($nodes as $node) {
// give it a unique name
$id = sprintf('%s_%d', hash('sha256', $file), ++$count);
$node->setAttribute('id', $id);
$definitions[$id] = array($node, $file, true);
}
}
// resolve definitions
krsort($definitions);
foreach ($definitions as $id => $def) {
list($domElement, $file, $wild) = $def;
if (null !== $definition = $this->parseDefinition($domElement, $file)) {
$this->container->setDefinition($id, $definition);
}
if (true === $wild) {
$tmpDomElement = new \DOMElement('_services', null, self::NS);
$domElement->parentNode->replaceChild($tmpDomElement, $domElement);
$tmpDomElement->setAttribute('id', $id);
} else {
if (null !== $domElement->parentNode) {
$domElement->parentNode->removeChild($domElement);
}
}
}
}
/**
* Returns arguments as valid php types.
*
* @param \DOMElement $node
* @param string $name
* @param bool $lowercase
*
* @return mixed
*/
private function getArgumentsAsPhp(\DOMElement $node, $name, $lowercase = true)
{
$arguments = array();
foreach ($this->getChildren($node, $name) as $arg) {
if ($arg->hasAttribute('name')) {
$arg->setAttribute('key', $arg->getAttribute('name'));
}
// this is used by DefinitionDecorator to overwrite a specific
// argument of the parent definition
if ($arg->hasAttribute('index')) {
$key = 'index_'.$arg->getAttribute('index');
} elseif (!$arg->hasAttribute('key')) {
// Append an empty argument, then fetch its key to overwrite it later
$arguments[] = null;
$keys = array_keys($arguments);
$key = array_pop($keys);
} else {
$key = $arg->getAttribute('key');
// parameter keys are case insensitive
if ('parameter' == $name && $lowercase) {
$key = strtolower($key);
}
}
switch ($arg->getAttribute('type')) {
case 'service':
$onInvalid = $arg->getAttribute('on-invalid');
$invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
if ('ignore' == $onInvalid) {
$invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
} elseif ('null' == $onInvalid) {
$invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE;
}
if ($strict = $arg->getAttribute('strict')) {
$strict = XmlUtils::phpize($strict);
} else {
$strict = true;
}
$arguments[$key] = new Reference($arg->getAttribute('id'), $invalidBehavior, $strict);
break;
case 'expression':
$arguments[$key] = new Expression($arg->nodeValue);
break;
case 'collection':
$arguments[$key] = $this->getArgumentsAsPhp($arg, $name, false);
break;
case 'string':
$arguments[$key] = $arg->nodeValue;
break;
case 'constant':
$arguments[$key] = \constant(trim($arg->nodeValue));
break;
default:
$arguments[$key] = XmlUtils::phpize($arg->nodeValue);
}
}
return $arguments;
}
/**
* Get child elements by name.
*
* @param \DOMNode $node
* @param mixed $name
*
* @return array
*/
private function getChildren(\DOMNode $node, $name)
{
$children = array();
foreach ($node->childNodes as $child) {
if ($child instanceof \DOMElement && $child->localName === $name && self::NS === $child->namespaceURI) {
$children[] = $child;
}
}
return $children;
}
/**
* Validates a documents XML schema.
*
* @param \DOMDocument $dom
*
* @return bool
*
* @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);
$locationstart = 'file:///';
if (0 === stripos($location, 'phar://')) {
$tmpfile = tempnam(sys_get_temp_dir(), 'sf2');
if ($tmpfile) {
copy($location, $tmpfile);
$tmpfiles[] = $tmpfile;
$parts = explode('/', str_replace('\\', '/', $tmpfile));
} else {
array_shift($parts);
$locationstart = 'phar:///';
}
}
$drive = '\\' === \DIRECTORY_SEPARATOR ? array_shift($parts).'/' : '';
$location = $locationstart.$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
;
$disableEntities = libxml_disable_entity_loader(false);
$valid = @$dom->schemaValidateSource($source);
libxml_disable_entity_loader($disableEntities);
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 \DOMDocument $xml
*/
private function loadFromExtensions(\DOMDocument $xml)
{
foreach ($xml->documentElement->childNodes as $node) {
if (!$node instanceof \DOMElement || self::NS === $node->namespaceURI) {
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\Config\FileLocatorInterface;
use Symfony\Component\Config\Loader\FileLoader as BaseFileLoader;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* 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;
public function __construct(ContainerBuilder $container, FileLocatorInterface $locator)
{
$this->container = $container;
parent::__construct($locator);
}
}
<?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\DirectoryResource;
/**
* DirectoryLoader is a recursive loader to go through directories.
*
* @author Sebastien Lavoie <seb@wemakecustom.com>
*/
class DirectoryLoader extends FileLoader
{
/**
* {@inheritdoc}
*/
public function load($file, $type = null)
{
$file = rtrim($file, '/');
$path = $this->locator->locate($file);
$this->container->addResource(new DirectoryResource($path));
foreach (scandir($path) as $dir) {
if ('.' !== $dir[0]) {
if (is_dir($path.'/'.$dir)) {
$dir .= '/'; // append / to allow recursion
}
$this->setCurrentDir($path);
$this->import($dir, null, false, $path);
}
}
}
/**
* {@inheritdoc}
*/
public function supports($resource, $type = null)
{
if ('directory' === $type) {
return true;
}
return null === $type && \is_string($resource) && '/' === substr($resource, -1);
}
}
<?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:group ref="foreign" />
<xsd:sequence minOccurs="0">
<xsd:element name="imports" type="imports" />
<xsd:group ref="foreign" />
</xsd:sequence>
<xsd:sequence minOccurs="0">
<xsd:element name="parameters" type="parameters" />
<xsd:group ref="foreign" />
</xsd:sequence>
<xsd:sequence minOccurs="0">
<xsd:element name="services" type="services" />
<xsd:group ref="foreign" />
</xsd:sequence>
</xsd:sequence>
</xsd:complexType>
<xsd:group name="foreign">
<xsd:sequence>
<xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:group>
<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="callable">
<xsd:choice minOccurs="0" maxOccurs="1">
<xsd:element name="service" type="service" minOccurs="0" maxOccurs="1" />
</xsd:choice>
<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="callable" minOccurs="0" maxOccurs="1" />
<xsd:element name="factory" type="callable" minOccurs="0" maxOccurs="1" />
<xsd:element name="deprecated" type="xsd:string" 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:element name="autowiring-type" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
</xsd:choice>
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="class" type="xsd:string" />
<xsd:attribute name="shared" type="boolean" />
<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:attribute name="decorates" type="xsd:string" />
<xsd:attribute name="decoration-inner-name" type="xsd:string" />
<xsd:attribute name="decoration-priority" type="xsd:integer" />
<xsd:attribute name="autowire" type="boolean" />
</xsd:complexType>
<xsd:complexType name="tag">
<xsd:attribute name="name" type="xsd:string" use="required" />
<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">
<xsd:element name="property" type="property" 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="name" type="xsd:string" />
<xsd:attribute name="on-invalid" type="invalid_sequence" />
<xsd:attribute name="strict" type="boolean" />
</xsd:complexType>
<xsd:complexType name="argument" mixed="true">
<xsd:choice minOccurs="0">
<xsd:element name="argument" type="argument" 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="invalid_sequence" />
<xsd:attribute name="strict" type="boolean" />
</xsd:complexType>
<xsd:complexType name="call">
<xsd:choice minOccurs="0">
<xsd:element name="argument" type="argument" maxOccurs="unbounded" />
</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="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="expression" />
<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\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
{
/**
* {@inheritdoc}
*/
public function load($resource, $type = null)
{
$path = $this->locator->locate($resource);
$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.', $resource));
}
if (isset($result['parameters']) && \is_array($result['parameters'])) {
foreach ($result['parameters'] as $key => $value) {
$this->container->setParameter($key, $value);
}
}
}
/**
* {@inheritdoc}
*/
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\Loader\Loader;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* 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;
public function __construct(ContainerBuilder $container)
{
$this->container = $container;
}
/**
* {@inheritdoc}
*/
public function load($resource, $type = null)
{
\call_user_func($resource, $this->container);
}
/**
* {@inheritdoc}
*/
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\Alias;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\Yaml\Exception\ParseException;
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;
/**
* {@inheritdoc}
*/
public function load($resource, $type = null)
{
$path = $this->locator->locate($resource);
$content = $this->loadFile($path);
$this->container->addResource(new FileResource($path));
// empty file
if (null === $content) {
return;
}
// imports
$this->parseImports($content, $path);
// parameters
if (isset($content['parameters'])) {
if (!\is_array($content['parameters'])) {
throw new InvalidArgumentException(sprintf('The "parameters" key should contain an array in %s. Check your YAML syntax.', $resource));
}
foreach ($content['parameters'] as $key => $value) {
$this->container->setParameter($key, $this->resolveServices($value));
}
}
// extensions
$this->loadFromExtensions($content);
// services
$this->parseDefinitions($content, $resource);
}
/**
* {@inheritdoc}
*/
public function supports($resource, $type = null)
{
return \is_string($resource) && \in_array(pathinfo($resource, PATHINFO_EXTENSION), array('yml', 'yaml'), true);
}
/**
* Parses all imports.
*
* @param array $content
* @param string $file
*/
private function parseImports(array $content, $file)
{
if (!isset($content['imports'])) {
return;
}
if (!\is_array($content['imports'])) {
throw new InvalidArgumentException(sprintf('The "imports" key should contain an array in %s. Check your YAML syntax.', $file));
}
$defaultDirectory = \dirname($file);
foreach ($content['imports'] as $import) {
if (!\is_array($import)) {
throw new InvalidArgumentException(sprintf('The values in the "imports" key should be arrays in %s. Check your YAML syntax.', $file));
}
$this->setCurrentDir($defaultDirectory);
$this->import($import['resource'], null, isset($import['ignore_errors']) ? (bool) $import['ignore_errors'] : false, $file);
}
}
/**
* Parses definitions.
*
* @param array $content
* @param string $file
*/
private function parseDefinitions(array $content, $file)
{
if (!isset($content['services'])) {
return;
}
if (!\is_array($content['services'])) {
throw new InvalidArgumentException(sprintf('The "services" key should contain an array in %s. Check your YAML syntax.', $file));
}
foreach ($content['services'] as $id => $service) {
$this->parseDefinition($id, $service, $file);
}
}
/**
* Parses a definition.
*
* @param string $id
* @param array|string $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;
}
if (!\is_array($service)) {
throw new InvalidArgumentException(sprintf('A service definition must be an array or a string starting with "@" but %s found for service "%s" in %s. Check your YAML syntax.', \gettype($service), $id, $file));
}
if (isset($service['alias'])) {
$public = !array_key_exists('public', $service) || (bool) $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['shared'])) {
$definition->setShared($service['shared']);
}
if (isset($service['scope'])) {
if ('request' !== $id) {
@trigger_error(sprintf('The "scope" key of service "%s" in file "%s" is deprecated since Symfony 2.8 and will be removed in 3.0.', $id, $file), E_USER_DEPRECATED);
}
$definition->setScope($service['scope'], false);
}
if (isset($service['synthetic'])) {
$definition->setSynthetic($service['synthetic']);
}
if (isset($service['synchronized'])) {
@trigger_error(sprintf('The "synchronized" key of service "%s" in file "%s" is deprecated since Symfony 2.7 and will be removed in 3.0.', $id, $file), E_USER_DEPRECATED);
$definition->setSynchronized($service['synchronized'], 'request' !== $id);
}
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 (array_key_exists('deprecated', $service)) {
$definition->setDeprecated(true, $service['deprecated']);
}
if (isset($service['factory'])) {
if (\is_string($service['factory'])) {
if (false !== strpos($service['factory'], ':') && false === strpos($service['factory'], '::')) {
$parts = explode(':', $service['factory']);
$definition->setFactory(array($this->resolveServices('@'.$parts[0]), $parts[1]));
} else {
$definition->setFactory($service['factory']);
}
} else {
$definition->setFactory(array($this->resolveServices($service['factory'][0]), $service['factory'][1]));
}
}
if (isset($service['factory_class'])) {
@trigger_error(sprintf('The "factory_class" key of service "%s" in file "%s" is deprecated since Symfony 2.6 and will be removed in 3.0. Use "factory" instead.', $id, $file), E_USER_DEPRECATED);
$definition->setFactoryClass($service['factory_class']);
}
if (isset($service['factory_method'])) {
@trigger_error(sprintf('The "factory_method" key of service "%s" in file "%s" is deprecated since Symfony 2.6 and will be removed in 3.0. Use "factory" instead.', $id, $file), E_USER_DEPRECATED);
$definition->setFactoryMethod($service['factory_method']);
}
if (isset($service['factory_service'])) {
@trigger_error(sprintf('The "factory_service" key of service "%s" in file "%s" is deprecated since Symfony 2.6 and will be removed in 3.0. Use "factory" instead.', $id, $file), E_USER_DEPRECATED);
$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'])) {
if (!\is_array($service['calls'])) {
throw new InvalidArgumentException(sprintf('Parameter "calls" must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file));
}
foreach ($service['calls'] as $call) {
if (isset($call['method'])) {
$method = $call['method'];
$args = isset($call['arguments']) ? $this->resolveServices($call['arguments']) : array();
} else {
$method = $call[0];
$args = isset($call[1]) ? $this->resolveServices($call[1]) : array();
}
$definition->addMethodCall($method, $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. Check your YAML syntax.', $id, $file));
}
foreach ($service['tags'] as $tag) {
if (!\is_array($tag)) {
throw new InvalidArgumentException(sprintf('A "tags" entry must be an array for service "%s" in %s. Check your YAML syntax.', $id, $file));
}
if (!isset($tag['name'])) {
throw new InvalidArgumentException(sprintf('A "tags" entry is missing a "name" key for service "%s" in %s.', $id, $file));
}
if (!\is_string($tag['name']) || '' === $tag['name']) {
throw new InvalidArgumentException(sprintf('The tag name for service "%s" in %s must be a non-empty string.', $id, $file));
}
$name = $tag['name'];
unset($tag['name']);
foreach ($tag as $attribute => $value) {
if (!is_scalar($value) && null !== $value) {
throw new InvalidArgumentException(sprintf('A "tags" attribute must be of a scalar-type for service "%s", tag "%s", attribute "%s" in %s. Check your YAML syntax.', $id, $name, $attribute, $file));
}
}
$definition->addTag($name, $tag);
}
}
if (isset($service['decorates'])) {
if ('' !== $service['decorates'] && '@' === $service['decorates'][0]) {
throw new InvalidArgumentException(sprintf('The value of the "decorates" option for the "%s" service must be the id of the service without the "@" prefix (replace "%s" with "%s").', $id, $service['decorates'], substr($service['decorates'], 1)));
}
$renameId = isset($service['decoration_inner_name']) ? $service['decoration_inner_name'] : null;
$priority = isset($service['decoration_priority']) ? $service['decoration_priority'] : 0;
$definition->setDecoratedService($service['decorates'], $renameId, $priority);
}
if (isset($service['autowire'])) {
$definition->setAutowired($service['autowire']);
}
if (isset($service['autowiring_types'])) {
if (\is_string($service['autowiring_types'])) {
$definition->addAutowiringType($service['autowiring_types']);
} else {
if (!\is_array($service['autowiring_types'])) {
throw new InvalidArgumentException(sprintf('Parameter "autowiring_types" must be a string or an array for service "%s" in %s. Check your YAML syntax.', $id, $file));
}
foreach ($service['autowiring_types'] as $autowiringType) {
if (!\is_string($autowiringType)) {
throw new InvalidArgumentException(sprintf('A "autowiring_types" attribute must be of type string for service "%s" in %s. Check your YAML syntax.', $id, $file));
}
$definition->addAutowiringType($autowiringType);
}
}
}
$this->container->setDefinition($id, $definition);
}
/**
* Loads a YAML file.
*
* @param string $file
*
* @return array The file content
*
* @throws InvalidArgumentException when the given file is not a local file or when it does not exist
*/
protected function loadFile($file)
{
if (!class_exists('Symfony\Component\Yaml\Parser')) {
throw new RuntimeException('Unable to load YAML config files as the Symfony Yaml Component is not installed.');
}
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 file "%s" does not exist.', $file));
}
if (null === $this->yamlParser) {
$this->yamlParser = new YamlParser();
}
try {
$configuration = $this->yamlParser->parse(file_get_contents($file));
} catch (ParseException $e) {
throw new InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML.', $file), 0, $e);
}
return $this->validate($configuration, $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. It should contain an array. Check your YAML syntax.', $file));
}
foreach ($content as $namespace => $data) {
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|array $value
*
* @return array|string|Reference
*/
private function resolveServices($value)
{
if (\is_array($value)) {
$value = array_map(array($this, 'resolveServices'), $value);
} elseif (\is_string($value) && 0 === strpos($value, '@=')) {
return new Expression(substr($value, 2));
} 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.
*/
private function loadFromExtensions(array $content)
{
foreach ($content as $namespace => $values) {
if (\in_array($namespace, array('imports', 'parameters', 'services'))) {
continue;
}
if (!\is_array($values) && null !== $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\ParameterBag;
use Symfony\Component\DependencyInjection\Exception\LogicException;
/**
* Holds read-only parameters.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class FrozenParameterBag extends ParameterBag
{
/**
* 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
*/
public function __construct(array $parameters = array())
{
$this->parameters = $parameters;
$this->resolved = true;
}
/**
* {@inheritdoc}
*/
public function clear()
{
throw new LogicException('Impossible to call clear() on a frozen ParameterBag.');
}
/**
* {@inheritdoc}
*/
public function add(array $parameters)
{
throw new LogicException('Impossible to call add() on a frozen ParameterBag.');
}
/**
* {@inheritdoc}
*/
public function set($name, $value)
{
throw new LogicException('Impossible to call set() on a frozen ParameterBag.');
}
/**
* {@inheritdoc}
*/
public function remove($name)
{
throw new LogicException('Impossible to call remove() 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\ParameterCircularReferenceException;
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
/**
* Holds parameters.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ParameterBag implements ParameterBagInterface
{
protected $parameters = array();
protected $resolved = false;
/**
* @param array $parameters An array of parameters
*/
public function __construct(array $parameters = array())
{
$this->add($parameters);
}
/**
* Clears all parameters.
*/
public function clear()
{
$this->parameters = array();
}
/**
* Adds parameters to the service container parameters.
*
* @param array $parameters An array of parameters
*/
public function add(array $parameters)
{
foreach ($parameters as $key => $value) {
$this->parameters[strtolower($key)] = $value;
}
}
/**
* {@inheritdoc}
*/
public function all()
{
return $this->parameters;
}
/**
* {@inheritdoc}
*/
public function get($name)
{
$name = strtolower($name);
if (!array_key_exists($name, $this->parameters)) {
if (!$name) {
throw new ParameterNotFoundException($name);
}
$alternatives = array();
foreach ($this->parameters as $key => $parameterValue) {
$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
*/
public function set($name, $value)
{
$this->parameters[strtolower($name)] = $value;
}
/**
* {@inheritdoc}
*/
public function has($name)
{
return array_key_exists(strtolower($name), $this->parameters);
}
/**
* Removes a parameter.
*
* @param string $name The parameter name
*/
public function remove($name)
{
unset($this->parameters[strtolower($name)]);
}
/**
* {@inheritdoc}
*/
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;
}
/**
* {@inheritdoc}
*/
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\LogicException;
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
/**
* ParameterBagInterface.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface ParameterBagInterface
{
/**
* Clears all parameters.
*
* @throws LogicException if the ParameterBagInterface can not be cleared
*/
public function clear();
/**
* Adds parameters to the service container parameters.
*
* @param array $parameters An array of parameters
*
* @throws LogicException if the parameter can not be added
*/
public function add(array $parameters);
/**
* Gets the service container parameters.
*
* @return array An array of parameters
*/
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
*/
public function get($name);
/**
* Sets a service container parameter.
*
* @param string $name The parameter name
* @param mixed $value The parameter value
*
* @throws LogicException if the parameter can not be set
*/
public function set($name, $value);
/**
* Returns true if a parameter name is defined.
*
* @param string $name The parameter name
*
* @return bool true if the parameter name is defined, false otherwise
*/
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);
}
<?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>
*/
class Definition
{
private $class;
private $file;
private $factory;
private $factoryClass;
private $factoryMethod;
private $factoryService;
private $shared = true;
private $deprecated = false;
private $deprecationTemplate;
private $scope = ContainerInterface::SCOPE_CONTAINER;
private $properties = array();
private $calls = array();
private $configurator;
private $tags = array();
private $public = true;
private $synthetic = false;
private $abstract = false;
private $synchronized = false;
private $lazy = false;
private $decoratedService;
private $autowired = false;
private $autowiringTypes = array();
private static $defaultDeprecationTemplate = 'The "%service_id%" service is deprecated. You should stop using it, as it will soon be removed.';
protected $arguments;
/**
* @param string|null $class The service class
* @param array $arguments An array of arguments to pass to the service constructor
*/
public function __construct($class = null, array $arguments = array())
{
$this->class = $class;
$this->arguments = $arguments;
}
/**
* Sets a factory.
*
* @param string|array $factory A PHP function or an array containing a class/Reference and a method to call
*
* @return $this
*/
public function setFactory($factory)
{
if (\is_string($factory) && false !== strpos($factory, '::')) {
$factory = explode('::', $factory, 2);
}
$this->factory = $factory;
return $this;
}
/**
* Gets the factory.
*
* @return string|array|null The PHP function or an array containing a class/Reference and a method to call
*/
public function getFactory()
{
return $this->factory;
}
/**
* 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 $this
*
* @deprecated since version 2.6, to be removed in 3.0.
*/
public function setFactoryClass($factoryClass)
{
@trigger_error(sprintf('%s(%s) is deprecated since Symfony 2.6 and will be removed in 3.0. Use Definition::setFactory() instead.', __METHOD__, $factoryClass), E_USER_DEPRECATED);
$this->factoryClass = $factoryClass;
return $this;
}
/**
* Gets the factory class.
*
* @return string|null The factory class name
*
* @deprecated since version 2.6, to be removed in 3.0.
*/
public function getFactoryClass($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.6 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return $this->factoryClass;
}
/**
* Sets the factory method able to create an instance of this class.
*
* @param string $factoryMethod The factory method name
*
* @return $this
*
* @deprecated since version 2.6, to be removed in 3.0.
*/
public function setFactoryMethod($factoryMethod)
{
@trigger_error(sprintf('%s(%s) is deprecated since Symfony 2.6 and will be removed in 3.0. Use Definition::setFactory() instead.', __METHOD__, $factoryMethod), E_USER_DEPRECATED);
$this->factoryMethod = $factoryMethod;
return $this;
}
/**
* Sets the service that this service is decorating.
*
* @param string|null $id The decorated service id, use null to remove decoration
* @param string|null $renamedId The new decorated service id
* @param int $priority The priority of decoration
*
* @return $this
*
* @throws InvalidArgumentException in case the decorated service id and the new decorated service id are equals
*/
public function setDecoratedService($id, $renamedId = null, $priority = 0)
{
if ($renamedId && $id === $renamedId) {
throw new \InvalidArgumentException(sprintf('The decorated service inner name for "%s" must be different than the service name itself.', $id));
}
if (null === $id) {
$this->decoratedService = null;
} else {
$this->decoratedService = array($id, $renamedId, (int) $priority);
}
return $this;
}
/**
* Gets the service that this service is decorating.
*
* @return array|null An array composed of the decorated service id, the new id for it and the priority of decoration, null if no service is decorated
*/
public function getDecoratedService()
{
return $this->decoratedService;
}
/**
* Gets the factory method.
*
* @return string|null The factory method name
*
* @deprecated since version 2.6, to be removed in 3.0.
*/
public function getFactoryMethod($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.6 and will be removed in 3.0.', E_USER_DEPRECATED);
}
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 $this
*
* @deprecated since version 2.6, to be removed in 3.0.
*/
public function setFactoryService($factoryService, $triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error(sprintf('%s(%s) is deprecated since Symfony 2.6 and will be removed in 3.0. Use Definition::setFactory() instead.', __METHOD__, $factoryService), E_USER_DEPRECATED);
}
$this->factoryService = $factoryService;
return $this;
}
/**
* Gets the factory service id.
*
* @return string|null The factory service id
*
* @deprecated since version 2.6, to be removed in 3.0.
*/
public function getFactoryService($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.6 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return $this->factoryService;
}
/**
* Sets the service class.
*
* @param string $class The service class
*
* @return $this
*/
public function setClass($class)
{
$this->class = $class;
return $this;
}
/**
* Gets the service class.
*
* @return string|null The service class
*/
public function getClass()
{
return $this->class;
}
/**
* Sets the arguments to pass to the service constructor/factory method.
*
* @return $this
*/
public function setArguments(array $arguments)
{
$this->arguments = $arguments;
return $this;
}
/**
* Sets the properties to define when creating the service.
*
* @return $this
*/
public function setProperties(array $properties)
{
$this->properties = $properties;
return $this;
}
/**
* Gets the properties to define when creating the service.
*
* @return array
*/
public function getProperties()
{
return $this->properties;
}
/**
* Sets a specific property.
*
* @param string $name
* @param mixed $value
*
* @return $this
*/
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 $this
*/
public function addArgument($argument)
{
$this->arguments[] = $argument;
return $this;
}
/**
* Replaces a specific argument.
*
* @param int $index
* @param mixed $argument
*
* @return $this
*
* @throws OutOfBoundsException When the replaced argument does not exist
*/
public function replaceArgument($index, $argument)
{
if (0 === \count($this->arguments)) {
throw new OutOfBoundsException('Cannot replace arguments if none have been configured yet.');
}
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
*/
public function getArguments()
{
return $this->arguments;
}
/**
* Gets an argument to pass to the service constructor/factory method.
*
* @param int $index
*
* @return mixed The argument value
*
* @throws OutOfBoundsException When the argument does not exist
*/
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.
*
* @return $this
*/
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 $this
*
* @throws InvalidArgumentException on empty $method param
*/
public function addMethodCall($method, array $arguments = array())
{
if (empty($method)) {
throw new InvalidArgumentException('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 $this
*/
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 bool
*/
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
*/
public function getMethodCalls()
{
return $this->calls;
}
/**
* Sets tags for this definition.
*
* @return $this
*/
public function setTags(array $tags)
{
$this->tags = $tags;
return $this;
}
/**
* Returns all tags.
*
* @return array An array of tags
*/
public function getTags()
{
return $this->tags;
}
/**
* Gets a tag by name.
*
* @param string $name The tag name
*
* @return array An array of attributes
*/
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 $this
*/
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 bool
*/
public function hasTag($name)
{
return isset($this->tags[$name]);
}
/**
* Clears all tags for a given name.
*
* @param string $name The tag name
*
* @return $this
*/
public function clearTag($name)
{
unset($this->tags[$name]);
return $this;
}
/**
* Clears the tags for this definition.
*
* @return $this
*/
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 $this
*/
public function setFile($file)
{
$this->file = $file;
return $this;
}
/**
* Gets the file to require before creating the service.
*
* @return string|null The full pathname to include
*/
public function getFile()
{
return $this->file;
}
/**
* Sets if the service must be shared or not.
*
* @param bool $shared Whether the service must be shared or not
*
* @return $this
*/
public function setShared($shared)
{
$this->shared = (bool) $shared;
return $this;
}
/**
* Whether this service is shared.
*
* @return bool
*/
public function isShared()
{
return $this->shared;
}
/**
* Sets the scope of the service.
*
* @param string $scope Whether the service must be shared or not
*
* @return $this
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function setScope($scope, $triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
if (ContainerInterface::SCOPE_PROTOTYPE === $scope) {
$this->setShared(false);
}
$this->scope = $scope;
return $this;
}
/**
* Returns the scope of the service.
*
* @return string
*
* @deprecated since version 2.8, to be removed in 3.0.
*/
public function getScope($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.8 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return $this->scope;
}
/**
* Sets the visibility of this service.
*
* @param bool $boolean
*
* @return $this
*/
public function setPublic($boolean)
{
$this->public = (bool) $boolean;
return $this;
}
/**
* Whether this service is public facing.
*
* @return bool
*/
public function isPublic()
{
return $this->public;
}
/**
* Sets the synchronized flag of this service.
*
* @param bool $boolean
*
* @return $this
*
* @deprecated since version 2.7, will be removed in 3.0.
*/
public function setSynchronized($boolean, $triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.7 and will be removed in 3.0.', E_USER_DEPRECATED);
}
$this->synchronized = (bool) $boolean;
return $this;
}
/**
* Whether this service is synchronized.
*
* @return bool
*
* @deprecated since version 2.7, will be removed in 3.0.
*/
public function isSynchronized($triggerDeprecationError = true)
{
if ($triggerDeprecationError) {
@trigger_error('The '.__METHOD__.' method is deprecated since Symfony 2.7 and will be removed in 3.0.', E_USER_DEPRECATED);
}
return $this->synchronized;
}
/**
* Sets the lazy flag of this service.
*
* @param bool $lazy
*
* @return $this
*/
public function setLazy($lazy)
{
$this->lazy = (bool) $lazy;
return $this;
}
/**
* Whether this service is lazy.
*
* @return bool
*/
public function isLazy()
{
return $this->lazy;
}
/**
* Sets whether this definition is synthetic, that is not constructed by the
* container, but dynamically injected.
*
* @param bool $boolean
*
* @return $this
*/
public function setSynthetic($boolean)
{
$this->synthetic = (bool) $boolean;
return $this;
}
/**
* Whether this definition is synthetic, that is not constructed by the
* container, but dynamically injected.
*
* @return bool
*/
public function isSynthetic()
{
return $this->synthetic;
}
/**
* Whether this definition is abstract, that means it merely serves as a
* template for other definitions.
*
* @param bool $boolean
*
* @return $this
*/
public function setAbstract($boolean)
{
$this->abstract = (bool) $boolean;
return $this;
}
/**
* Whether this definition is abstract, that means it merely serves as a
* template for other definitions.
*
* @return bool
*/
public function isAbstract()
{
return $this->abstract;
}
/**
* Whether this definition is deprecated, that means it should not be called
* anymore.
*
* @param bool $status
* @param string $template Template message to use if the definition is deprecated
*
* @return $this
*
* @throws InvalidArgumentException when the message template is invalid
*/
public function setDeprecated($status = true, $template = null)
{
if (null !== $template) {
if (preg_match('#[\r\n]|\*/#', $template)) {
throw new InvalidArgumentException('Invalid characters found in deprecation template.');
}
if (false === strpos($template, '%service_id%')) {
throw new InvalidArgumentException('The deprecation template must contain the "%service_id%" placeholder.');
}
$this->deprecationTemplate = $template;
}
$this->deprecated = (bool) $status;
return $this;
}
/**
* Whether this definition is deprecated, that means it should not be called
* anymore.
*
* @return bool
*/
public function isDeprecated()
{
return $this->deprecated;
}
/**
* Message to use if this definition is deprecated.
*
* @param string $id Service id relying on this definition
*
* @return string
*/
public function getDeprecationMessage($id)
{
return str_replace('%service_id%', $id, $this->deprecationTemplate ?: self::$defaultDeprecationTemplate);
}
/**
* Sets a configurator to call after the service is fully initialized.
*
* @param callable $callable A PHP callable
*
* @return $this
*/
public function setConfigurator($callable)
{
$this->configurator = $callable;
return $this;
}
/**
* Gets the configurator to call after the service is fully initialized.
*
* @return callable|null The PHP callable to call
*/
public function getConfigurator()
{
return $this->configurator;
}
/**
* Sets types that will default to this definition.
*
* @param string[] $types
*
* @return $this
*/
public function setAutowiringTypes(array $types)
{
$this->autowiringTypes = array();
foreach ($types as $type) {
$this->autowiringTypes[$type] = true;
}
return $this;
}
/**
* Is the definition autowired?
*
* @return bool
*/
public function isAutowired()
{
return $this->autowired;
}
/**
* Enables/disables autowiring.
*
* @param bool $autowired
*
* @return $this
*/
public function setAutowired($autowired)
{
$this->autowired = $autowired;
return $this;
}
/**
* Gets autowiring types that will default to this definition.
*
* @return string[]
*/
public function getAutowiringTypes()
{
return array_keys($this->autowiringTypes);
}
/**
* Adds a type that will default to this definition.
*
* @param string $type
*
* @return $this
*/
public function addAutowiringType($type)
{
$this->autowiringTypes[$type] = true;
return $this;
}
/**
* Removes a type.
*
* @param string $type
*
* @return $this
*/
public function removeAutowiringType($type)
{
unset($this->autowiringTypes[$type]);
return $this;
}
/**
* Will this definition default for the given type?
*
* @param string $type
*
* @return bool
*/
public function hasAutowiringType($type)
{
return isset($this->autowiringTypes[$type]);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/5.2/phpunit.xsd"
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"
failOnRisky="true"
failOnWarning="true"
>
<php>
<ini name="error_reporting" value="-1" />
</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\Extension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
interface PrependExtensionInterface
{
/**
* Allow an extension to prepend the extension configurations.
*/
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>
*/
interface ExtensionInterface
{
/**
* Loads a specific configuration.
*
* @throws \InvalidArgumentException When provided tag is not defined in this extension
*/
public function load(array $configs, ContainerBuilder $container);
/**
* Returns the namespace to be used for this extension (XML namespace).
*
* @return string The XML namespace
*/
public function getNamespace();
/**
* Returns the base path for the XSD files.
*
* @return string The XSD base path
*/
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
*/
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\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\Definition\Processor;
use Symfony\Component\Config\Resource\FileResource;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\BadMethodCallException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
/**
* Provides useful features shared by many extensions.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
abstract class Extension implements ExtensionInterface, ConfigurationExtensionInterface
{
/**
* {@inheritdoc}
*/
public function getXsdValidationBasePath()
{
return false;
}
/**
* {@inheritdoc}
*/
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 ('Extension' != substr($className, -9)) {
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')) {
return new $class();
}
}
}
final protected function processConfiguration(ConfigurationInterface $configuration, array $configs)
{
$processor = new Processor();
return $processor->processConfiguration($configuration, $configs);
}
/**
* @return bool 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 (bool) $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\Extension;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* ConfigurationExtensionInterface is the interface implemented by container extension classes.
*
* @author Kevin Bond <kevinbond@gmail.com>
*/
interface ConfigurationExtensionInterface
{
/**
* Returns extension configuration.
*
* @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;
/**
* ContainerAware trait.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
trait ContainerAwareTrait
{
/**
* @var ContainerInterface
*/
protected $container;
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;
/**
* Parameter represents a parameter reference.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Parameter
{
private $id;
/**
* @param string $id The parameter key
*/
public function __construct($id)
{
$this->id = $id;
}
/**
* @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;
use Symfony\Component\ExpressionLanguage\ExpressionFunction;
use Symfony\Component\ExpressionLanguage\ExpressionFunctionProviderInterface;
/**
* Define some ExpressionLanguage functions.
*
* To get a service, use service('request').
* To get a parameter, use parameter('kernel.debug').
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class ExpressionLanguageProvider implements ExpressionFunctionProviderInterface
{
public function getFunctions()
{
return array(
new ExpressionFunction('service', function ($arg) {
return sprintf('$this->get(%s)', $arg);
}, function (array $variables, $value) {
return $variables['container']->get($value);
}),
new ExpressionFunction('parameter', function ($arg) {
return sprintf('$this->getParameter(%s)', $arg);
}, function (array $variables, $value) {
return $variables['container']->getParameter($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;
/**
* Interface that must be implemented by compilation passes.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
interface CompilerPassInterface
{
/**
* You can modify the container here before it is dumped to PHP code.
*/
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\Alias;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Overwrites a service but keeps the overridden one.
*
* @author Christophe Coevoet <stof@notk.org>
* @author Fabien Potencier <fabien@symfony.com>
* @author Diego Saint Esteben <diego@saintesteben.me>
*/
class DecoratorServicePass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$definitions = new \SplPriorityQueue();
$order = PHP_INT_MAX;
foreach ($container->getDefinitions() as $id => $definition) {
if (!$decorated = $definition->getDecoratedService()) {
continue;
}
$definitions->insert(array($id, $definition), array($decorated[2], --$order));
}
foreach ($definitions as $arr) {
list($id, $definition) = $arr;
list($inner, $renamedId) = $definition->getDecoratedService();
$definition->setDecoratedService(null);
if (!$renamedId) {
$renamedId = $id.'.inner';
}
// we create a new alias/service for the service we are replacing
// to be able to reference it in the new one
if ($container->hasAlias($inner)) {
$alias = $container->getAlias($inner);
$public = $alias->isPublic();
$container->setAlias($renamedId, new Alias((string) $alias, false));
} else {
$decoratedDefinition = $container->getDefinition($inner);
$definition->setTags(array_merge($decoratedDefinition->getTags(), $definition->getTags()));
$definition->setAutowiringTypes(array_merge($decoratedDefinition->getAutowiringTypes(), $definition->getAutowiringTypes()));
$public = $decoratedDefinition->isPublic();
$decoratedDefinition->setPublic(false);
$decoratedDefinition->setTags(array());
$decoratedDefinition->setAutowiringTypes(array());
$container->setDefinition($renamedId, $decoratedDefinition);
}
$container->setAlias($inner, new Alias($id, $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\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
/**
* 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.
*/
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 $e) {
// 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 $e) {
// ignore property
}
}
$definition->setProperties($properties);
}
}
/**
* Processes arguments to determine invalid references.
*
* @param array $arguments An array of Reference objects
* @param bool $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\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.
*
* @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()));
if ($definition->getFactoryClass(false)) {
$definition->setFactoryClass($parameterBag->resolveValue($definition->getFactoryClass(false)));
}
$factory = $definition->getFactory();
if (\is_array($factory) && isset($factory[0])) {
$factory[0] = $parameterBag->resolveValue($factory[0]);
$definition->setFactory($factory);
}
$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)] = $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\Alias;
use Symfony\Component\DependencyInjection\Definition;
/**
* 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 = array();
private $outEdges = array();
private $value;
/**
* @param string $id The node identifier
* @param mixed $value The node value
*/
public function __construct($id, $value)
{
$this->id = $id;
$this->value = $value;
}
public function addInEdge(ServiceReferenceGraphEdge $edge)
{
$this->inEdges[] = $edge;
}
public function addOutEdge(ServiceReferenceGraphEdge $edge)
{
$this->outEdges[] = $edge;
}
/**
* Checks if the value of this node is an Alias.
*
* @return bool 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 bool 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\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
/**
* Inline service definitions where this is possible.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class InlineServiceDefinitionsPass implements RepeatablePassInterface
{
private $graph;
private $compiler;
private $formatter;
private $currentId;
/**
* {@inheritdoc}
*/
public function setRepeatedPass(RepeatedPass $repeatedPass)
{
// no-op for BC
}
/**
* Processes the ContainerBuilder for inline service definitions.
*/
public function process(ContainerBuilder $container)
{
$this->compiler = $container->getCompiler();
$this->formatter = $this->compiler->getLoggingFormatter();
$this->graph = $this->compiler->getServiceReferenceGraph();
$container->setDefinitions($this->inlineArguments($container, $container->getDefinitions(), true));
}
/**
* Processes inline arguments.
*
* @param ContainerBuilder $container The ContainerBuilder
* @param array $arguments An array of arguments
* @param bool $isRoot If we are processing the root definitions or not
*
* @return array
*/
private function inlineArguments(ContainerBuilder $container, array $arguments, $isRoot = false)
{
foreach ($arguments as $k => $argument) {
if ($isRoot) {
$this->currentId = $k;
}
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 ($definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE !== $definition->getScope(false)) {
$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()));
$configurator = $this->inlineArguments($container, array($argument->getConfigurator()));
$argument->setConfigurator($configurator[0]);
$factory = $this->inlineArguments($container, array($argument->getFactory()));
$argument->setFactory($factory[0]);
}
}
return $arguments;
}
/**
* Checks if the definition is inlineable.
*
* @param ContainerBuilder $container
* @param string $id
* @param Definition $definition
*
* @return bool If the definition is inlineable
*/
private function isInlineableDefinition(ContainerBuilder $container, $id, Definition $definition)
{
if ($definition->isDeprecated() || $definition->isLazy() || $definition->isSynthetic()) {
return false;
}
if (!$definition->isShared() || ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope(false)) {
return true;
}
if ($definition->isPublic()) {
return false;
}
if (!$this->graph->hasNode($id)) {
return true;
}
if ($this->currentId == $id) {
return false;
}
$ids = array();
foreach ($this->graph->getNode($id)->getInEdges() as $edge) {
$ids[] = $edge->getSourceNode()->getId();
}
if (\count(array_unique($ids)) > 1) {
return false;
}
if (\count($ids) > 1 && \is_array($factory = $definition->getFactory()) && ($factory[0] instanceof Reference || $factory[0] instanceof Definition)) {
return false;
}
if (\count($ids) > 1 && $definition->getFactoryService(false)) {
return false;
}
return $container->getDefinition(reset($ids))->getScope(false) === $definition->getScope(false);
}
}
<?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>
*/
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 = array();
private $beforeOptimizationPasses = array();
private $beforeRemovingPasses = array();
private $optimizationPasses;
private $removingPasses;
public function __construct()
{
$this->mergePass = new MergeExtensionConfigurationPass();
$this->optimizationPasses = array(
new ExtensionCompilerPass(),
new ResolveDefinitionTemplatesPass(),
new DecoratorServicePass(),
new ResolveParameterPlaceHoldersPass(),
new CheckDefinitionValidityPass(),
new ResolveReferencesToAliasesPass(),
new ResolveInvalidReferencesPass(),
new AutowirePass(),
new AnalyzeServiceReferencesPass(true),
new CheckCircularReferencesPass(),
new CheckReferenceValidityPass(),
);
$this->removingPasses = array(
new RemovePrivateAliasesPass(),
new ReplaceAliasByActualDefinitionPass(),
new RemoveAbstractDefinitionsPass(),
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
*/
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
*/
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));
}
$this->{$property}[] = $pass;
}
/**
* Gets all passes for the AfterRemoving pass.
*
* @return array An array of passes
*/
public function getAfterRemovingPasses()
{
return $this->afterRemovingPasses;
}
/**
* Gets all passes for the BeforeOptimization pass.
*
* @return array An array of passes
*/
public function getBeforeOptimizationPasses()
{
return $this->beforeOptimizationPasses;
}
/**
* Gets all passes for the BeforeRemoving pass.
*
* @return array An array of passes
*/
public function getBeforeRemovingPasses()
{
return $this->beforeRemovingPasses;
}
/**
* Gets all passes for the Optimization pass.
*
* @return array An array of passes
*/
public function getOptimizationPasses()
{
return $this->optimizationPasses;
}
/**
* Gets all passes for the Removing pass.
*
* @return array An array of passes
*/
public function getRemovingPasses()
{
return $this->removingPasses;
}
/**
* Gets the Merge pass.
*
* @return CompilerPassInterface The merge pass
*/
public function getMergePass()
{
return $this->mergePass;
}
public function setMergePass(CompilerPassInterface $pass)
{
$this->mergePass = $pass;
}
/**
* Sets the AfterRemoving passes.
*
* @param array $passes An array of passes
*/
public function setAfterRemovingPasses(array $passes)
{
$this->afterRemovingPasses = $passes;
}
/**
* Sets the BeforeOptimization passes.
*
* @param array $passes An array of passes
*/
public function setBeforeOptimizationPasses(array $passes)
{
$this->beforeOptimizationPasses = $passes;
}
/**
* Sets the BeforeRemoving passes.
*
* @param array $passes An array of passes
*/
public function setBeforeRemovingPasses(array $passes)
{
$this->beforeRemovingPasses = $passes;
}
/**
* Sets the Optimization passes.
*
* @param array $passes An array of passes
*/
public function setOptimizationPasses(array $passes)
{
$this->optimizationPasses = $passes;
}
/**
* Sets the Removing passes.
*
* @param array $passes An array of passes
*/
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;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* A pass to automatically process extensions if they implement
* CompilerPassInterface.
*
* @author Wouter J <wouter@wouterj.nl>
*/
class ExtensionCompilerPass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
foreach ($container->getExtensions() as $extension) {
if (!$extension instanceof CompilerPassInterface) {
continue;
}
$extension->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\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.
*/
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;
use Symfony\Component\DependencyInjection\Extension\ConfigurationExtensionInterface;
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();
$exprLangProviders = $container->getExpressionLanguageProviders();
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);
if ($extension instanceof ConfigurationExtensionInterface && null !== $configuration = $extension->getConfiguration($config, $tmpContainer)) {
$tmpContainer->addObjectResource($configuration);
}
foreach ($exprLangProviders as $provider) {
$tmpContainer->addExpressionLanguageProvider($provider);
}
$extension->load($config, $tmpContainer);
$container->merge($tmpContainer);
$container->getParameterBag()->add($parameters);
}
$container->addDefinitions($definitions);
$container->addAliases($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\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Removes abstract Definitions.
*/
class RemoveAbstractDefinitionsPass implements CompilerPassInterface
{
/**
* Removes abstract definitions from the ContainerBuilder.
*/
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;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Exception\ScopeCrossingInjectionException;
use Symfony\Component\DependencyInjection\Exception\ScopeWideningInjectionException;
use Symfony\Component\DependencyInjection\Reference;
/**
* 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 $currentScope;
private $currentScopeAncestors;
private $currentScopeChildren;
/**
* Processes the ContainerBuilder to validate References.
*/
public function process(ContainerBuilder $container)
{
$this->container = $container;
$children = $this->container->getScopeChildren(false);
$ancestors = array();
$scopes = $this->container->getScopes(false);
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->currentScope = $scope = $definition->getScope(false);
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.
*
* @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(false)) {
return;
}
if (null === $definition) {
return;
}
if ($this->currentScope === $scope = $definition->getScope(false)) {
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;
}
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;
/**
* 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.
*/
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\Alias;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
use Symfony\Component\DependencyInjection\Reference;
/**
* 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.
*/
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()));
$definition->setFactory($this->processFactory($definition->getFactory()));
$definition->setFactoryService($this->processFactoryService($definition->getFactoryService(false)), false);
}
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(false));
}
}
}
return $arguments;
}
private function processFactoryService($factoryService)
{
if (null === $factoryService) {
return;
}
return $this->getDefinitionId($factoryService);
}
private function processFactory($factory)
{
if (null === $factory || !\is_array($factory) || !$factory[0] instanceof Reference) {
return $factory;
}
$defId = $this->getDefinitionId($id = (string) $factory[0]);
if ($defId !== $id) {
$factory[0] = new Reference($defId, $factory[0]->getInvalidBehavior(), $factory[0]->isStrict(false));
}
return $factory;
}
/**
* 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)
{
$seen = array();
while ($this->container->hasAlias($id)) {
if (isset($seen[$id])) {
throw new ServiceCircularReferenceException($id, array_keys($seen));
}
$seen[$id] = true;
$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\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
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>
* @author Nicolas Grekas <p@tchwork.com>
*/
class ResolveDefinitionTemplatesPass implements CompilerPassInterface
{
private $compiler;
private $formatter;
private $currentId;
/**
* Process the ContainerBuilder to replace DefinitionDecorator instances with their real Definition instances.
*/
public function process(ContainerBuilder $container)
{
$this->compiler = $container->getCompiler();
$this->formatter = $this->compiler->getLoggingFormatter();
$container->setDefinitions($this->resolveArguments($container, $container->getDefinitions(), true));
}
/**
* Resolves definition decorator arguments.
*
* @param ContainerBuilder $container The ContainerBuilder
* @param array $arguments An array of arguments
* @param bool $isRoot If we are processing the root definitions or not
*
* @return array
*/
private function resolveArguments(ContainerBuilder $container, array $arguments, $isRoot = false)
{
foreach ($arguments as $k => $argument) {
if ($isRoot) {
// yes, we are specifically fetching the definition from the
// container to ensure we are not operating on stale data
$arguments[$k] = $argument = $container->getDefinition($k);
$this->currentId = $k;
}
if (\is_array($argument)) {
$arguments[$k] = $this->resolveArguments($container, $argument);
} elseif ($argument instanceof Definition) {
if ($argument instanceof DefinitionDecorator) {
$arguments[$k] = $argument = $this->resolveDefinition($container, $argument);
if ($isRoot) {
$container->setDefinition($k, $argument);
}
}
$argument->setArguments($this->resolveArguments($container, $argument->getArguments()));
$argument->setMethodCalls($this->resolveArguments($container, $argument->getMethodCalls()));
$argument->setProperties($this->resolveArguments($container, $argument->getProperties()));
$configurator = $this->resolveArguments($container, array($argument->getConfigurator()));
$argument->setConfigurator($configurator[0]);
$factory = $this->resolveArguments($container, array($argument->getFactory()));
$argument->setFactory($factory[0]);
}
}
return $arguments;
}
/**
* Resolves the definition.
*
* @param ContainerBuilder $container The ContainerBuilder
* @param DefinitionDecorator $definition
*
* @return Definition
*
* @throws \RuntimeException When the definition is invalid
*/
private function resolveDefinition(ContainerBuilder $container, DefinitionDecorator $definition)
{
if (!$container->hasDefinition($parent = $definition->getParent())) {
throw new RuntimeException(sprintf('The parent definition "%s" defined for definition "%s" does not exist.', $parent, $this->currentId));
}
$parentDef = $container->getDefinition($parent);
if ($parentDef instanceof DefinitionDecorator) {
$id = $this->currentId;
$this->currentId = $parent;
$parentDef = $this->resolveDefinition($container, $parentDef);
$container->setDefinition($parent, $parentDef);
$this->currentId = $id;
}
$this->compiler->addLogMessage($this->formatter->formatResolveInheritance($this, $this->currentId, $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->setAutowiringTypes($parentDef->getAutowiringTypes());
if ($parentDef->getFactoryClass(false)) {
$def->setFactoryClass($parentDef->getFactoryClass(false));
}
if ($parentDef->getFactoryMethod(false)) {
$def->setFactoryMethod($parentDef->getFactoryMethod(false));
}
if ($parentDef->getFactoryService(false)) {
$def->setFactoryService($parentDef->getFactoryService(false));
}
if ($parentDef->isDeprecated()) {
$def->setDeprecated(true, $parentDef->getDeprecationMessage('%service_id%'));
}
$def->setFactory($parentDef->getFactory());
$def->setConfigurator($parentDef->getConfigurator());
$def->setFile($parentDef->getFile());
$def->setPublic($parentDef->isPublic());
$def->setLazy($parentDef->isLazy());
$def->setAutowired($parentDef->isAutowired());
// 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(false));
}
if (isset($changes['factory_method'])) {
$def->setFactoryMethod($definition->getFactoryMethod(false));
}
if (isset($changes['factory_service'])) {
$def->setFactoryService($definition->getFactoryService(false));
}
if (isset($changes['factory'])) {
$def->setFactory($definition->getFactory());
}
if (isset($changes['configurator'])) {
$def->setConfigurator($definition->getConfigurator());
}
if (isset($changes['file'])) {
$def->setFile($definition->getFile());
}
if (isset($changes['public'])) {
$def->setPublic($definition->isPublic());
}
if (isset($changes['lazy'])) {
$def->setLazy($definition->isLazy());
}
if (isset($changes['deprecated'])) {
$def->setDeprecated($definition->isDeprecated(), $definition->getDeprecationMessage('%service_id%'));
}
if (isset($changes['autowire'])) {
$def->setAutowired($definition->isAutowired());
}
if (isset($changes['decorated_service'])) {
$decoratedService = $definition->getDecoratedService();
if (null === $decoratedService) {
$def->setDecoratedService($decoratedService);
} else {
$def->setDecoratedService($decoratedService[0], $decoratedService[1], $decoratedService[2]);
}
}
// 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 = (int) 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));
}
// merge autowiring types
foreach ($definition->getAutowiringTypes() as $autowiringType) {
$def->addAutowiringType($autowiringType);
}
// these attributes are always taken from the child
$def->setAbstract($definition->isAbstract());
$def->setScope($definition->getScope(false), false);
$def->setShared($definition->isShared());
$def->setTags($definition->getTags());
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;
/**
* 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;
/**
* @param ServiceReferenceGraphNode $sourceNode
* @param ServiceReferenceGraphNode $destNode
* @param mixed $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 string
*/
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\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\DependencyInjection\Reference;
/**
* 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;
/**
* 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\ContainerBuilder;
/**
* This class is used to remove circular dependencies between individual passes.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class Compiler
{
private $passConfig;
private $log = array();
private $loggingFormatter;
private $serviceReferenceGraph;
public function __construct()
{
$this->passConfig = new PassConfig();
$this->serviceReferenceGraph = new ServiceReferenceGraph();
$this->loggingFormatter = new LoggingFormatter();
}
/**
* Returns the PassConfig.
*
* @return PassConfig The PassConfig instance
*/
public function getPassConfig()
{
return $this->passConfig;
}
/**
* Returns the ServiceReferenceGraph.
*
* @return ServiceReferenceGraph The ServiceReferenceGraph instance
*/
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
*/
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.
*/
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\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
/**
* Guesses constructor arguments of services definitions and try to instantiate services if necessary.
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class AutowirePass implements CompilerPassInterface
{
private $container;
private $reflectionClasses = array();
private $definedTypes = array();
private $types;
private $notGuessableTypes = array();
private $autowired = array();
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
$throwingAutoloader = function ($class) { throw new \ReflectionException(sprintf('Class %s does not exist', $class)); };
spl_autoload_register($throwingAutoloader);
try {
$this->container = $container;
foreach ($container->getDefinitions() as $id => $definition) {
if ($definition->isAutowired()) {
$this->completeDefinition($id, $definition);
}
}
} catch (\Exception $e) {
} catch (\Throwable $e) {
}
spl_autoload_unregister($throwingAutoloader);
// Free memory and remove circular reference to container
$this->container = null;
$this->reflectionClasses = array();
$this->definedTypes = array();
$this->types = null;
$this->notGuessableTypes = array();
$this->autowired = array();
if (isset($e)) {
throw $e;
}
}
/**
* Wires the given definition.
*
* @param string $id
* @param Definition $definition
*
* @throws RuntimeException
*/
private function completeDefinition($id, Definition $definition)
{
if ($definition->getFactory() || $definition->getFactoryClass(false) || $definition->getFactoryService(false)) {
throw new RuntimeException(sprintf('Service "%s" can use either autowiring or a factory, not both.', $id));
}
if (!$reflectionClass = $this->getReflectionClass($id, $definition)) {
return;
}
$this->container->addClassResource($reflectionClass);
if (!$constructor = $reflectionClass->getConstructor()) {
return;
}
$parameters = $constructor->getParameters();
if (method_exists('ReflectionMethod', 'isVariadic') && $constructor->isVariadic()) {
array_pop($parameters);
}
$arguments = $definition->getArguments();
foreach ($parameters as $index => $parameter) {
if (array_key_exists($index, $arguments) && '' !== $arguments[$index]) {
continue;
}
try {
if (!$typeHint = $parameter->getClass()) {
if (isset($arguments[$index])) {
continue;
}
// no default value? Then fail
if (!$parameter->isOptional()) {
throw new RuntimeException(sprintf('Unable to autowire argument index %d ($%s) for the service "%s". If this is an object, give it a type-hint. Otherwise, specify this argument\'s value explicitly.', $index, $parameter->name, $id));
}
// specifically pass the default value
$arguments[$index] = $parameter->getDefaultValue();
continue;
}
if (isset($this->autowired[$typeHint->name])) {
$arguments[$index] = $this->autowired[$typeHint->name] ? new Reference($this->autowired[$typeHint->name]) : null;
continue;
}
if (null === $this->types) {
$this->populateAvailableTypes();
}
if (isset($this->types[$typeHint->name]) && !isset($this->notGuessableTypes[$typeHint->name])) {
$value = new Reference($this->types[$typeHint->name]);
} else {
try {
$value = $this->createAutowiredDefinition($typeHint, $id);
} catch (RuntimeException $e) {
if ($parameter->isDefaultValueAvailable()) {
$value = $parameter->getDefaultValue();
} elseif ($parameter->allowsNull()) {
$value = null;
} else {
throw $e;
}
$this->autowired[$typeHint->name] = false;
}
}
} catch (\ReflectionException $e) {
// Typehint against a non-existing class
if (!$parameter->isDefaultValueAvailable()) {
throw new RuntimeException(sprintf('Cannot autowire argument %s for %s because the type-hinted class does not exist (%s).', $index + 1, $definition->getClass(), $e->getMessage()), 0, $e);
}
$value = $parameter->getDefaultValue();
}
$arguments[$index] = $value;
}
if ($parameters && !isset($arguments[++$index])) {
while (0 <= --$index) {
$parameter = $parameters[$index];
if (!$parameter->isDefaultValueAvailable() || $parameter->getDefaultValue() !== $arguments[$index]) {
break;
}
unset($arguments[$index]);
}
}
// it's possible index 1 was set, then index 0, then 2, etc
// make sure that we re-order so they're injected as expected
ksort($arguments);
$definition->setArguments($arguments);
}
/**
* Populates the list of available types.
*/
private function populateAvailableTypes()
{
$this->types = array();
foreach ($this->container->getDefinitions() as $id => $definition) {
$this->populateAvailableType($id, $definition);
}
}
/**
* Populates the list of available types for a given definition.
*
* @param string $id
* @param Definition $definition
*/
private function populateAvailableType($id, Definition $definition)
{
// Never use abstract services
if ($definition->isAbstract()) {
return;
}
foreach ($definition->getAutowiringTypes() as $type) {
$this->definedTypes[$type] = true;
$this->types[$type] = $id;
unset($this->notGuessableTypes[$type]);
}
if (!$reflectionClass = $this->getReflectionClass($id, $definition)) {
return;
}
foreach ($reflectionClass->getInterfaces() as $reflectionInterface) {
$this->set($reflectionInterface->name, $id);
}
do {
$this->set($reflectionClass->name, $id);
} while ($reflectionClass = $reflectionClass->getParentClass());
}
/**
* Associates a type and a service id if applicable.
*
* @param string $type
* @param string $id
*/
private function set($type, $id)
{
if (isset($this->definedTypes[$type])) {
return;
}
if (!isset($this->types[$type])) {
$this->types[$type] = $id;
return;
}
if ($this->types[$type] === $id) {
return;
}
if (!isset($this->notGuessableTypes[$type])) {
$this->notGuessableTypes[$type] = true;
$this->types[$type] = (array) $this->types[$type];
}
$this->types[$type][] = $id;
}
/**
* Registers a definition for the type if possible or throws an exception.
*
* @param \ReflectionClass $typeHint
* @param string $id
*
* @return Reference A reference to the registered definition
*
* @throws RuntimeException
*/
private function createAutowiredDefinition(\ReflectionClass $typeHint, $id)
{
if (isset($this->notGuessableTypes[$typeHint->name])) {
$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
$matchingServices = implode(', ', $this->types[$typeHint->name]);
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $typeHint->name, $id, $classOrInterface, $matchingServices));
}
if (!$typeHint->isInstantiable()) {
$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". No services were found matching this %s and it cannot be auto-registered.', $typeHint->name, $id, $classOrInterface));
}
$this->autowired[$typeHint->name] = $argumentId = sprintf('autowired.%s', $typeHint->name);
$argumentDefinition = $this->container->register($argumentId, $typeHint->name);
$argumentDefinition->setPublic(false);
try {
$this->completeDefinition($argumentId, $argumentDefinition);
} catch (RuntimeException $e) {
$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
$message = sprintf('Unable to autowire argument of type "%s" for the service "%s". No services were found matching this %s and it cannot be auto-registered.', $typeHint->name, $id, $classOrInterface);
throw new RuntimeException($message, 0, $e);
}
return new Reference($argumentId);
}
/**
* Retrieves the reflection class associated with the given service.
*
* @param string $id
* @param Definition $definition
*
* @return \ReflectionClass|false
*/
private function getReflectionClass($id, Definition $definition)
{
if (isset($this->reflectionClasses[$id])) {
return $this->reflectionClasses[$id];
}
// Cannot use reflection if the class isn't set
if (!$class = $definition->getClass()) {
return false;
}
$class = $this->container->getParameterBag()->resolveValue($class);
if ($deprecated = $definition->isDeprecated()) {
$prevErrorHandler = set_error_handler(function ($level, $message, $file, $line) use (&$prevErrorHandler) {
return (E_USER_DEPRECATED === $level || !$prevErrorHandler) ? false : $prevErrorHandler($level, $message, $file, $line);
});
}
$e = null;
try {
$reflector = new \ReflectionClass($class);
} catch (\Exception $e) {
} catch (\Throwable $e) {
}
if ($deprecated) {
restore_error_handler();
}
if (null !== $e) {
if (!$e instanceof \ReflectionException) {
throw $e;
}
$reflector = false;
}
return $this->reflectionClasses[$id] = $reflector;
}
}
<?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 bool
*/
private $repeat = false;
private $passes;
/**
* @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.
*/
public function process(ContainerBuilder $container)
{
do {
$this->repeat = false;
foreach ($this->passes as $pass) {
$pass->process($container);
}
} while ($this->repeat);
}
/**
* 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\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;
/**
* Process the Container to replace aliases with service definitions.
*
* @throws InvalidArgumentException if the service definition does not exist
*/
public function process(ContainerBuilder $container)
{
// Setup
$this->compiler = $container->getCompiler();
$this->formatter = $this->compiler->getLoggingFormatter();
// First collect all alias targets that need to be replaced
$seenAliasTargets = array();
$replacements = array();
foreach ($container->getAliases() as $definitionId => $target) {
$targetId = (string) $target;
// Special case: leave this target alone
if ('service_container' === $targetId) {
continue;
}
// Check if target needs to be replaces
if (isset($replacements[$targetId])) {
$container->setAlias($definitionId, $replacements[$targetId]);
}
// No need to process the same target twice
if (isset($seenAliasTargets[$targetId])) {
continue;
}
// Process new target
$seenAliasTargets[$targetId] = true;
try {
$definition = $container->getDefinition($targetId);
} catch (InvalidArgumentException $e) {
throw new InvalidArgumentException(sprintf('Unable to replace alias "%s" with actual definition "%s".', $definitionId, $targetId), null, $e);
}
if ($definition->isPublic()) {
continue;
}
// Remove private definition and schedule for replacement
$definition->setPublic(true);
$container->setDefinition($definitionId, $definition);
$container->removeDefinition($targetId);
$replacements[$targetId] = $definitionId;
}
// Now replace target instances in all definitions
foreach ($container->getDefinitions() as $definitionId => $definition) {
$definition->setArguments($this->updateArgumentReferences($replacements, $definitionId, $definition->getArguments()));
$definition->setMethodCalls($this->updateArgumentReferences($replacements, $definitionId, $definition->getMethodCalls()));
$definition->setProperties($this->updateArgumentReferences($replacements, $definitionId, $definition->getProperties()));
$definition->setFactoryService($this->updateFactoryReferenceId($replacements, $definition->getFactoryService(false)), false);
$definition->setFactory($this->updateFactoryReference($replacements, $definition->getFactory()));
}
}
/**
* Recursively updates references in an array.
*
* @param array $replacements Table of aliases to replace
* @param string $definitionId Identifier of this definition
* @param array $arguments Where to replace the aliases
*
* @return array
*/
private function updateArgumentReferences(array $replacements, $definitionId, array $arguments)
{
foreach ($arguments as $k => $argument) {
// Handle recursion step
if (\is_array($argument)) {
$arguments[$k] = $this->updateArgumentReferences($replacements, $definitionId, $argument);
continue;
}
// Skip arguments that don't need replacement
if (!$argument instanceof Reference) {
continue;
}
$referenceId = (string) $argument;
if (!isset($replacements[$referenceId])) {
continue;
}
// Perform the replacement
$newId = $replacements[$referenceId];
$arguments[$k] = new Reference($newId, $argument->getInvalidBehavior());
$this->compiler->addLogMessage($this->formatter->formatUpdateReference($this, $definitionId, $referenceId, $newId));
}
return $arguments;
}
/**
* Returns the updated reference for the factory service.
*
* @param array $replacements Table of aliases to replace
* @param string|null $referenceId Factory service reference identifier
*
* @return string|null
*/
private function updateFactoryReferenceId(array $replacements, $referenceId)
{
if (null === $referenceId) {
return;
}
return isset($replacements[$referenceId]) ? $replacements[$referenceId] : $referenceId;
}
private function updateFactoryReference(array $replacements, $factory)
{
if (\is_array($factory) && $factory[0] instanceof Reference && isset($replacements[$referenceId = (string) $factory[0]])) {
$factory[0] = new Reference($replacements[$referenceId], $factory[0]->getInvalidBehavior());
}
return $factory;
}
}
<?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
{
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\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
/**
* 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 $onlyConstructorArguments;
/**
* @param bool $onlyConstructorArguments Sets this Service Reference pass to ignore method calls
*/
public function __construct($onlyConstructorArguments = false)
{
$this->onlyConstructorArguments = (bool) $onlyConstructorArguments;
}
/**
* {@inheritdoc}
*/
public function setRepeatedPass(RepeatedPass $repeatedPass)
{
// no-op for BC
}
/**
* Processes a ContainerBuilder object to populate the service reference graph.
*/
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 ($definition->getFactoryService(false)) {
$this->processArguments(array(new Reference($definition->getFactoryService(false))));
}
if (\is_array($definition->getFactory())) {
$this->processArguments($definition->getFactory());
}
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());
if (\is_array($argument->getFactory())) {
$this->processArguments($argument->getFactory());
}
if ($argument->getFactoryService(false)) {
$this->processArguments(array(new Reference($argument->getFactoryService(false))));
}
}
}
}
/**
* 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;
}
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;
use Symfony\Component\DependencyInjection\ContainerInterface;
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
* - shared 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.
*
* @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(false)) {
throw new RuntimeException(sprintf('A synthetic service ("%s") cannot be of scope "prototype".', $id));
}
// shared service has non-prototype scope
if ($definition->isShared() && ContainerInterface::SCOPE_PROTOTYPE === $definition->getScope(false)) {
throw new RuntimeException(sprintf('A shared service ("%s") cannot be of scope "prototype".', $id));
}
if ($definition->getFactory() && ($definition->getFactoryClass(false) || $definition->getFactoryService(false) || $definition->getFactoryMethod(false))) {
throw new RuntimeException(sprintf('A service ("%s") can use either the old or the new factory syntax, not both.', $id));
}
// non-synthetic, non-abstract service has class
if (!$definition->isAbstract() && !$definition->isSynthetic() && !$definition->getClass()) {
if ($definition->getFactory() || $definition->getFactoryClass(false) || $definition->getFactoryService(false)) {
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));
}
// tag attribute values must be scalars
foreach ($definition->getTags() as $name => $tags) {
foreach ($tags as $attributes) {
foreach ($attributes as $attribute => $value) {
if (!is_scalar($value) && null !== $value) {
throw new RuntimeException(sprintf('A "tags" attribute must be of a scalar-type for service "%s", tag "%s", attribute "%s".', $id, $name, $attribute));
}
}
}
}
}
}
}
<?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\ServiceCircularReferenceException;
/**
* 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 $currentPath;
private $checkedNodes;
/**
* Checks the ContainerBuilder object for circular references.
*/
public function process(ContainerBuilder $container)
{
$graph = $container->getCompiler()->getServiceReferenceGraph();
$this->checkedNodes = array();
foreach ($graph->getNodes() as $id => $node) {
$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();
if (empty($this->checkedNodes[$id])) {
// don't check circular dependencies for lazy services
if (!$node->getValue() || !$node->getValue()->isLazy()) {
$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());
}
$this->checkedNodes[$id] = true;
array_pop($this->currentPath);
}
}
}
}
<?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 = array();
/**
* Checks if the graph has a specific node.
*
* @param string $id Id to check
*
* @return bool
*/
public function hasNode($id)
{
return isset($this->nodes[$id]);
}
/**
* Gets a node by identifier.
*
* @param string $id The id to retrieve
*
* @return ServiceReferenceGraphNode
*
* @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[]
*/
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 mixed $sourceValue
* @param string $destId
* @param mixed $destValue
* @param string $reference
*/
public function connect($sourceId, $sourceValue, $destId, $destValue = null, $reference = null)
{
if (null === $sourceId || null === $destId) {
return;
}
$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 mixed $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\Alias;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
/**
* Sets a service to be an alias of another one, given a format pattern.
*/
class AutoAliasServicePass implements CompilerPassInterface
{
/**
* {@inheritdoc}
*/
public function process(ContainerBuilder $container)
{
foreach ($container->findTaggedServiceIds('auto_alias') as $serviceId => $tags) {
foreach ($tags as $tag) {
if (!isset($tag['format'])) {
throw new InvalidArgumentException(sprintf('Missing tag information "format" on auto_alias service "%s".', $serviceId));
}
$aliasId = $container->getParameterBag()->resolveValue($tag['format']);
if ($container->hasDefinition($aliasId) || $container->hasAlias($aliasId)) {
$container->setAlias($serviceId, new Alias($aliasId));
}
}
}
}
}
<?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;
class Alias
{
private $id;
private $public;
/**
* @param string $id Alias identifier
* @param bool $public If this alias is public
*/
public function __construct($id, $public = true)
{
$this->id = strtolower($id);
$this->public = $public;
}
/**
* Checks if this DI Alias should be public or not.
*
* @return bool
*/
public function isPublic()
{
return $this->public;
}
/**
* Sets if this Alias is public.
*
* @param bool $boolean If this Alias should be public
*/
public function setPublic($boolean)
{
$this->public = (bool) $boolean;
}
/**
* Returns the Id of this alias.
*
* @return string The alias id
*/
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\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;
/**
* 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;
/**
* 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 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;
/**
* 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 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 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\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;
/**
* 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;
/**
* 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;
/**
* @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;
/**
* 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;
/**
* 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;
/**
* 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;
/**
* ContainerAwareInterface should be implemented by classes that depends on a Container.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface ContainerAwareInterface
{
/**
* Sets the container.
*/
public function setContainer(ContainerInterface $container = 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\DependencyInjection;
/**
* ResettableContainerInterface defines additional resetting functionality
* for containers, allowing to release shared services when the container is
* not needed anymore.
*
* @author Christophe Coevoet <stof@notk.org>
*/
interface ResettableContainerInterface extends ContainerInterface
{
/**
* Resets shared services from the container.
*
* The container is not intended to be used again after being reset in a normal workflow. This method is
* meant as a way to release references for ref-counting.
* A subsequent call to ContainerInterface::get will recreate a new instance of the shared service.
*/
public function reset();
}
<?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>
*
* @deprecated since version 2.8, to be removed in 3.0. Use the ContainerAwareTrait instead.
*/
abstract class ContainerAware implements ContainerAwareInterface
{
/**
* @var ContainerInterface
*/
protected $container;
/**
* {@inheritdoc}
*/
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
}
}
Symfony Polyfill / Ctype
========================
This component provides `ctype_*` functions to users who run php versions without the ctype extension.
More information can be found in the
[main Polyfill README](https://github.com/symfony/polyfill/blob/master/README.md).
License
=======
This library is released under the [MIT license](LICENSE).
Copyright (c) 2018-2019 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\Polyfill\Ctype;
/**
* Ctype implementation through regex.
*
* @internal
*
* @author Gert de Pagter <BackEndTea@gmail.com>
*/
final class Ctype
{
/**
* Returns TRUE if every character in text is either a letter or a digit, FALSE otherwise.
*
* @see https://php.net/ctype-alnum
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_alnum($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z0-9]/', $text);
}
/**
* Returns TRUE if every character in text is a letter, FALSE otherwise.
*
* @see https://php.net/ctype-alpha
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_alpha($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text && !preg_match('/[^A-Za-z]/', $text);
}
/**
* Returns TRUE if every character in text is a control character from the current locale, FALSE otherwise.
*
* @see https://php.net/ctype-cntrl
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_cntrl($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text && !preg_match('/[^\x00-\x1f\x7f]/', $text);
}
/**
* Returns TRUE if every character in the string text is a decimal digit, FALSE otherwise.
*
* @see https://php.net/ctype-digit
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_digit($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text && !preg_match('/[^0-9]/', $text);
}
/**
* Returns TRUE if every character in text is printable and actually creates visible output (no white space), FALSE otherwise.
*
* @see https://php.net/ctype-graph
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_graph($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text && !preg_match('/[^!-~]/', $text);
}
/**
* Returns TRUE if every character in text is a lowercase letter.
*
* @see https://php.net/ctype-lower
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_lower($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text && !preg_match('/[^a-z]/', $text);
}
/**
* Returns TRUE if every character in text will actually create output (including blanks). Returns FALSE if text contains control characters or characters that do not have any output or control function at all.
*
* @see https://php.net/ctype-print
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_print($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text && !preg_match('/[^ -~]/', $text);
}
/**
* Returns TRUE if every character in text is printable, but neither letter, digit or blank, FALSE otherwise.
*
* @see https://php.net/ctype-punct
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_punct($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text && !preg_match('/[^!-\/\:-@\[-`\{-~]/', $text);
}
/**
* Returns TRUE if every character in text creates some sort of white space, FALSE otherwise. Besides the blank character this also includes tab, vertical tab, line feed, carriage return and form feed characters.
*
* @see https://php.net/ctype-space
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_space($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text && !preg_match('/[^\s]/', $text);
}
/**
* Returns TRUE if every character in text is an uppercase letter.
*
* @see https://php.net/ctype-upper
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_upper($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text && !preg_match('/[^A-Z]/', $text);
}
/**
* Returns TRUE if every character in text is a hexadecimal 'digit', that is a decimal digit or a character from [A-Fa-f] , FALSE otherwise.
*
* @see https://php.net/ctype-xdigit
*
* @param string|int $text
*
* @return bool
*/
public static function ctype_xdigit($text)
{
$text = self::convert_int_to_char_for_ctype($text);
return \is_string($text) && '' !== $text && !preg_match('/[^A-Fa-f0-9]/', $text);
}
/**
* Converts integers to their char versions according to normal ctype behaviour, if needed.
*
* If an integer between -128 and 255 inclusive is provided,
* it is interpreted as the ASCII value of a single character
* (negative values have 256 added in order to allow characters in the Extended ASCII range).
* Any other integer is interpreted as a string containing the decimal digits of the integer.
*
* @param string|int $int
*
* @return mixed
*/
private static function convert_int_to_char_for_ctype($int)
{
if (!\is_int($int)) {
return $int;
}
if ($int < -128 || $int > 255) {
return (string) $int;
}
if ($int < 0) {
$int += 256;
}
return \chr($int);
}
}
{
"name": "symfony/polyfill-ctype",
"type": "library",
"description": "Symfony polyfill for ctype functions",
"keywords": ["polyfill", "compatibility", "portable", "ctype"],
"homepage": "https://symfony.com",
"license": "MIT",
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"require": {
"php": ">=5.3.3"
},
"autoload": {
"psr-4": { "Symfony\\Polyfill\\Ctype\\": "" },
"files": [ "bootstrap.php" ]
},
"suggest": {
"ext-ctype": "For best performance"
},
"minimum-stability": "dev",
"extra": {
"branch-alias": {
"dev-master": "1.18-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
}
}
<?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.
*/
use Symfony\Polyfill\Ctype as p;
if (!function_exists('ctype_alnum')) {
function ctype_alnum($text) { return p\Ctype::ctype_alnum($text); }
}
if (!function_exists('ctype_alpha')) {
function ctype_alpha($text) { return p\Ctype::ctype_alpha($text); }
}
if (!function_exists('ctype_cntrl')) {
function ctype_cntrl($text) { return p\Ctype::ctype_cntrl($text); }
}
if (!function_exists('ctype_digit')) {
function ctype_digit($text) { return p\Ctype::ctype_digit($text); }
}
if (!function_exists('ctype_graph')) {
function ctype_graph($text) { return p\Ctype::ctype_graph($text); }
}
if (!function_exists('ctype_lower')) {
function ctype_lower($text) { return p\Ctype::ctype_lower($text); }
}
if (!function_exists('ctype_print')) {
function ctype_print($text) { return p\Ctype::ctype_print($text); }
}
if (!function_exists('ctype_punct')) {
function ctype_punct($text) { return p\Ctype::ctype_punct($text); }
}
if (!function_exists('ctype_space')) {
function ctype_space($text) { return p\Ctype::ctype_space($text); }
}
if (!function_exists('ctype_upper')) {
function ctype_upper($text) { return p\Ctype::ctype_upper($text); }
}
if (!function_exists('ctype_xdigit')) {
function ctype_xdigit($text) { return p\Ctype::ctype_xdigit($text); }
}
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit0cffd5de0edad1133a933321d7b83570::getLoader();
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD;
/**
* This is the main facade of the PHP PMD application
*/
class PHPMD
{
/**
* The current PHPMD version.
*/
const VERSION = '2.9.1snapshot202009232245';
/**
* 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 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 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->setIgnorePattern($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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD;
/**
* This factory class is used to create the {@link \PHPMD\RuleSet} instance
* that PHPMD will use to analyze the source code.
*/
class RuleSetFactory
{
/**
* Is the strict mode active?
*
* @var boolean
* @since 1.2.0
*/
private $strict = false;
/**
* The data directory set within the class constructor.
*
* @var string
*/
private $location;
/**
* The minimum priority for rules to load.
*
* @var integer
*/
private $minimumPriority = Rule::LOWEST_PRIORITY;
/**
* The maximum priority for rules to load.
*
* @var integer
*/
private $maximumPriority = Rule::HIGHEST_PRIORITY;
/**
* Constructs a new default rule-set factory instance.
*/
public function __construct()
{
$this->location = __DIR__ . '/../../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;
}
/**
* Sets the maximum priority that a rule must have.
*
* @param integer $maximumPriority The maximum priority value.
* @return void
*/
public function setMaximumPriority($maximumPriority)
{
$this->maximumPriority = $maximumPriority;
}
/**
* 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 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 Path to rule set file name
* @throws RuleSetNotFoundException Thrown if no readable file found
*/
private function createRuleSetFileName($ruleSetOrFileName)
{
foreach ($this->filePaths($ruleSetOrFileName) as $filePath) {
if ($this->isReadableFile($filePath)) {
return $filePath;
}
}
throw new RuleSetNotFoundException($ruleSetOrFileName);
}
/**
* Lists available rule-set identifiers in given directory.
*
* @param string $directory The directory to scan for rule-sets.
* @return 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
* @throws \RuntimeException When loading the XML file fails.
*/
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);
return;
}
if ('' === (string)$node['ref']) {
$this->parseSingleRuleNode($ruleSet, $node);
return;
}
$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);
$ruleSetFactory->setMaximumPriority($this->maximumPriority);
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 RuleClassFileNotFoundException
* @throws 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 && $rule->getPriority() >= $this->maximumPriority) {
$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 && $rule->getPriority() >= $this->maximumPriority) {
$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 Thrown if file is not proper xml
*/
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;
}
/**
* Checks if given file path exists, is file (or symlink to file)
* and is readable by current user
*
* @param string $filePath File path to check against
* @return bool True if file exists and is readable, false otherwise
*/
private function isReadableFile($filePath)
{
return is_readable($filePath) && is_file($filePath);
}
/**
* Returns list of possible file paths to search against code rules
*
* @param string $fileName Rule set file name
* @return array Array of possible file locations
*/
private function filePaths($fileName)
{
$filePathParts = array(
array($fileName),
array($this->location, $fileName),
array($this->location, 'rulesets', $fileName . '.xml'),
array(getcwd(), 'rulesets', $fileName . '.xml'),
);
foreach (explode(PATH_SEPARATOR, get_include_path()) as $includePath) {
$filePathParts[] = array($includePath, $fileName);
$filePathParts[] = array($includePath, $fileName . '.xml');
}
return array_map('implode', array_fill(0, count($filePathParts), DIRECTORY_SEPARATOR), $filePathParts);
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD;
/**
* @deprecated 3.0.0 Use PHPMD\Exception\RuleClassFileNotFoundException instead.
*/
class_alias('PHPMD\Exception\RuleClassFileNotFoundException', 'PHPMD\RuleClassFileNotFoundException');
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD;
/**
* Base interface for a PHPMD rule.
*
* @since 1.1.0
*/
interface Rule
{
/**
* The default lowest rule priority.
*/
const LOWEST_PRIORITY = 5;
/**
* The default highest rule priority.
*/
const HIGHEST_PRIORITY = 1;
/**
* 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 Report
*/
public function getReport();
/**
* Sets the violation report for this rule.
*
* @param Report $report
* @return void
*/
public function setReport(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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Writer;
use PHPMD\AbstractWriter;
/**
* This writer uses PHP's stream api as its output target.
*/
class StreamWriter extends AbstractWriter
{
/**
* The stream resource handle
*
* @var resource
*/
private $stream = null;
/**
* Constructs a new stream writer instance.
*
* @param resource|string $streamResourceOrUri
* @throws \RuntimeException If the output directory cannot be found.
*/
public function __construct($streamResourceOrUri)
{
if (is_resource($streamResourceOrUri) === true) {
$this->stream = $streamResourceOrUri;
return;
}
$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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD;
/**
* Simple data class that we use to keep parsing errors for the report renderer.
*
* @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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD;
/**
* Abstract base class for PHPMD rendering engines.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD;
/**
* The report class collects all found violations and further information about
* a PHPMD run.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Node;
use PDepend\Source\AST\AbstractASTCallable;
/**
* Abstract base class for PHP_Depend function and method wrappers.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Node;
use PDepend\Source\AST\ASTClass;
/**
* Wrapper around PHP_Depend's class objects.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Node;
use PDepend\Source\AST\ASTTrait;
/**
* Wrapper around PHP_Depend's interface objects.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Node;
use PHPMD\Rule;
/**
* Simple code annotation class.
*/
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 (lcfirst($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\.' . preg_replace('/^.*\/([^\/]*)$/', '$1', $rule->getName()) . '/',
$this->value
)) {
return true;
}
return (stripos($rule->getName(), $this->value) !== false);
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Node;
use PHPMD\Rule;
/**
* Collection of code annotations.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*
* Methods available on $node via PHPMD\AbstractNode::__call
*
* @method bool isPrivate() Returns true if this node is marked as private.
*/
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;
}
}
$parentType = $parentNode->getParentClass();
if (is_object($parentType)) {
$methods = $parentType->getAllMethods();
if (isset($methods[$methodName])) {
return false;
}
}
return true;
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Node;
use PHPMD\Rule;
/**
* Abstract base class for all code nodes.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Node;
use PDepend\Source\AST\ASTFunction;
/**
* Wrapper around a PDepend function node.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Node;
use PDepend\Source\AST\ASTInterface;
/**
* Wrapper around PHP_Depend's interface objects.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Node;
use PHPMD\Rule;
/**
* Wrapper around a PHP_Depend ast node.
*/
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")
* @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Node;
use PDepend\Source\AST\AbstractASTClassOrInterface;
/**
* Abstract base class for classes and interfaces.
*/
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 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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\TextUI;
use PHPMD\Renderer\AnsiRenderer;
use PHPMD\Renderer\HTMLRenderer;
use PHPMD\Renderer\JSONRenderer;
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.
*
* @SuppressWarnings(PHPMD.LongVariable)
*/
class CommandLineOptions
{
/**
* Error code for invalid input
*/
const INPUT_ERROR = 23;
/**
* The minimum rule priority.
*
* @var integer
*/
protected $minimumPriority = Rule::LOWEST_PRIORITY;
/**
* The maximum rule priority.
*
* @var integer
*/
protected $maximumPriority = Rule::HIGHEST_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.
*
* Use asterisks to exclude by pattern. For example *src/foo/*.php or *src/foo/*
*
* @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 string[] $args
* @param string[] $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 '--min-priority':
case '--minimum-priority':
case '--minimumpriority':
$this->minimumPriority = (int)array_shift($args);
break;
case '--max-priority':
case '--maximum-priority':
case '--maximumpriority':
$this->maximumPriority = (int)array_shift($args);
break;
case '--report-file':
case '--reportfile':
$this->reportFile = array_shift($args);
break;
case '--input-file':
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 */
$this->extensions = array_shift($args);
break;
case '--suffixes':
$this->extensions = array_shift($args);
break;
case '--ignore':
$this->logDeprecated('ignore', 'exclude');
/* Deprecated: We use the exclude option now */
$this->ignore = array_shift($args);
break;
case '--exclude':
$this->ignore = array_shift($args);
break;
case '--version':
$this->version = true;
return;
case '--strict':
$this->strict = true;
break;
case '--not-strict':
$this->strict = false;
break;
case '--ignore-violations-on-exit':
$this->ignoreViolationsOnExit = true;
break;
case '--reportfile-html':
case '--reportfile-text':
case '--reportfile-xml':
case '--reportfile-json':
preg_match('(^\-\-reportfile\-(xml|html|text|json)$)', $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 maximum rule priority.
*
* @return integer
*/
public function getMaximumPriority()
{
return $this->maximumPriority;
}
/**
* 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>
* <li>json</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();
case 'json':
return $this->createJsonRenderer();
case 'ansi':
return $this->createAnsiRenderer();
default:
return $this->createCustomRenderer();
}
}
/**
* @return \PHPMD\Renderer\XMLRenderer
*/
protected function createXmlRenderer()
{
return new XMLRenderer();
}
/**
* @return \PHPMD\Renderer\TextRenderer
*/
protected function createTextRenderer()
{
return new TextRenderer();
}
/**
* @return \PHPMD\Renderer\AnsiRenderer
*/
protected function createAnsiRenderer()
{
return new AnsiRenderer();
}
/**
* @return \PHPMD\Renderer\HTMLRenderer
*/
protected function createHtmlRenderer()
{
return new HTMLRenderer();
}
/**
* @return \PHPMD\Renderer\JSONRenderer
*/
protected function createJsonRenderer()
{
return new JSONRenderer();
}
/**
* @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()
{
$availableRenderers = $this->getListOfAvailableRenderers();
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 .
'Example: phpmd /path/to/source format ruleset' . \PHP_EOL . \PHP_EOL .
'Available formats: ' . $availableRenderers . '.' . \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. Use asterisks to exclude by pattern. ' .
'For example *src/foo/*.php or *src/foo/*' . \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;
}
/**
* Get a list of available renderers
*
* @return string The list of renderers found.
*/
protected function getListOfAvailableRenderers()
{
$renderersDirPathName = __DIR__ . '/../Renderer';
$renderers = array();
foreach (scandir($renderersDirPathName) as $rendererFileName) {
if (preg_match('/^(\w+)Renderer.php$/i', $rendererFileName, $rendererName)) {
$renderers[] = strtolower($rendererName[1]);
}
}
sort($renderers);
if (count($renderers) > 1) {
return implode(', ', $renderers);
}
return array_pop($renderers);
}
/**
* 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 implode(',', array_map('trim', file($inputFile)));
}
throw new \InvalidArgumentException("Input file '{$inputFile}' not exists.");
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\TextUI;
use PHPMD\PHPMD;
use PHPMD\RuleSetFactory;
use PHPMD\Writer\StreamWriter;
/**
* This class provides a command line interface for PHPMD
*/
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() ? $opts->getReportFile() : 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($reportFile));
$renderers[] = $reportRenderer;
}
// Configure a rule set factory
$ruleSetFactory->setMinimumPriority($opts->getMinimumPriority());
$ruleSetFactory->setMaximumPriority($opts->getMaximumPriority());
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.9.1snapshot202009232245';
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 string[] $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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Renderer;
use PHPMD\AbstractRenderer;
use PHPMD\PHPMD;
use PHPMD\Report;
/**
* This class will render a JSON report.
*/
class JSONRenderer extends AbstractRenderer
{
/**
* {@inheritDoc}
*/
public function renderReport(Report $report)
{
$data = $this->initReportData();
$data = $this->addViolationsToReport($report, $data);
$data = $this->addErrorsToReport($report, $data);
$jsonData = $this->encodeReport($data);
$writer = $this->getWriter();
$writer->write($jsonData . PHP_EOL);
}
/**
* Create report data and add renderer meta properties
*
* @return array
*/
private function initReportData()
{
$data = array(
'version' => PHPMD::VERSION,
'package' => 'phpmd',
'timestamp' => date('c'),
);
return $data;
}
/**
* Add violations, if any, to the report data
*
* @param Report $report The report with potential violations.
* @param array $data The report output to add the violations to.
* @return array The report output with violations, if any.
*/
private function addViolationsToReport(Report $report, array $data)
{
$filesList = array();
/** @var RuleViolation $violation */
foreach ($report->getRuleViolations() as $violation) {
$fileName = $violation->getFileName();
$rule = $violation->getRule();
$filesList[$fileName]['file'] = $fileName;
$filesList[$fileName]['violations'][] = array(
'beginLine' => $violation->getBeginLine(),
'endLine' => $violation->getEndLine(),
'package' => $violation->getNamespaceName(),
'function' => $violation->getFunctionName(),
'class' => $violation->getClassName(),
'method' => $violation->getMethodName(),
'description' => $violation->getDescription(),
'rule' => $rule->getName(),
'ruleSet' => $rule->getRuleSetName(),
'externalInfoUrl' => $rule->getExternalInfoUrl(),
'priority' => $rule->getPriority(),
);
}
$data['files'] = array_values($filesList);
return $data;
}
/**
* Add errors, if any, to the report data
*
* @param Report $report The report with potential errors.
* @param array $data The report output to add the errors to.
* @return array The report output with errors, if any.
*/
private function addErrorsToReport(Report $report, array $data)
{
$errors = $report->getErrors();
if ($errors) {
foreach ($errors as $error) {
$data['errors'][] = array(
'fileName' => $error->getFile(),
'message' => $error->getMessage(),
);
}
}
return $data;
}
/**
* Encode report data to the JSON representation string
*
* @param array $data The report data
*
* @return string
*/
private function encodeReport($data)
{
$encodeOptions = JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP |
(defined('JSON_PRETTY_PRINT') ? JSON_PRETTY_PRINT : 0);
return json_encode($data, $encodeOptions);
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Renderer;
use PHPMD\AbstractRenderer;
use PHPMD\Report;
/**
* This renderer output a html file with all found violations.
*
* @author Premysl Karbula <premavansmuuf@gmail.com>
* @copyright 2017 Premysl Karbula. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class HTMLRenderer extends AbstractRenderer
{
const CATEGORY_PRIORITY = 'category_priority';
const CATEGORY_NAMESPACE = 'category_namespace';
const CATEGORY_RULESET = 'category_ruleset';
const CATEGORY_RULE = 'category_rule';
protected static $priorityTitles = array(
1 => 'Top (1)',
2 => 'High (2)',
3 => 'Moderate (3)',
4 => 'Low (4)',
5 => 'Lowest (5)',
);
// Used in self::colorize() method.
protected static $descHighlightRules = array(
'method' => array( // Method names.
'regex' => 'method\s+(((["\']).*["\'])|(\S+))',
'css-class' => 'hlt-method',
),
'quoted' => array( // Quoted strings.
'regex' => '(["\'][^\'"]+["\'])',
'css-class' => 'hlt-quoted',
),
'variable' => array( // Variables.
'regex' => '(\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)',
'css-class' => 'hlt-variable',
),
);
protected static $compiledHighlightRegex = null;
/**
* This method will be called on all renderers before the engine starts the
* real report processing.
*
* @return void
*/
public function start()
{
$writer = $this->getWriter();
$mainColor = "#2f838a";
// Avoid inlining styles.
$style = "
<script>
function toggle(id) {
var item = document.getElementById(id);
item.classList.toggle('hidden');
}
</script>
<style>
@media (min-width: 1366px) {
body { max-width: 80%; margin: auto; }
}
body {
font-family: sans-serif;
}
a {
color: $mainColor;
}
a:hover {
color: #333;
}
em {
font-weight: bold;
font-style: italic;
}
h1 {
padding: 0.5ex 0.2ex;
border-bottom: 2px solid #333;
}
table {
width: 100%;
border-spacing: 0;
}
table tr > th {
text-align: left;
}
table caption {
font-weight: bold;
padding: 1ex 0.5ex;
text-align: left;
font-size: 120%;
border-bottom: 2px solid #333;
}
tbody tr:nth-child(odd) {
background: rgba(0, 0, 0, 0.08);
}
tbody tr:hover {
background: #ffee99;
}
thead th {
border-bottom: 1px solid #aaa;
}
table td, table th {
padding: 0.5ex;
}
/* Table 'count' and 'percentage' column */
.t-cnt, .t-pct {
width: 5em;
}
.t-pct {
opacity: 0.8;
font-style: italic;
font-size: 80%;
}
/* Table bar chart */
.t-bar {
height: 0.5ex;
margin-top: 0.5ex;
background-color: $mainColor; /* rgba(47, 131, 138, 0.2); */
}
section, table {
margin-bottom: 2em;
}
#details-link.hidden {
display: none;
}
#details-wrapper.hidden {
display: none;
}
ul.code {
margin: 0;
padding: 0;
}
ul.code.hidden {
display: none;
}
ul.code li {
display: flex;
line-height: 1.4em;
font-family: monospace;
white-space: nowrap;
}
ul.code li:nth-child(odd) {
background-color: rgba(47, 131, 138, 0.1)
}
/* Excerpt: Line number */
ul.code .no {
width: 5%;
min-width: 5em;
text-align: right;
border-right: 1px solid rgba(47, 131, 138, 0.6);
padding-right: 1ex;
box-sizing: border-box;
}
/* Excerpt: Code */
ul.code .cd {
padding-left: 1ex;
white-space: pre-wrap;
box-sizing: border-box;
word-wrap: break-word;
overflow: hidden;
}
.hlt {
background: #ffee99 !important
}
.prio {
color: #333;
float: right;
}
.indx {
padding: 0.5ex 1ex;
background-color: #000;
color: #fff;
text-decoration: none;
}
.indx:hover {
background-color: $mainColor;
color: #fff;
}
/* Problem container */
.prb h3 {
padding: 1ex 0.5ex;
border-bottom: 2px solid #000;
font-size: 95%;
margin: 0;
}
.info-lnk {
font-style: italic !important;
font-weight: normal !important;
text-decoration: none;
}
.info-lnk.blck {
padding: 0.5ex 1ex;
background-color: rgba(47, 131, 138, 0.2);
}
.path-basename {
font-weight: bold;
}
.hlt-info {
display: inline-block;
padding: 2px 4px;
font-style: italic;
}
.hlt-info.quoted {
background-color: #92de71;
}
.hlt-info.variable {
background-color: #a3d2ff;
}
.hlt-info.method {
background-color: #f7c0ff;
}
.sub-info {
padding: 1ex 0.5ex;
}
/* Handle printer friendly styles */
@media print {
body, th { font-size: 10pt; }
.hlt-info { padding: 0; background: none; }
section, table { margin-bottom: 1em; }
h1, h2, h3, table caption { padding: 0.5ex 0.2ex; }
.prb h3 { border-bottom: 0.5px solid #aaa; }
.t-bar { display: none; }
.info-lnk { display: none; }
#details-wrapper { display: block !important; font-size: 90% !important; }
}
</style>";
$style = self::reduceWhitespace($style);
$writer->write("<html><head>{$style}<title>PHPMD Report</title></head><body>" . PHP_EOL);
$header = sprintf("
<header>
<h1>PHPMD Report</h1>
Generated at <em>%s</em>
with <a href='%s' target='_blank'>PHP Mess Detector</a>
on <em>PHP %s</em>
on <em>%s</em>
</header>
", date('Y-m-d H:i'), "https://phpmd.org", \PHP_VERSION, gethostname());
$writer->write($header);
}
/**
* 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)
{
$w = $this->getWriter();
$index = 0;
$violations = $report->getRuleViolations();
$count = count($violations);
$w->write(sprintf('<h3>%d problems found</h3>', $count));
// If no problems were found, don't bother with rendering anything else.
if (!$count) {
return;
}
// Render summary tables.
$w->write("<h2>Summary</h2>");
$categorized = self::sumUpViolations($violations);
$this->writeTable('By priority', 'Priority', $categorized[self::CATEGORY_PRIORITY]);
$this->writeTable('By namespace', 'PHP Namespace', $categorized[self::CATEGORY_NAMESPACE]);
$this->writeTable('By rule set', 'Rule set', $categorized[self::CATEGORY_RULESET]);
$this->writeTable('By name', 'Rule name', $categorized[self::CATEGORY_RULE]);
// Render details of each violation and place the "Details" display toggle.
$w->write("<h2 style='page-break-before: always'>Details</h2>");
$w->write("
<a
id='details-link'
class='info-lnk blck'
href='#'
onclick='toggle(\"details-link\"); toggle(\"details-wrapper\"); return false;'
>
Show details &#x25BC;
</a>");
$w->write("<div id='details-wrapper' class='hidden'>");
foreach ($violations as $violation) {
// This is going to be used as ID in HTML (deep anchoring).
$htmlId = "p-" . $index++;
// Get excerpt of the code from validated file.
$excerptHtml = null;
$excerpt = self::getLineExcerpt(
$violation->getFileName(),
$violation->getBeginLine(),
2
);
foreach ($excerpt as $line => $code) {
$class = $line === $violation->getBeginLine() ? " class='hlt'" : null;
$codeHtml = htmlspecialchars($code);
$excerptHtml .= "<li{$class}><div class='no'>{$line}</div><div class='cd'>{$codeHtml}</div></li>";
}
$descHtml = self::colorize(htmlentities($violation->getDescription()));
$filePath = $violation->getFileName();
$fileHtml = "<a href='file://$filePath' target='_blank'>" . self::highlightFile($filePath) . "</a>";
// Create an external link to rule's help, if there's any provided.
$linkHtml = null;
if ($url = $violation->getRule()->getExternalInfoUrl()) {
$linkHtml = "<a class='info-lnk' href='{$url}' target='_blank'>(help)</a>";
}
// HTML snippet handling the toggle to display the file's code.
$showCodeAnchor = "
<a class='info-lnk blck' href='#' onclick='toggle(\"$htmlId-code\"); return false;'>
Show code &#x25BC;
</a>";
$prio = self::$priorityTitles[$violation->getRule()->getPriority()];
$html = "
<section class='prb' id='$htmlId'>
<header>
<h3>
<a href='#$htmlId' class='indx'>#{$index}</a>
{$descHtml} {$linkHtml} <span class='prio'>{$prio}</span>
</h3>
</header>
<div class='sub-info'><b>File:</b> {$fileHtml} {$showCodeAnchor}</div>
<ul class='code hidden' id='$htmlId-code'>%s</ul>
</section>";
// Remove unnecessary tab/space characters at the line beginnings.
$html = self::reduceWhitespace($html);
$w->write(sprintf($html, $excerptHtml));
}
}
/**
* 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('</div></body></html>');
}
/**
* Return array of lines from a specified file:line, optionally with extra lines around
* for additional cognitive context.
*
* @return array
*/
protected static function getLineExcerpt($file, $lineNumber, $extra = 0)
{
if (!is_readable($file)) {
return array();
}
$file = new \SplFileObject($file);
// We have to subtract 1 to extract correct lines via SplFileObject.
$line = max($lineNumber - 1 - $extra, 0);
$result = array();
if (!$file->eof()) {
$file->seek($line);
for ($i = 0; $i <= ($extra * 2); $i++) {
$result[++$line] = trim((string)$file->current(), "\n");
$file->next();
}
}
return $result;
}
/**
* Take a rule description text and try to decorate/stylize parts of it with HTML.
* Based on self::$descHighlightRules config.
*
* @return string
*/
protected static function colorize($message)
{
// Compile final regex, if not done already.
if (!self::$compiledHighlightRegex) {
$prepared = self::$descHighlightRules;
array_walk($prepared, function (&$v, $k) {
$v = "(?<{$k}>{$v['regex']})";
});
self::$compiledHighlightRegex = "#(" . implode('|', $prepared) . ")#";
}
$rules = self::$descHighlightRules;
return preg_replace_callback(self::$compiledHighlightRegex, function ($x) use ($rules) {
// Extract currently matched specification of highlighting (Match groups
// are named and we can find out which is not empty.).
$definition = array_keys(array_intersect_key($rules, array_filter($x)));
$definition = reset($definition);
return "<span class='hlt-info {$definition}'>{$x[0]}</span>";
}, $message);
}
/**
* Take a file path and return a bit of HTML where the basename is wrapped in styled <span>.
*
* @return string
*/
protected static function highlightFile($path)
{
$file = substr(strrchr($path, "/"), 1);
$dir = str_replace($file, null, $path);
return $dir . "<span class='path-basename'>" . $file . '</span>';
}
/**
* Render a pretty informational table and send the HTML to the writer.
*
* @return void
*/
protected function writeTable($title, $itemsTitle, $items)
{
if (!$items) {
return;
}
$writer = $this->getWriter();
$rows = null;
// We will need to calculate percentages and whatnot.
$max = max($items);
$sum = array_sum($items);
foreach ($items as $name => $count) {
// Calculate chart/bar's percentage width relative to the highest occuring item.
$width = $max !== 0 ? $count / $max * 100 : 0; // Avoid division by zero.
$bar = sprintf(
'<div class="t-bar" style="width: %d%%; opacity: %.2f"></div>',
$width,
min(0.2 + $width / 100, 1) // Minimum opacity for the bar is 0.2.
);
$pct = $sum !== 0 ? sprintf('%.1f', $count / $sum * 100) : '-'; // Avoid division by zero.
$rows .= "<tr>
<td class='t-cnt'>$count</td>
<td class='t-pct'>$pct %</td>
<th class='t-n'>{$name}{$bar}</th>
</tr>";
}
$header = "<thead><tr><th>Count</th><th>%</th><th>$itemsTitle</th></tr></thead>";
$html = "<section><table><caption>$title</caption>{$header}{$rows}</table></section>";
$writer->write(self::reduceWhitespace($html));
}
/**
* Go through passed violations and count occurrences based on pre-specified conditions.
*
* @return array
*/
protected static function sumUpViolations($violations)
{
$result = array(
self::CATEGORY_PRIORITY => array(),
self::CATEGORY_NAMESPACE => array(),
self::CATEGORY_RULESET => array(),
self::CATEGORY_RULE => array(),
);
foreach ($violations as $v) {
// We use "ref" reference to make things somewhat easier to read.
// Also, using a reference to non-existing array index doesn't throw a notice.
if ($ns = $v->getNamespaceName()) {
$ref = &$result[self::CATEGORY_NAMESPACE][$ns];
$ref = isset($ref) ? $ref + 1 : 1;
}
$rule = $v->getRule();
// Friendly priority -> Add a describing word to "just number".
$friendlyPriority = self::$priorityTitles[$rule->getPriority()];
$ref = &$result[self::CATEGORY_PRIORITY][$friendlyPriority];
$ref = isset($ref) ? $ref + 1 : 1;
$ref = &$result[self::CATEGORY_RULESET][$rule->getRuleSetName()];
$ref = isset($ref) ? $ref + 1 : 1;
$ref = &$result[self::CATEGORY_RULE][$rule->getName()];
$ref = isset($ref) ? $ref + 1 : 1;
}
// Sort numbers in each category from high to low.
foreach ($result as &$inner) {
arsort($inner);
}
return $result;
}
/**
* Reduces two and more whitespaces in a row to a single whitespace to conserve space.
*
* @return string
*/
protected static function reduceWhitespace($input, $eol = true)
{
return preg_replace("#\s+#", " ", $input) . ($eol ? PHP_EOL : null);
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Renderer;
use PHPMD\AbstractRenderer;
use PHPMD\PHPMD;
use PHPMD\Report;
/**
* This class will render a Java-PMD compatible xml-report.
*/
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(' ' . htmlspecialchars($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 PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Renderer;
use PHPMD\AbstractRenderer;
use PHPMD\Report;
/**
* This renderer output a textual log with all found violations and suspect
* software artifacts.
*/
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
namespace PHPMD\Renderer;
use PHPMD\AbstractRenderer;
use PHPMD\Report;
use PHPMD\RuleViolation;
/**
* This renderer output a command line friendly log with all found violations
* and suspect software artifacts.
*/
class AnsiRenderer extends AbstractRenderer
{
/**
* @param \PHPMD\Report $report
* @return void
*/
public function renderReport(Report $report)
{
$this->writeViolationsReport($report);
$this->writeErrorsReport($report);
$this->writeReportSummary($report);
}
/**
* @param \PHPMD\Report $report
* @return void
*/
private function writeViolationsReport(Report $report)
{
if ($report->isEmpty()) {
return;
}
$padding = $this->getMaxLineNumberLength($report);
$previousFile = null;
foreach ($report->getRuleViolations() as $violation) {
if ($violation->getFileName() !== $previousFile) {
$this->writeViolationFileHeader($violation);
}
$this->writeViolationLine($violation, $padding);
$previousFile = $violation->getFileName();
}
}
/**
* @param \PHPMD\Report $report
* @return int|null
*/
private function getMaxLineNumberLength(Report $report)
{
$maxLength = null;
foreach ($report->getRuleViolations() as $violation) {
if ($maxLength === null || strlen($violation->getBeginLine()) > $maxLength) {
$maxLength = strlen($violation->getBeginLine());
}
}
return $maxLength;
}
/**
* @param \PHPMD\RuleViolation $violation
* @return void
*/
private function writeViolationFileHeader(RuleViolation $violation)
{
$fileHeader = sprintf(
'FILE: %s',
$violation->getFileName()
);
$this->getWriter()->write(
PHP_EOL . $fileHeader . PHP_EOL .
str_repeat('-', strlen($fileHeader)) . PHP_EOL
);
}
/**
* @param \PHPMD\RuleViolation $violation
* @param int $padding
* @return void
*/
private function writeViolationLine(RuleViolation $violation, $padding)
{
$this->getWriter()->write(sprintf(
" %s | \e[31mVIOLATION\e[0m | %s" . PHP_EOL,
str_pad($violation->getBeginLine(), $padding, ' '),
$violation->getDescription()
));
}
/**
* @param \PHPMD\Report $report
* @return void
*/
private function writeErrorsReport(Report $report)
{
if (!$report->hasErrors()) {
return;
}
/** @var ProcessingError $error */
foreach ($report->getErrors() as $error) {
$errorHeader = sprintf(
"\e[33mERROR\e[0m while parsing %s",
$error->getFile()
);
$this->getWriter()->write(
PHP_EOL . $errorHeader . PHP_EOL .
str_repeat('-', strlen($errorHeader) - 9) . PHP_EOL
);
$this->getWriter()->write(sprintf(
'%s' . PHP_EOL,
$error->getMessage()
));
}
}
/**
* @param \PHPMD\Report $report
* @return void
*/
private function writeReportSummary(Report $report)
{
$this->getWriter()->write(
sprintf(
PHP_EOL . 'Found %s %s and %s %s in %sms' . PHP_EOL,
count($report->getRuleViolations()),
count($report->getRuleViolations()) !== 1 ? 'violations' : 'violation',
iterator_count($report->getErrors()),
iterator_count($report->getErrors()) !== 1 ? 'errors' : 'error',
$report->getElapsedTimeInMillis()
)
);
if (count($report->getRuleViolations()) === 0 && iterator_count($report->getErrors()) === 0) {
$this->getWriter()->write(PHP_EOL . "\e[32mNo mess detected\e[0m" . PHP_EOL);
}
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD;
/**
* @deprecated 3.0.0 Use PHPMD\Exception\RuleClassNotFoundException instead.
*/
class_alias('PHPMD\Exception\RuleClassNotFoundException', 'PHPMD\RuleClassNotFoundException');
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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 void
*/
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 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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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>
*/
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)
{
$node = $this->getNode();
if (!method_exists($node, $name)) {
throw new \BadMethodCallException(
sprintf('Invalid method %s() called.', $name)
);
}
return call_user_func_array(array($node, $name), $args);
}
/**
* Returns the parent of this node or <b>null</b> when no parent node
* exists.
*
* @return ASTNode
*/
public function getParent()
{
$node = $this->node->getParent();
if ($node === 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 ASTNode|null
*/
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 ASTNode[]
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD;
/**
* @deprecated 3.0.0 Use PHPMD\Exception\RuleSetNotFoundException instead.
*/
class_alias('PHPMD\Exception\RuleSetNotFoundException', 'PHPMD\RuleSetNotFoundException');
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD;
/**
* This class is a collection of concrete source analysis rules.
*/
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) {
/** @var $rule 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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
class ParserFactory
{
/** @var string The default config file name */
const PDEPEND_CONFIG_FILE_NAME = '/pdepend.xml';
/** @var string The distribution config file name */
const PDEPEND_CONFIG_FILE_NAME_DIST = '/pdepend.xml.dist';
/**
* 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();
$currentWorkingDirectory = getcwd();
if (file_exists($currentWorkingDirectory . self::PDEPEND_CONFIG_FILE_NAME)) {
$application->setConfigurationFile($currentWorkingDirectory . self::PDEPEND_CONFIG_FILE_NAME);
} elseif (file_exists($currentWorkingDirectory . self::PDEPEND_CONFIG_FILE_NAME_DIST)) {
$application->setConfigurationFile($currentWorkingDirectory . self::PDEPEND_CONFIG_FILE_NAME_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) {
$trimmedPath = trim($path);
if (is_dir($trimmedPath)) {
$pdepend->addDirectory($trimmedPath);
continue;
}
$pdepend->addFile($trimmedPath);
}
}
/**
* 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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD;
use PHPMD\Node\ClassNode;
/**
* This is the abstract base class for pmd rules.
*
* @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 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
*
* Throws an exception when no property with <b>$name</b> exists
* and no default value to fall back was given.
*
* @param string $name The name of the property, e.g. "ignore-whitespace".
* @param mixed $default An optional default value to fall back instead of throwing an exception.
* @return mixed The value of a configured property.
* @throws \OutOfBoundsException When no property for <b>$name</b> exists and
* no default value to fall back was given.
*/
protected function getProperty($name, $default = null)
{
if (isset($this->properties[$name])) {
return $this->properties[$name];
}
if ($default !== null) {
return $default;
}
throw new \OutOfBoundsException('Property "' . $name . '" does not exist.');
}
/**
* Returns the value of a configured property as a boolean
*
* Throws an exception when no property with <b>$name</b> exists
* and no default value to fall back was given.
*
* @param string $name The name of the property, e.g. "ignore-whitespace".
* @param bool $default An optional default value to fall back instead of throwing an exception.
* @return bool The value of a configured property as a boolean.
* @throws \OutOfBoundsException When no property for <b>$name</b> exists and
* no default value to fall back was given.
*/
public function getBooleanProperty($name, $default = null)
{
return in_array($this->getProperty($name, $default), array('true', 'on', 1), false);
}
/**
* Returns the value of a configured property as an integer
*
* Throws an exception when no property with <b>$name</b> exists
* and no default value to fall back was given.
*
* @param string $name The name of the property, e.g. "minimum".
* @param int $default An optional default value to fall back instead of throwing an exception.
* @return int The value of a configured property as an integer.
* @throws \OutOfBoundsException When no property for <b>$name</b> exists and
* no default value to fall back was given.
*/
public function getIntProperty($name, $default = null)
{
return (int)$this->getProperty($name, $default);
}
/**
* Returns the raw string value of a configured property
*
* Throws an exception when no property with <b>$name</b> exists
* and no default value to fall back was given.
*
* @param string $name The name of the property, e.g. "exceptions".
* @param string|null $default An optional default value to fall back instead of throwing an exception.
* @return string The raw string value of a configured property.
* @throws \OutOfBoundsException When no property for <b>$name</b> exists and
* no default value to fall back was given.
*/
public function getStringProperty($name, $default = null)
{
return (string)$this->getProperty($name, $default);
}
/**
* 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);
}
/**
* Apply the current rule on each method of a class node.
*
* @param ClassNode $node class node containing methods.
*/
protected function applyOnClassMethods(ClassNode $node)
{
foreach ($node->getMethods() as $method) {
if ($method->hasSuppressWarningsAnnotationFor($this)) {
continue;
}
$this->apply($method);
}
}
/**
* 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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD;
/**
* This is abstract base class for an output writer.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Utility;
use InvalidArgumentException;
/**
* Utility class to provide string checks and manipulations
*/
class Strings
{
/**
* Returns the length of the given string, excluding at most one suffix
*
* @param string $stringName String to calculate the length for.
* @param array $subtractSuffixes List of suffixes to exclude from the calculated length.
* @return int The length of the string, without suffix, if applicable.
*/
public static function lengthWithoutSuffixes($stringName, array $subtractSuffixes)
{
$stringLength = strlen($stringName);
foreach ($subtractSuffixes as $suffix) {
$suffixLength = strlen($suffix);
if (substr($stringName, -$suffixLength) === $suffix) {
$stringLength -= $suffixLength;
break;
}
}
return $stringLength;
}
/**
* Split a string with the given separator, trim whitespaces around the parts and remove any empty strings
*
* @param string $listAsString The string to split.
* @param string $separator The separator to split the string with, similar to explode.
* @return array The list of trimmed and filtered parts of the string.
* @throws InvalidArgumentException When the separator is an empty string.
*/
public static function splitToList($listAsString, $separator)
{
if ($separator === '') {
throw new InvalidArgumentException("Separator can't be empty string");
}
return array_filter(
array_map('trim', explode($separator, $listAsString)),
function ($value) {
return $value !== '';
}
);
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Exception;
/**
* This type of exception is thrown when the class file for a configured rule
* does not exist within php's include path.
*/
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 PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Exception;
/**
* When a configured rule class does not exist.
*/
class RuleClassNotFoundException extends \RuntimeException
{
/**
* Constructs a new class not found exception.
*
* @param string $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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Exception;
/**
* This type of exception is thrown when a not existing rule-set was specified.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule;
use PDepend\Source\AST\ASTArguments;
use PDepend\Source\AST\ASTArrayIndexExpression;
use PDepend\Source\AST\ASTMemberPrimaryPrefix;
use PDepend\Source\AST\ASTPropertyPostfix;
use PDepend\Source\AST\ASTVariable;
use PDepend\Source\AST\ASTVariableDeclarator;
use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Node\ASTNode;
use ReflectionException;
use ReflectionFunction;
/**
* Base class for rules that rely on local variables.
*
* @since 0.2.6
*/
abstract class AbstractLocalVariable extends AbstractRule
{
/**
* @var array Self reference class names.
*/
protected $selfReferences = array('self', 'static');
/**
* PHP super globals that are available in all php scopes, so that they
* can never be unused local variables.
*
* @var array(string=>boolean)
* @link http://php.net/manual/en/reserved.variables.php
*/
protected 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,
'$php_errormsg' => true,
'$http_response_header' => 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 isSuperGlobal(AbstractNode $variable)
{
return isset(self::$superGlobals[$variable->getImage()]);
}
/**
* Tests if the given variable does not represent one of the PHP super globals
* that are available in scopes.
*
* @param \PHPMD\AbstractNode $variable
* @return boolean
*/
protected function isNotSuperGlobal(AbstractNode $variable)
{
return !$this->isSuperGlobal($variable);
}
/**
* 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));
}
/**
* Get the image of the given variable node.
*
* Prefix self:: and static:: properties with "::".
*
* @param ASTVariable|ASTPropertyPostfix|ASTVariableDeclarator $variable
* @return string
*/
protected function getVariableImage($variable)
{
$image = $variable->getImage();
if ($image === '::') {
return $image.$variable->getChild(1)->getImage();
}
$base = $variable;
$parent = $this->getNode($variable->getParent());
while ($parent instanceof ASTArrayIndexExpression &&
$base instanceof ASTNode &&
$parent->getChild(0) === $base->getNode()
) {
$base = $parent;
$parent = $this->getNode($base->getParent());
}
if ($parent instanceof ASTPropertyPostfix) {
$previousChildImage = $this->getParentMemberPrimaryPrefixImage($image, $parent);
if (in_array($previousChildImage, $this->selfReferences, true)) {
return "::$image";
}
}
return $image;
}
protected function getParentMemberPrimaryPrefixImage($image, ASTPropertyPostfix $postfix)
{
do {
$postfix = $postfix->getParent();
} while ($postfix && $postfix->getChild(0) && $postfix->getChild(0)->getImage() === $image);
$previousChildImage = $postfix->getChild(0)->getImage();
if ($postfix instanceof ASTMemberPrimaryPrefix &&
in_array($previousChildImage, $this->selfReferences)
) {
return $previousChildImage;
}
return null;
}
/**
* Return the PDepend node of ASTNode PHPMD node.
*
* Or return the input as is if it's not an ASTNode PHPMD node.
*
* @param mixed $node
* @return \PDepend\Source\AST\ASTArtifact|\PDepend\Source\AST\ASTNode
*/
protected function getNode($node)
{
if ($node instanceof ASTNode) {
return $node->getNode();
}
return $node;
}
/**
* Return true if the given variable is passed by reference in a native PHP function.
*
* @param ASTVariable|ASTPropertyPostfix|ASTVariableDeclarator $variable
* @return bool
*/
protected function isPassedByReference($variable)
{
$parent = $this->getNode($variable->getParent());
if ($parent && $parent instanceof ASTArguments) {
$argumentPosition = array_search($this->getNode($variable), $parent->getChildren());
$function = $this->getNode($parent->getParent());
$functionName = $function->getImage();
try {
$reflectionFunction = new ReflectionFunction($functionName);
$parameters = $reflectionFunction->getParameters();
if (isset($parameters[$argumentPosition]) && $parameters[$argumentPosition]->isPassedByReference()) {
return true;
}
} catch (ReflectionException $exception) {
// @TODO: Find a way to handle user-land functions
// @TODO: Find a way to handle methods
}
}
return false;
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*
* @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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule\Design;
use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;
/**
* This rule class will detect excessive long classes.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
class TooManyMethods extends AbstractRule implements ClassAware
{
/**
* Regular expression that filters all methods that are ignored by this rule.
*
* @var string
*/
protected $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;
}
/** @var AbstractTypeNode $node */
$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
*/
protected 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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule\Design;
use PDepend\Source\AST\AbstractASTNode;
use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Node\ASTNode;
use PHPMD\Node\ClassNode;
use PHPMD\Rule\ClassAware;
/**
* Count In Loop Expression Rule
*
* Performs a scan to check if loops use
* count() or sizeof() in expressions.
*
* Checks for:
* - for() loops
* - while() loops
* - do-while() loops
*
* @author Kamil Szymanski <kamilszymanski@gmail.com>
*/
class CountInLoopExpression extends AbstractRule implements ClassAware
{
/**
* List of functions to search against
*
* @var array
*/
protected $unwantedFunctions = array('count', 'sizeof');
/**
* List of already processed functions
*
* @var array
*/
protected $processedFunctions = array();
/**
* Functions in classes tends to be name-spaced
*
* @var string
*/
protected $currentNamespace = '';
/**
* Gets a list of loops in a node and iterates over them
*
* @param AbstractNode $node
* @return void
*/
public function apply(AbstractNode $node)
{
if ($node instanceof ClassNode) {
return $this->applyOnClassMethods($node);
}
$this->currentNamespace = $node->getNamespaceName() . '\\';
$loops = array_merge(
$node->findChildrenOfType('ForStatement'),
$node->findChildrenOfType('WhileStatement'),
$node->findChildrenOfType('DoWhileStatement')
);
/** @var AbstractNode $loop */
foreach ($loops as $loop) {
$this->findViolations($loop);
}
}
/**
* Scans for expressions and count() or sizeof() functions inside,
* if found, triggers a violation
*
* @param AbstractNode $loop Loop statement to look against
*/
protected function findViolations(AbstractNode $loop)
{
foreach ($loop->findChildrenOfType('Expression') as $expression) {
if ($this->isDirectChild($loop, $expression)) {
continue;
}
foreach ($expression->findChildrenOfType('FunctionPostfix') as $function) {
if (!$this->isUnwantedFunction($function)) {
continue;
}
$hash = $this->getHash($function->getNode());
if (isset($this->processedFunctions[$hash])) {
continue;
}
$this->addViolation($loop, array($function->getImage(), $loop->getImage()));
$this->processedFunctions[$hash] = true;
}
}
}
/**
* Checks whether node in a direct child of the loop
*
* @param AbstractNode $loop
* @param ASTNode $expression
* @return bool
*/
protected function isDirectChild(AbstractNode $loop, ASTNode $expression)
{
return $this->getHash($expression->getParent()->getNode()) !== $this->getHash($loop->getNode());
}
/**
* Generates an unique hash for a given node
*
* PDepend method getChildrenOfType() iterates trough all children of a node.
* As one function may be found more than once, we use a hash (which in reality
* is a clone of the node's metadata) to check, if a given node hasn't
* already been processed.
*
* Example hash:
* 22:22:10:15:PHPMD\count
*
* @param AbstractASTNode $node
* @return string
*/
protected function getHash(AbstractASTNode $node)
{
return sprintf(
'%s:%s:%s:%s:%s',
$node->getStartLine(),
$node->getEndLine(),
$node->getStartColumn(),
$node->getEndColumn(),
$node->getImage()
);
}
/**
* Checks the given function against the list of unwanted functions
*
* @param ASTNode $function
* @return bool
*/
protected function isUnwantedFunction(ASTNode $function)
{
$functionName = str_replace($this->currentNamespace, '', $function->getImage());
return in_array($functionName, $this->unwantedFunctions);
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule\Design;
use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;
/**
* This rule class detects violations of Coupling Between Objects metric.
*
* @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');
$threshold = $this->getIntProperty('maximum');
if ($cbo >= $threshold) {
$this->addViolation($node, array($node->getName(), $cbo, $threshold));
}
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
class TooManyPublicMethods extends AbstractRule implements ClassAware
{
/**
* Regular expression that filters all methods that are ignored by this rule.
*
* @var string
*/
protected $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;
}
/** @var AbstractTypeNode $node */
$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
*/
protected 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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*
* @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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule\Design;
use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;
/**
* This rule class detects empty catch blocks
*
* @author Grégoire Paris <postmaster@greg0ire.fr>
* @author Kamil Szymanski <kamilszymanski@gmail.com>
*/
class EmptyCatchBlock extends AbstractRule implements MethodAware, FunctionAware
{
/**
* This method checks if a given function or method contains an empty catch block
* and emits a rule violation when it exists.
*
* @param \PHPMD\AbstractNode $node
* @return void
*/
public function apply(AbstractNode $node)
{
foreach ($node->findChildrenOfType('CatchStatement') as $catchBlock) {
$scope = $catchBlock->getFirstChildOfType('ScopeStatement');
if (count($scope->getChildren()) === 0) {
$this->addViolation($catchBlock, array($node->getName()));
}
}
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*
* @link 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)
{
$ignoreNS = $this->getBooleanProperty('ignore-namespaces');
$namespace = $node->getNamespaceName();
foreach ($node->findChildrenOfType('FunctionPostfix') as $postfix) {
$fragment = $postfix->getImage();
if ($ignoreNS) {
$fragment = str_replace("{$namespace}\\", "", $fragment);
}
$fragment = strtolower($fragment);
if (false === in_array($fragment, $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, $fragment));
}
}
/**
* Returns an array with function images that are normally only used during
* development.
*
* @return array
*/
protected 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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule\CleanCode;
use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Node\ASTNode;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;
/**
* If Statement Assignment Rule
*
* This rule covers the following cases:
* - single assignment in an if clause
* - multiple assignments in same if clause
* - assignments in nested if clauses
* - assignments in elseif clauses
* - duplicated assignments (multiple conditions before and after *=* sign)
*
* Empty if clauses are skipped
*/
class IfStatementAssignment extends AbstractRule implements MethodAware, FunctionAware
{
/**
* @var array List of statement types where to forbid assignation.
*/
protected $ifStatements = array(
'IfStatement',
'ElseIfStatement',
);
/**
* This method checks if method/function has if clauses
* that use assignment instead of comparison.
*
* @param AbstractNode $node An instance of MethodNode or FunctionNode class
* @return void
*/
public function apply(AbstractNode $node)
{
$statements = $this->getStatements($node);
$expressions = $this->getExpressions($statements);
$assignments = $this->getAssignments($expressions);
$this->addViolations($node, $assignments);
}
/**
* Extracts if and elseif statements from method/function body
*
* @param AbstractNode $node An instance of MethodNode or FunctionNode class
* @return ASTNode[]
*/
protected function getStatements(AbstractNode $node)
{
return call_user_func_array('array_merge', array_map(function ($type) use ($node) {
return $node->findChildrenOfType($type);
}, $this->ifStatements));
}
/**
* Extracts all expression from statements array
*
* @param ASTNode[] $statements Array of if and elseif clauses
* @return ASTExpression[]
*/
protected function getExpressions(array $statements)
{
return array_map(function (ASTNode $statement) {
return $statement->getFirstChildOfType('Expression');
}, $statements);
}
/**
* Extracts all assignments from expressions array
*
* @param ASTExpression[] $expressions Array of expressions
* @return ASTAssignmentExpression[]
*/
protected function getAssignments(array $expressions)
{
$assignments = array();
/** @var ASTNode $expression */
foreach ($expressions as $expression) {
$assignments = array_merge($assignments, $expression->findChildrenOfType('AssignmentExpression'));
}
return $assignments;
}
/**
* Signals if any violations have been found in given method or function
*
* @param AbstractNode $node An instance of MethodNode or FunctionNode class
* @param ASTAssignmentExpression[] $assignments Array of assignments
*/
protected function addViolations(AbstractNode $node, array $assignments)
{
$processesViolations = array();
/** @var \PDepend\Source\AST\AbstractASTNode $assignment */
foreach ($assignments as $assignment) {
if (null === $assignment || $assignment->getImage() !== '=') {
continue;
}
$uniqueHash = $assignment->getStartColumn() . ':' . $assignment->getStartLine();
if (!in_array($uniqueHash, $processesViolations)) {
$processesViolations[] = $uniqueHash;
$this->addViolation($node, array($assignment->getStartLine(), $assignment->getStartColumn()));
}
}
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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()));
}
}
/**
* Whether the given scope is an else clause
*
* @param AbstractNode $scope
* @param ASTNode $parent
* @return bool
*/
protected function isElseScope(AbstractNode $scope, ASTNode $parent)
{
return (
count($parent->getChildren()) === 3 &&
$scope->getNode() === $parent->getChild(2)->getNode()
);
}
/**
* Whether the parent node is an if or an elseif clause
*
* @param ASTNode $parent
* @return bool
*/
protected function isIfOrElseIfStatement(ASTNode $parent)
{
return ($parent->getName() === "if" || $parent->getName() === "elseif");
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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()));
}
}
protected 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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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 ($this->isExcludedFromAnalysis($className, $exceptions)) {
continue;
}
$this->addViolation($methodCall, array($className, $node->getName()));
}
}
protected function isExcludedFromAnalysis($className, $exceptions)
{
return in_array(trim($className, " \t\n\r\0\x0B\\"), $exceptions);
}
protected function isStaticMethodCall(AbstractNode $methodCall)
{
return $methodCall->getChild(0)->getNode() instanceof ASTClassOrInterfaceReference &&
$methodCall->getChild(1)->getNode() instanceof ASTMethodPostfix &&
!$this->isCallingParent($methodCall) &&
!$this->isCallingSelf($methodCall);
}
protected function isCallingParent(AbstractNode $methodCall)
{
return $methodCall->getChild(0)->getNode() instanceof ASTParentReference;
}
protected function isCallingSelf(AbstractNode $methodCall)
{
return $methodCall->getChild(0)->getNode() instanceof ASTSelfReference;
}
/**
* Gets array of exceptions from property
*
* @return array
*/
protected 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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule\CleanCode;
use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Node\ASTNode;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;
/**
* Checks that all classes are imported
*
* This rule can be used to prevent use of fully qualified class names.
*/
class MissingImport extends AbstractRule implements MethodAware, FunctionAware
{
/**
* @var array Self reference class names.
*/
protected $selfReferences = array('self', 'static');
/**
* Checks for missing class imports and warns about it
*
* @param AbstractNode $node The node to check upon.
* @return void
*/
public function apply(AbstractNode $node)
{
foreach ($node->findChildrenOfType('AllocationExpression') as $allocationNode) {
if (!$allocationNode) {
continue;
}
$classNode = $allocationNode->getChild(0);
if ($this->isSelfReference($classNode)) {
continue;
}
$classNameLength = $classNode->getEndColumn() - $classNode->getStartColumn() + 1;
$fqcnLength = strlen($classNode->getImage());
if ($classNameLength === $fqcnLength) {
$this->addViolation($classNode, array($classNode->getBeginLine(), $classNode->getStartColumn()));
}
}
}
/**
* Check whether a given class node is a self reference
*
* @param ASTNode $classNode A class node to check.
* @return bool Whether the given class node is a self reference.
*/
protected function isSelfReference(ASTNode $classNode)
{
return in_array($classNode->getImage(), $this->selfReferences, true);
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule\CleanCode;
use PDepend\Source\AST\AbstractASTNode;
use PDepend\Source\AST\ASTLiteral;
use PDepend\Source\AST\ASTNode as PDependASTNode;
use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Node\ASTNode;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;
/**
* Duplicated Array Key Rule
*
* This rule detects duplicated array keys.
*
* @author RafaÅ Wrzeszcz <rafal.wrzeszcz@wrzasq.pl>
* @author Kamil Szymanaski <kamil.szymanski@gmail.com>
*/
class DuplicatedArrayKey extends AbstractRule implements MethodAware, FunctionAware
{
/**
* Retrieves all arrays from single node and performs comparison logic on it
*
* @param AbstractNode $node
* @return void
*/
public function apply(AbstractNode $node)
{
foreach ($node->findChildrenOfType('Array') as $arrayNode) {
/** @var ASTNode $arrayNode */
$this->checkForDuplicatedArrayKeys($arrayNode);
}
}
/**
* This method checks if a given function or method contains an array literal
* with duplicated entries for any key and emits a rule violation if so.
*
* @param ASTNode $node Array node.
* @return void
*/
protected function checkForDuplicatedArrayKeys(ASTNode $node)
{
$keys = array();
/** @var ASTArrayElement $arrayElement */
foreach ($node->getChildren() as $index => $arrayElement) {
$arrayElement = $this->normalizeKey($arrayElement, $index);
if (null === $arrayElement) {
// skip everything that can't be resolved easily
continue;
}
$key = $arrayElement->getImage();
if (isset($keys[$key])) {
$this->addViolation($node, array($key, $arrayElement->getStartLine()));
continue;
}
$keys[$key] = $arrayElement;
}
}
/**
* Changes key name to its string format.
*
* To compare keys, we have to cast them to string.
* Non-associative keys have to use index as its key,
* while boolean and nulls have to be casted respectively.
* As current logic doesn't evaluate expressions nor constants,
* statics, globals, etc. we simply skip them.
*
* @param AbstractASTNode $node Array key to evaluate.
* @param int $index Fallback in case of non-associative arrays
* @return AbstractASTNode Key name
*/
protected function normalizeKey(AbstractASTNode $node, $index)
{
$childCount = count($node->getChildren());
// Skip, if there is no array key, just an array value
if ($childCount === 1) {
return null;
}
// non-associative - key name equals to its index
if ($childCount === 0) {
$node->setImage((string)$index);
return $node;
}
$node = $node->getChild(0);
if (!($node instanceof ASTLiteral)) {
// skip expressions, method calls, globals and constants
return null;
}
$node->setImage($this->castStringFromLiteral($node));
return $node;
}
/**
* Cleans string literals and casts boolean and null values as PHP engine does
*
* @param PDependASTNode $key
* @return string
*/
protected function castStringFromLiteral(PDependASTNode $key)
{
$value = $key->getImage();
switch ($value) {
case 'false':
return '0';
case 'true':
return '1';
case 'null':
return '';
default:
return trim($value, '\'""');
}
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule\CleanCode;
use PDepend\Source\AST\ASTArray;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTPropertyPostfix;
use PDepend\Source\AST\ASTUnaryExpression;
use PDepend\Source\AST\ASTVariable;
use PDepend\Source\AST\ASTVariableDeclarator;
use PDepend\Source\AST\State;
use PHPMD\AbstractNode;
use PHPMD\Node\AbstractCallableNode;
use PHPMD\Node\ASTNode;
use PHPMD\Node\MethodNode;
use PHPMD\Rule\AbstractLocalVariable;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;
/**
* This rule collects all undefined variables within a given function or method
* that are used by any code in the analyzed source artifact.
*/
class UndefinedVariable extends AbstractLocalVariable implements FunctionAware, MethodAware
{
/**
* Found variable images within a single method or function.
*
* @var array(string)
*/
protected $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();
if ($node instanceof MethodNode) {
$this->collectProperties($this->getNode($node->getNode()->getParent()));
}
$this->collect($node);
foreach ($node->findChildrenOfType('Class') as $class) {
/** @var ASTClass $class */
$this->collectProperties($class);
foreach ($class->getMethods() as $method) {
$this->collect(new MethodNode($method));
}
}
foreach ($node->findChildrenOfType('Variable') as $variable) {
/** @var ASTVariable $variable */
if ($this->isSuperGlobal($variable) || $this->isPassedByReference($variable)) {
$this->addVariableDefinition($variable);
} elseif (!$this->checkVariableDefined($variable, $node)) {
$this->addViolation($variable, array($this->getVariableImage($variable)));
}
}
}
/**
* Collect variables defined inside a PHPMD entry node (such as MethodNode).
*
* @param AbstractNode $node
*/
protected function collect(AbstractNode $node)
{
$this->collectPropertyPostfix($node);
$this->collectClosureParameters($node);
$this->collectForeachStatements($node);
$this->collectListExpressions($node);
$this->collectAssignments($node);
$this->collectParameters($node);
$this->collectExceptionCatches($node);
$this->collectGlobalStatements($node);
}
protected function collectProperties($node)
{
if (!($node instanceof ASTClass)) {
return;
}
foreach ($node->getProperties() as $property) {
if ($property->isStatic()) {
$this->images['::'.$property->getName()] = $property;
}
}
}
/**
* Stores the given literal node in an global of found variables.
*
* @param \PHPMD\Node\AbstractNode $node
* @return void
*/
protected function collectGlobalStatements(AbstractNode $node)
{
$globalStatements = $node->findChildrenOfType('GlobalStatement');
foreach ($globalStatements as $globalStatement) {
foreach ($globalStatement->getChildren() as $variable) {
$this->addVariableDefinition($variable);
}
}
}
/**
* Stores the given literal node in an catch of found variables.
*
* @param \PHPMD\Node\AbstractCallableNode $node
* @return void
*/
protected function collectExceptionCatches(AbstractCallableNode $node)
{
$catchStatements = $node->findChildrenOfType('CatchStatement');
foreach ($catchStatements as $catchStatement) {
foreach ($catchStatement->getChildren() as $children) {
if ($children instanceof ASTVariable) {
$this->addVariableDefinition($children);
}
}
}
}
/**
* Stores the given literal node in an internal list of found variables.
*
* @param \PHPMD\Node\AbstractCallableNode $node
* @return void
*/
protected function collectListExpressions(AbstractCallableNode $node)
{
$lists = $node->findChildrenOfType('ListExpression');
foreach ($lists as $listExpression) {
foreach ($listExpression->getChildren() as $variable) {
$this->addVariableDefinition($variable);
}
}
}
/**
* Stores the given literal node in an internal foreach of found variables.
*
* @param \PHPMD\Node\AbstractCallableNode $node
* @return void
*/
protected function collectForeachStatements(AbstractCallableNode $node)
{
$foreachStatements = $node->findChildrenOfType('ForeachStatement');
foreach ($foreachStatements as $foreachStatement) {
foreach ($foreachStatement->getChildren() as $children) {
if ($children instanceof ASTVariable) {
$this->addVariableDefinition($children);
} elseif ($children instanceof ASTUnaryExpression) {
foreach ($children->getChildren() as $refChildren) {
if ($refChildren instanceof ASTVariable) {
$this->addVariableDefinition($refChildren);
}
}
}
}
}
}
/**
* Stores the given literal node in an internal closure of found variables.
*
* @param \PHPMD\Node\AbstractCallableNode $node
* @return void
*/
protected function collectClosureParameters(AbstractCallableNode $node)
{
$closures = $node->findChildrenOfType('Closure');
foreach ($closures as $closure) {
$this->collectParameters($closure);
}
}
/**
* Check if the given variable was defined in the current context before usage.
*
* @param \PHPMD\Node\ASTNode $variable
* @param \PHPMD\Node\AbstractCallableNode $parentNode
* @return bool
*/
protected function checkVariableDefined(ASTNode $variable, AbstractCallableNode $parentNode)
{
$image = $this->getVariableImage($variable);
return isset($this->images[$image]) || $this->isNameAllowedInContext($parentNode, $variable);
}
/**
* Collect parameter names of method/function.
*
* @param \PHPMD\Node\AbstractNode $node
* @return void
*/
protected function collectParameters(AbstractNode $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) {
$this->addVariableDefinition($declarator);
}
}
/**
* Collect assignments of variables.
*
* @param \PHPMD\Node\AbstractCallableNode $node
* @return void
*/
protected function collectAssignments(AbstractCallableNode $node)
{
foreach ($node->findChildrenOfType('AssignmentExpression') as $assignment) {
$variable = $assignment->getChild(0);
if ($variable->getNode() instanceof ASTArray) {
foreach ($variable->findChildrenOfType('Variable') as $unpackedVariable) {
$this->addVariableDefinition($unpackedVariable);
}
continue;
}
$this->addVariableDefinition($variable);
}
}
/**
* Collect postfix property.
*
* @param \PHPMD\Node\AbstractNode $node
* @return void
*/
protected function collectPropertyPostfix(AbstractNode $node)
{
$properties = $node->findChildrenOfType('PropertyPostfix');
foreach ($properties as $property) {
foreach ($property->getChildren() as $children) {
if ($children instanceof ASTVariable) {
$this->addVariableDefinition($children);
}
}
}
}
/**
* Add the variable to images.
*
* @param ASTVariable|ASTPropertyPostfix|ASTVariableDeclarator $variable
* @return void
*/
protected function addVariableDefinition($variable)
{
$image = $this->getVariableImage($variable);
if (!isset($this->images[$image])) {
$this->images[$image] = $variable;
}
}
/**
* Checks if a short name is acceptable in the current context.
*
* @param \PHPMD\Node\AbstractCallableNode $node
* @param \PHPMD\Node\ASTNode $variable
*
* @return boolean
*/
protected function isNameAllowedInContext(AbstractCallableNode $node, ASTNode $variable)
{
return (
$node instanceof MethodNode &&
$variable->getImage() === '$this' &&
($node->getModifiers() & State::IS_STATIC) === 0
);
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule\CleanCode;
use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;
/**
* Error Control Operators Rule
*
* This rule detects usage of error control operator (@).
*
* @author Kamil Szymanaski <kamil.szymanski@gmail.com>
* @link http://php.net/manual/en/language.operators.errorcontrol.php
*/
class ErrorControlOperator extends AbstractRule implements MethodAware, FunctionAware
{
/**
* Loops trough all class or function nodes and looks for '@' sign.
*
* @param AbstractNode $node
* @return void
*/
public function apply(AbstractNode $node)
{
foreach ($node->findChildrenOfType('UnaryExpression') as $unaryExpression) {
if ($unaryExpression->getImage() === '@') {
$this->addViolation($node, array($unaryExpression->getBeginLine()));
}
}
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
class UnusedLocalVariable extends AbstractLocalVariable implements FunctionAware, MethodAware
{
/**
* Found variable images within a single method or function.
*
* @var array(string)
*/
protected $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();
/** @var $node AbstractCallableNode */
$this->collectVariables($node);
$this->removeParameters($node);
foreach ($this->images as $nodes) {
if (!$this->containsUsages($nodes)) {
$this->doCheckNodeImage($nodes[0]);
}
}
}
/**
* Return true if one of the passed nodes contains variables usages.
*
* @param array $nodes
*
* @return bool
*/
protected function containsUsages(array $nodes)
{
if (count($nodes) === 1) {
return false;
}
foreach ($nodes as $node) {
$parent = $node->getParent();
if (!$parent->isInstanceOf('AssignmentExpression')) {
return true;
}
if (in_array($this->getNode($node), array_slice($parent->getChildren(), 1))) {
return true;
}
}
return false;
}
/**
* 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
*/
protected 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
*/
protected function collectVariables(AbstractCallableNode $node)
{
foreach ($node->findChildrenOfType('Variable') as $variable) {
/** @var $variable ASTNode */
if ($this->isLocal($variable)) {
$this->collectVariable($variable);
}
}
foreach ($node->findChildrenOfType('CompoundVariable') as $variable) {
$this->collectCompoundVariableInString($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) {
/** @var $literal ASTNode */
$this->collectLiteral($literal);
}
}
}
}
/**
* Stores the given compound variable node in an internal list of found variables.
*
* @param \PHPMD\Node\ASTNode $node
* @return void
*/
protected function collectCompoundVariableInString(ASTNode $node)
{
$parentNode = $node->getParent()->getNode();
$candidateParentNodes = $node->getParentsOfType('PDepend\Source\AST\ASTString');
if (in_array($parentNode, $candidateParentNodes)) {
$variablePrefix = $node->getImage();
foreach ($node->findChildrenOfType('Expression') as $child) {
$variableName = $child->getImage();
$variableImage = $variablePrefix . $variableName;
$this->storeImage($variableImage, $node);
}
}
}
/**
* Stores the given variable node in an internal list of found variables.
*
* @param \PHPMD\Node\ASTNode $node
* @return void
*/
protected function collectVariable(ASTNode $node)
{
$imageName = $node->getImage();
$this->storeImage($imageName, $node);
}
/**
* Safely add node to $this->images.
*
* @param string $imageName the name to store the node as
* @param \PHPMD\Node\ASTNode $node the node being stored
* @return void
*/
protected function storeImage($imageName, ASTNode $node)
{
if (!isset($this->images[$imageName])) {
$this->images[$imageName] = array();
}
$this->images[$imageName][] = $node;
}
/**
* Stores the given literal node in an internal list of found variables.
*
* @param \PHPMD\Node\ASTNode $node
* @return void
*/
protected 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 ASTNode $node
* @return void
*/
protected function doCheckNodeImage(ASTNode $node)
{
if ($this->isNameAllowedInContext($node)) {
return;
}
if ($this->isUnusedForeachVariableAllowed($node)) {
return;
}
if (in_array(substr($node->getImage(), 1), $this->getExceptionsList())) {
return;
}
$parent = $node->getParent();
// ASTFormalParameter should be handled by the UnusedFormalParameter rule
if ($parent && $parent->isInstanceOf('FormalParameter')) {
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
*/
protected 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.
*/
protected 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
*/
protected function isChildOf(AbstractNode $node, $type)
{
$parent = $node->getParent();
return $parent->isInstanceOf($type);
}
/**
* Gets array of exceptions from property
*
* @return array
*/
protected function getExceptionsList()
{
return explode(',', $this->getStringProperty('exceptions', ''));
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule;
/**
* This interface is used to mark a rule implementation as function aware.
*/
interface FunctionAware
{
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule;
/**
* This interface marks a rule implementation as method aware,
*/
interface MethodAware
{
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule;
/**
* This interface marks a rule implementation as interface aware,
*/
interface InterfaceAware
{
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule\Naming;
use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;
use PHPMD\Rule\InterfaceAware;
use PHPMD\Utility\Strings;
/**
* This rule will detect classes and interfaces with names that are too short.
*/
class ShortClassName extends AbstractRule implements ClassAware, InterfaceAware
{
/**
* Temporary cache of configured exceptions. Have name as key
*
* @var array<string, int>|null
*/
protected $exceptions;
/**
* Check if a class or interface name is below the minimum configured length and emit a rule violation
*
* @param \PHPMD\AbstractNode $node
* @return void
*/
public function apply(AbstractNode $node)
{
$threshold = $this->getIntProperty('minimum');
$classOrInterfaceName = $node->getName();
if (strlen($classOrInterfaceName) >= $threshold) {
return;
}
$exceptions = $this->getExceptionsList();
if (isset($exceptions[$classOrInterfaceName])) {
return;
}
$this->addViolation($node, array($classOrInterfaceName, $threshold));
}
/**
* Gets array of exceptions from property
*
* @return array<string, int>
*/
protected function getExceptionsList()
{
if ($this->exceptions === null) {
$this->exceptions = array_flip(
Strings::splitToList($this->getStringProperty('exceptions', ''), ',')
);
}
return $this->exceptions;
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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)
{
/** @var $node MethodNode */
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
*/
protected 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
*/
protected 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
*/
protected 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
*/
protected 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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
class ShortVariable extends AbstractRule implements ClassAware, MethodAware, FunctionAware
{
/**
* Temporary map holding variables that were already processed in the
* current context.
*
* @var array(string=>boolean)
*/
protected $processedVariables = array();
/**
* Extracts all variable and variable declarator nodes from the given node
*
* 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') {
$this->applyClass($node);
return;
}
$this->applyNonClass($node);
}
/**
* Extracts all variable and variable declarator nodes from the given class node
*
* Checks the variable name length against the configured minimum
* length.
*
* @param AbstractNode $node
* @return void
*/
protected function applyClass(AbstractNode $node)
{
$fields = $node->findChildrenOfType('FieldDeclaration');
foreach ($fields as $field) {
$declarators = $field->findChildrenOfType('VariableDeclarator');
foreach ($declarators as $declarator) {
$this->checkNodeImage($declarator);
}
}
$this->resetProcessed();
}
/**
* Extracts all variable and variable declarator nodes from the given non-class node
*
* Checks the variable name length against the configured minimum
* length.
*
* @param AbstractNode $node
* @return void
*/
protected function applyNonClass(AbstractNode $node)
{
$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
*/
protected 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
*/
protected function isNameAllowedInContext(AbstractNode $node)
{
if ($this->isChildOf($node, 'ForeachStatement')) {
return $this->isInitializedInLoop($node);
}
return $this->isChildOf($node, 'CatchStatement')
|| $this->isChildOf($node, 'ForInit')
|| $this->isChildOf($node, 'MemberPrimaryPrefix');
}
/**
* Checks if a short name is initialized within a foreach loop statement
*
* @param \PHPMD\AbstractNode $node
* @return boolean
*/
protected function isInitializedInLoop(AbstractNode $node)
{
if (!$this->getBooleanProperty('allow-short-variables-in-loop', true)) {
return false;
}
$exceptionVariables = array();
$parentForeaches = $this->getParentsOfType($node, 'ForeachStatement');
foreach ($parentForeaches as $foreach) {
foreach ($foreach->getChildren() as $foreachChild) {
$exceptionVariables[] = $foreachChild->getImage();
}
}
$exceptionVariables = array_filter(array_unique($exceptionVariables));
return in_array($node->getImage(), $exceptionVariables, true);
}
/**
* Returns an array of parent nodes of the specified type
*
* @param \PHPMD\AbstractNode $node
* @return array
*/
protected function getParentsOfType(AbstractNode $node, $type)
{
$parents = array();
$parent = $node->getParent();
while (is_object($parent)) {
if ($parent->isInstanceOf($type)) {
$parents[] = $parent;
}
$parent = $parent->getParent();
}
return $parents;
}
/**
* 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
*/
protected 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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule\Naming;
use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;
use PHPMD\Utility\Strings;
/**
* This rule class will detect variables, parameters and properties with really
* long names.
*/
class LongVariable extends AbstractRule implements ClassAware, MethodAware, FunctionAware
{
/**
* Temporary cache of configured suffixes to subtract
*
* @var string[]|null
*/
protected $subtractSuffixes;
/**
* Temporary map holding variables that were already processed in the
* current context.
*
* @var array(string=>boolean)
*/
protected $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) {
$declarators = $field->findChildrenOfType('VariableDeclarator');
foreach ($declarators as $declarator) {
$this->checkNodeImage($declarator);
}
}
$this->resetProcessed();
return;
}
$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
* @SuppressWarnings(PHPMD.LongVariable)
*/
protected function checkMaximumLength(AbstractNode $node)
{
$threshold = $this->getIntProperty('maximum');
$variableName = $node->getImage();
$lengthWithoutDollarSign = Strings::lengthWithoutSuffixes($variableName, $this->getSubtractSuffixList()) - 1;
if ($lengthWithoutDollarSign <= $threshold) {
return;
}
if ($this->isNameAllowedInContext($node)) {
return;
}
$this->addViolation($node, array($variableName, $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
*/
protected 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
*/
protected 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()]);
}
/**
* Gets array of suffixes from property
*
* @return string[]
*/
protected function getSubtractSuffixList()
{
if ($this->subtractSuffixes === null) {
$this->subtractSuffixes = Strings::splitToList($this->getStringProperty('subtract-suffixes', ''), ',');
}
return $this->subtractSuffixes;
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule\Naming;
use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;
use PHPMD\Rule\InterfaceAware;
use PHPMD\Utility\Strings;
/**
* This rule checks if an interface or class name exceeds the configured length excluding certain configured suffixes
*/
class LongClassName extends AbstractRule implements ClassAware, InterfaceAware
{
/**
* Temporary cache of configured suffixes to subtract
*
* @var string[]|null
*/
protected $subtractSuffixes;
/**
* Check if a class name exceeds the configured maximum length and emit a rule violation
*
* @param \PHPMD\AbstractNode $node
* @return void
*/
public function apply(AbstractNode $node)
{
$threshold = $this->getIntProperty('maximum');
$classOrInterfaceName = $node->getName();
if (Strings::lengthWithoutSuffixes($classOrInterfaceName, $this->getSubtractSuffixList()) <= $threshold) {
return;
}
$this->addViolation($node, array($classOrInterfaceName, $threshold));
}
/**
* Gets array of suffixes from property
*
* @return string[]
*/
protected function getSubtractSuffixList()
{
if ($this->subtractSuffixes === null) {
$this->subtractSuffixes = Strings::splitToList(
$this->getStringProperty('subtract-suffixes', ''),
','
);
}
return $this->subtractSuffixes;
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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
*/
protected 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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule;
use PDepend\Source\AST\ASTMethodPostfix;
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.
*/
class UnusedPrivateMethod extends AbstractRule implements ClassAware
{
/**
* This method checks that all private class methods are at least accessed
* by one method.
*
* @param AbstractNode $class
* @return void
*/
public function apply(AbstractNode $class)
{
/** @var ClassNode $node */
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 ClassNode $class
* @return ASTMethodPostfix[]
*/
protected function collectUnusedPrivateMethods(ClassNode $class)
{
$methods = $this->collectPrivateMethods($class);
return $this->removeUsedMethods($class, $methods);
}
/**
* Collects all private methods declared in the given class node.
*
* @param ClassNode $class
* @return AbstractNode[]
*/
protected 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 ClassNode $class
* @param MethodNode $method
* @return boolean
*/
protected 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 ClassNode $class
* @param MethodNode[] $methods
* @return ASTMethodPostfix[]
*/
protected function removeUsedMethods(ClassNode $class, array $methods)
{
foreach ($class->findChildrenOfType('MethodPostfix') as $postfix) {
/** @var $postfix ASTNode */
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 ClassNode $class
* @param ASTNode $postfix
* @return boolean
*/
protected 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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule;
use PHPMD\AbstractNode;
use PHPMD\Node\ASTNode;
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.
*/
class UnusedFormalParameter extends AbstractLocalVariable implements FunctionAware, MethodAware
{
/**
* Collected ast nodes.
*
* @var \PHPMD\Node\ASTNode[]
*/
protected $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
*/
protected 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
*/
protected function isInheritedSignature(AbstractNode $node)
{
if ($node instanceof MethodNode) {
return preg_match('/@inheritdoc/i', $node->getDocComment()) === 1;
}
return false;
}
/**
* Returns <b>true</b> when the given node is a magic method signature
*
* @param AbstractNode $node
* @return boolean
*/
protected function isMagicMethod(AbstractNode $node)
{
if (!($node instanceof MethodNode)) {
return false;
}
static $magicMethodRegExp = null;
if ($magicMethodRegExp === null) {
$magicMethodRegExp = '/__(?:' . implode("|", array(
'call',
'callStatic',
'get',
'set',
'isset',
'unset',
'set_state',
)) . ')/i';
}
return preg_match($magicMethodRegExp, $node->getName()) === 1;
}
/**
* 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
*/
protected 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
*/
protected function collectParameters(AbstractNode $node)
{
// First collect the formal parameters containers
foreach ($node->findChildrenOfType('FormalParameters') as $parameters) {
// 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
*/
protected function removeUsedParameters(AbstractNode $node)
{
$this->removeRegularVariables($node);
$this->removeCompoundVariables($node);
$this->removeVariablesUsedByFuncGetArgs($node);
}
/**
* Removes all the regular variables from a given node
*
* @param \PHPMD\AbstractNode $node The node to remove the regular variables from.
* @return void
*/
protected function removeRegularVariables(AbstractNode $node)
{
$variables = $node->findChildrenOfType('Variable');
foreach ($variables as $variable) {
/** @var $variable ASTNode */
if ($this->isRegularVariable($variable)) {
unset($this->nodes[$variable->getImage()]);
}
}
}
/**
* Removes all the compound variables from a given node
*
* Such as
*
* <code>
* // ------
* Foo::${BAR}();
* // ------
*
* // ------
* Foo::$${BAR}();
* // ------
* </code>
*
* @param \PHPMD\AbstractNode $node The node to remove the compound variables from.
* @return void
*/
protected function removeCompoundVariables(AbstractNode $node)
{
$compoundVariables = $node->findChildrenOfType('CompoundVariable');
foreach ($compoundVariables as $compoundVariable) {
$variablePrefix = $compoundVariable->getImage();
foreach ($compoundVariable->findChildrenOfType('Expression') as $child) {
$variableImage = $variablePrefix . $child->getImage();
if (isset($this->nodes[$variableImage])) {
unset($this->nodes[$variableImage]);
}
}
}
}
/**
* Removes all the variables from a given node, if func_get_args() is called within
*
* If the given method calls func_get_args() then all parameters are automatically referenced.
*
* @param \PHPMD\AbstractNode $node The node to remove the referneced variables from.
* @return void
*/
protected function removeVariablesUsedByFuncGetArgs(AbstractNode $node)
{
$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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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.
*/
class UnusedPrivateField extends AbstractRule implements ClassAware
{
/**
* Collected private fields/variable declarators in the currently processed
* class.
*
* @var \PHPMD\Node\ASTNode[]
*/
protected $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)
{
/** @var ClassNode $field */
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[]
*/
protected 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
*/
protected function collectPrivateFields(ClassNode $class)
{
foreach ($class->findChildrenOfType('FieldDeclaration') as $declaration) {
/** @var ASTNode $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
*/
protected 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
*/
protected function removeUsedFields(ClassNode $class)
{
foreach ($class->findChildrenOfType('PropertyPostfix') as $postfix) {
/** @var $postfix ASTNode */
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
*/
protected 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 = $this->getOwner($postfix);
return (
$owner->isInstanceOf('SelfReference') ||
$owner->isInstanceOf('StaticReference') ||
strcasecmp($owner->getImage(), '$this') === 0 ||
strcasecmp($owner->getImage(), $class->getImage()) === 0
);
}
/**
* Looks for owner of the given variable.
*
* @param \PHPMD\Node\ASTNode $postfix
* @return \PHPMD\Node\ASTNode
*/
protected function getOwner(ASTNode $postfix)
{
$owner = $postfix->getParent()->getChild(0);
if ($owner->isInstanceOf('PropertyPostfix')) {
$owner = $owner->getParent()->getParent()->getChild(0);
}
if ($owner->getParent()->isInstanceOf('ArrayIndexExpression')) {
$owner = $owner->getParent()->getParent()->getChild(0);
}
return $owner;
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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>
* @since 1.1.0
*/
class CamelCaseVariableName extends AbstractRule implements MethodAware, FunctionAware
{
/**
* @var array
*/
protected $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) {
if (!$this->isValid($variable)) {
$this->addViolation(
$node,
array(
$variable->getImage(),
)
);
}
}
}
protected function isValid($variable)
{
$image = $variable->getImage();
if (in_array($image, $this->exceptions)) {
return true;
}
if ($this->getBooleanProperty('allow-underscore')) {
if (preg_match('/^\$[_]?[a-z][a-zA-Z0-9]*$/', $image)) {
return true;
}
}
if (preg_match('/^\$[a-z][a-zA-Z0-9]*$/', $image)) {
return true;
}
if ($variable->getParent()->isInstanceOf('PropertyPostfix')) {
return true;
}
return false;
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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>
* @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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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>
* @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',
'__serialize',
'__unserialize',
);
/**
* 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,
)
);
}
}
}
protected 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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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>
* @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 (!$this->isValid($parameter->getName())) {
$this->addViolation(
$node,
array(
$parameter->getName(),
)
);
}
}
}
protected function isValid($parameterName)
{
if ($this->getBooleanProperty('allow-underscore')) {
return preg_match('/^\$[_]?[a-z][a-zA-Z0-9]*$/', $parameterName);
}
return preg_match('/^\$[a-z][a-zA-Z0-9]*$/', $parameterName);
}
}
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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>
* @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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
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>
* @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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule;
use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
/**
* This rule checks a given method or function against the configured cyclomatic
* complexity threshold.
*/
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) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/
namespace PHPMD\Rule;
/**
* This interface is used to mark a rule implementation as class aware.
*/
interface ClassAware
{
}
<?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="https://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="https://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" />
<property name="exceptions" description="Comma-separated list of exceptions" value=""/>
</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="https://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="https://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"?>
<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="https://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 clauses are basically not necessary and you can simplify the code by not using them."
class="PHPMD\Rule\CleanCode\ElseExpression"
externalInfoUrl="https://phpmd.org/rules/cleancode.html#elseexpression">
<description>
<![CDATA[
An if expression with an else branch is basically not necessary. You can rewrite the
conditions in a way that the else clause is not necessary and the code becomes simpler
to read. To achieve this, use early return statements, though 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/>
<example>
<![CDATA[
class Foo
{
public function bar($flag)
{
if ($flag) {
// one branch
} else {
// another branch
}
}
}
]]>
</example>
</rule>
<rule name="IfStatementAssignment"
since="2.7.0"
message="Avoid assigning values to variables in if clauses and the like (line '{0}', column '{1}')."
class="PHPMD\Rule\CleanCode\IfStatementAssignment"
externalInfoUrl="http://phpmd.org/rules/cleancode.html#ifstatementassignment">
<description>
<![CDATA[
Assignments in if clauses and the like are considered a code smell.
Assignments in PHP return the right operand as their result.
In many cases, this is an expected behavior, but can lead
to many difficult to spot bugs, especially when the right
operand could result in zero, null or an empty string and the like.
]]>
</description>
<priority>1</priority>
<properties></properties>
<example>
<![CDATA[
class Foo
{
public function bar($flag)
{
if ($foo = 'bar') { // possible typo
// ...
}
if ($baz = 0) { // always false
// ...
}
}
}
]]>
</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="https://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>
<rule name="DuplicatedArrayKey"
message="Duplicated array key {0}, first declared at line {1}."
class="PHPMD\Rule\CleanCode\DuplicatedArrayKey"
externalInfoUrl="http://phpmd.org/rules/cleancode.html#duplicatedarraykey">
<description>
<![CDATA[
Defining another value for the same key in an array literal overrides the previous key/value,
which makes it effectively an unused code. If it's known from the beginning that the key
will have different value, there is usually no point in defining first one.
]]>
</description>
<priority>2</priority>
<example>
<![CDATA[
function createArray() {
return [
'non-associative 0element', // not applied
0 => 'associative 0-element', // applied
false => 'associative 0-element', // applied
'foo' => 'bar', // not applied
"foo" => 'baz', // applied
];
}
]]>
</example>
</rule>
<rule name="ErrorControlOperator"
message="Remove error control operator '@' on line {0}."
class="PHPMD\Rule\CleanCode\ErrorControlOperator"
externalInfoUrl="http://phpmd.org/rules/cleancode.html#errorcontroloperator">
<description>
<![CDATA[
Error suppression should be avoided if possible as it doesn't just suppress the error, that
you are trying to stop, but will also suppress errors that you didn't predict would ever occur.
Consider changing error_reporting() level and/or setting up your own error handler.
]]>
</description>
<priority>1</priority>
<example>
<![CDATA[
function foo($filePath) {
$file = @fopen($filPath); // hides exceptions
$key = @$array[$notExistingKey]; // assigns null to $key
}
]]>
</example>
</rule>
<rule name="MissingImport"
since="2.7.0"
message="Missing class import via use statement (line '{0}', column '{1}')."
class="PHPMD\Rule\CleanCode\MissingImport"
externalInfoUrl="http://phpmd.org/rules/cleancode.html#MissingImport">
<description>
<![CDATA[
Importing all external classes in a file through use statements makes them clearly visible.
]]>
</description>
<priority>1</priority>
<example>
<![CDATA[
function make() {
return new \stdClass();
}
]]>
</example>
</rule>
<rule name="UndefinedVariable"
since="2.8.0"
message="Avoid using undefined variables such as '{0}' which will lead to PHP notices."
class="PHPMD\Rule\CleanCode\UndefinedVariable"
externalInfoUrl="">
<description>
Detects when a variable is used that has not been defined before.
</description>
<priority>3</priority>
<example>
<![CDATA[
class Foo
{
private function bar()
{
// $message is undefined
echo $message;
}
}
]]>
</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="https://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="https://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="https://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="https://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="https://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="https://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="maximum" 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="https://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." />
<property name="ignore-namespaces" value="false" description="Ignore namespaces when looking for dev. fragments" />
</properties>
<example>
<![CDATA[
class SuspectCode {
public function doSomething(array $items)
{
foreach ($items as $i => $item) {
// …
if ('qafoo' == $item) var_dump($i);
// …
}
}
}
]]>
</example>
</rule>
<rule name="EmptyCatchBlock"
since="2.7.0"
message="Avoid using empty try-catch blocks in {0}."
class="PHPMD\Rule\Design\EmptyCatchBlock"
externalInfoUrl="https://phpmd.org/rules/design.html#emptycatchblock">
<description>
<![CDATA[
Usually empty try-catch is a bad idea because you are silently swallowing an error condition
and then continuing execution. Occasionally this may be the right thing to do, but often
it's a sign that a developer saw an exception, didn't know what to do about it,
and so used an empty catch to silence the problem.
]]>
</description>
<priority>2</priority>
<properties />
<example>
<![CDATA[
class Foo {
public function bar()
{
try {
// ...
} catch (Exception $e) {} // empty catch block
}
}
]]>
</example>
</rule>
<rule name="CountInLoopExpression"
since="2.7.0"
message="Avoid using {0}() function in {1} loops."
class="PHPMD\Rule\Design\CountInLoopExpression"
externalInfoUrl="https://phpmd.org/rules/design.html#countinloopexpression">
<description>
<![CDATA[
Using count/sizeof in loops expressions is considered bad practice and is a potential source of
many bugs, especially when the loop manipulates an array, as count happens on each iteration.
]]>
</description>
<priority>2</priority>
<properties />
<example>
<![CDATA[
class Foo {
public function bar()
{
$array = array();
for ($i = 0; count($array); $i++) {
// ...
}
}
}
]]>
</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="https://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="https://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="https://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="https://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="https://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="https://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="https://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="https://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|is|has|with))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="https://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|is|has|with))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="https://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>
<?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="LongClassName"
since="2.9"
message="Avoid excessively long class names like {0}. Keep class name length under {1}."
class="PHPMD\Rule\Naming\LongClassName"
externalInfoUrl="https://phpmd.org/rules/naming.html#longclassname">
<description>
Detects when classes or interfaces are declared with excessively long names.
</description>
<priority>3</priority>
<properties>
<property name="maximum" description="The class name length reporting threshold" value="40"/>
<property name="subtract-suffixes" description="Comma-separated list of suffixes that will not count in the length of the class name. Only the first matching suffix will be subtracted." value=""/>
</properties>
<example>
<![CDATA[
class ATooLongClassNameThatHintsAtADesignProblem {
}
interface ATooLongInterfaceNameThatHintsAtADesignProblem {
}
]]>
</example>
</rule>
<rule name="ShortClassName"
since="2.9"
message="Avoid classes with short names like {0}. Configured minimum length is {1}."
class="PHPMD\Rule\Naming\ShortClassName"
externalInfoUrl="https://phpmd.org/rules/naming.html#shortclassname">
<description>
Detects when classes or interfaces have a very short name.
</description>
<priority>3</priority>
<properties>
<property name="minimum" description="The class name length reporting threshold" value="3"/>
<property name="exceptions" description="Comma-separated list of exceptions. Example: Log,URL,FTP" value=""/>
</properties>
<example>
<![CDATA[
class Fo {
}
interface Fo {
}
]]>
</example>
</rule>
<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="https://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="https://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"/>
<property name="subtract-suffixes" description="Comma-separated list of suffixes that will not count in the length of the variable name. Only the first matching suffix will be subtracted." value=""/>
</properties>
<example>
<![CDATA[
class Something {
protected $reallyLongIntName = -3; // VIOLATION - Field
public static function main( array $interestingArgumentsList[] ) { // 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="https://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="https://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="https://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="https://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"?>
<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>
<property name="allow-underscore"
description="Allow an optional, single underscore at the beginning."
value="false" />
</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>
<property name="allow-underscore"
description="Allow an optional, single underscore at the beginning."
value="false" />
</properties>
<example>
<![CDATA[
class ClassName {
public function doSomething() {
$data_module = new DataModule();
}
}
]]>
</example>
</rule>
</ruleset>
Ÿ6sûCB¾2G Ø)áäJcóÒtÀv¦ ÜÁZÅ ä¶&Óq‰óÅÐÛª³sPÉ¡°Å~~ïif¸%VGBMB