| <?php |
| /** |
| * PHPUnit |
| * |
| * Copyright (c) 2002-2008, Sebastian Bergmann <sb@sebastian-bergmann.de>. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * * Neither the name of Sebastian Bergmann nor the names of his |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
| * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
| * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
| * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| * |
| * @category Testing |
| * @package PHPUnit |
| * @author Sebastian Bergmann <sb@sebastian-bergmann.de> |
| * @copyright 2002-2008 Sebastian Bergmann <sb@sebastian-bergmann.de> |
| * @license http://www.opensource.org/licenses/bsd-license.php BSD License |
| * @version SVN: $Id: Class.php 1985 2007-12-26 18:11:55Z sb $ |
| * @link http://www.phpunit.de/ |
| * @since File available since Release 3.2.0 |
| */ |
| |
| require_once 'PHPUnit/Util/Class.php'; |
| require_once 'PHPUnit/Util/Metrics.php'; |
| require_once 'PHPUnit/Util/Filter.php'; |
| |
| PHPUnit_Util_Filter::addFileToFilter(__FILE__, 'PHPUNIT'); |
| |
| /** |
| * Class-Level Metrics. |
| * |
| * @category Testing |
| * @package PHPUnit |
| * @author Sebastian Bergmann <sb@sebastian-bergmann.de> |
| * @copyright 2002-2008 Sebastian Bergmann <sb@sebastian-bergmann.de> |
| * @license http://www.opensource.org/licenses/bsd-license.php BSD License |
| * @version Release: 3.2.9 |
| * @link http://www.phpunit.de/ |
| * @since Class available since Release 3.2.0 |
| */ |
| class PHPUnit_Util_Metrics_Class extends PHPUnit_Util_Metrics { |
| protected $aif = 0; |
| protected $ahf = 0; |
| protected $ca = 0; |
| protected $ce = 0; |
| protected $coverage = 0; |
| protected $dit = 0; |
| protected $i = 0; |
| protected $impl = 0; |
| protected $loc = 0; |
| protected $locExecutable = 0; |
| protected $locExecuted = 0; |
| protected $mif = 0; |
| protected $mhf = 0; |
| protected $noc = 0; |
| protected $pf = 0; |
| protected $vars = 0; |
| protected $varsNp = 0; |
| protected $varsI = 0; |
| protected $wmc = 0; |
| protected $wmcNp = 0; |
| protected $wmcI = 0; |
| |
| protected $project; |
| protected $package = ''; |
| protected $class; |
| protected $methods = array(); |
| protected $inheritedMethods = array(); |
| protected $dependencies = array(); |
| protected $publicMethods = 0; |
| |
| protected static $cache = array(); |
| protected static $nocCache = array(); |
| |
| /** |
| * Constructor. |
| * |
| * @param ReflectionClass $class |
| * @param array $codeCoverage |
| * @access protected |
| */ |
| protected function __construct(ReflectionClass $class, &$codeCoverage = array()) { |
| $this->class = $class; |
| |
| $className = $class->getName(); |
| |
| $packageInformation = PHPUnit_Util_Class::getPackageInformation($className); |
| |
| if (! empty($packageInformation['fullPackage'])) { |
| $this->package = $packageInformation['fullPackage']; |
| } |
| |
| $this->setCoverage($codeCoverage); |
| |
| $this->dit = count(PHPUnit_Util_Class::getHierarchy($class->getName())) - 1; |
| $this->impl = count($class->getInterfaces()); |
| |
| foreach ($this->class->getMethods() as $method) { |
| if ($method->getDeclaringClass()->getName() == $className) { |
| $this->methods[$method->getName()] = PHPUnit_Util_Metrics_Function::factory($method, $codeCoverage); |
| } else { |
| $this->inheritedMethods[$method->getName()] = PHPUnit_Util_Metrics_Function::factory($method, $codeCoverage); |
| } |
| } |
| |
| $this->calculateAttributeMetrics(); |
| $this->calculateMethodMetrics(); |
| $this->calculateNumberOfChildren(); |
| $this->calculatePolymorphismFactor(); |
| $this->calculateDependencies(); |
| } |
| |
| /** |
| * Factory. |
| * |
| * @param ReflectionClass $class |
| * @param array $codeCoverage |
| * @return PHPUnit_Util_Metrics_Class |
| * @access public |
| * @static |
| */ |
| public static function factory(ReflectionClass $class, &$codeCoverage = array()) { |
| $className = $class->getName(); |
| |
| if (! isset(self::$cache[$className])) { |
| self::$cache[$className] = new PHPUnit_Util_Metrics_Class($class, $codeCoverage); |
| } |
| |
| else if (! empty($codeCoverage) && self::$cache[$className]->getCoverage() == 0) { |
| self::$cache[$className]->setCoverage($codeCoverage); |
| } |
| |
| return self::$cache[$className]; |
| } |
| |
| /** |
| * @param array $codeCoverage |
| * @access public |
| */ |
| public function setCoverage(array &$codeCoverage) { |
| if (! empty($codeCoverage)) { |
| $this->calculateCodeCoverage($codeCoverage); |
| |
| foreach ($this->methods as $method) { |
| $method->setCoverage($codeCoverage); |
| } |
| } |
| } |
| |
| /** |
| * @param PHPUnit_Util_Metrics_Project $project |
| * @access public |
| */ |
| public function setProject(PHPUnit_Util_Metrics_Project $project) { |
| $this->project = $project; |
| |
| $this->ca = 0; |
| $this->ce = 0; |
| $this->i = 0; |
| } |
| |
| /** |
| * Returns the class. |
| * |
| * @return ReflectionClass |
| * @access public |
| */ |
| public function getClass() { |
| return $this->class; |
| } |
| |
| /** |
| * Returns the package of this class. |
| * |
| * @return string |
| * @access public |
| */ |
| public function getPackage() { |
| return $this->package; |
| } |
| |
| /** |
| * Returns the methods of this class. |
| * |
| * @return array |
| * @access public |
| */ |
| public function getMethods() { |
| return $this->methods; |
| } |
| |
| /** |
| * Returns the names of the classes this class depends on. |
| * |
| * @return array |
| * @access public |
| */ |
| public function getDependencies() { |
| return $this->dependencies; |
| } |
| |
| /** |
| * Lines of Code (LOC). |
| * |
| * @return int |
| * @access public |
| */ |
| public function getLoc() { |
| return $this->loc; |
| } |
| |
| /** |
| * Executable Lines of Code (ELOC). |
| * |
| * @return int |
| * @access public |
| */ |
| public function getLocExecutable() { |
| return $this->locExecutable; |
| } |
| |
| /** |
| * Executed Lines of Code. |
| * |
| * @return int |
| * @access public |
| */ |
| public function getLocExecuted() { |
| return $this->locExecuted; |
| } |
| |
| /** |
| * Returns the Number of Public Methods of the class. |
| * |
| * @return integer |
| * @access public |
| */ |
| public function getPublicMethods() { |
| return $this->publicMethods; |
| } |
| |
| /** |
| * Returns the Attribute Inheritance Factor (AIF) for the class. |
| * |
| * @return integer |
| * @access public |
| * @see http://www.aivosto.com/project/help/pm-oo-mood.html |
| */ |
| public function getAIF() { |
| return $this->aif; |
| } |
| |
| /** |
| * Returns the Attribute Hiding Factor (AHF) for the class. |
| * |
| * @return integer |
| * @access public |
| * @see http://www.aivosto.com/project/help/pm-oo-mood.html |
| */ |
| public function getAHF() { |
| return $this->ahf; |
| } |
| |
| /** |
| * Returns the Afferent Couplings (Ca) for the class. |
| * |
| * The number of other classes that depend upon a class is an indicator of |
| * the class' responsibility. |
| * |
| * @return integer |
| * @access public |
| */ |
| public function getCa() { |
| $this->calculateDependencyMetrics(); |
| |
| return $this->ca; |
| } |
| |
| /** |
| * Returns the Efferent Couplings (Ce) for the class. |
| * |
| * The number of other classes that the class depends upon is an indicator |
| * of the class' independence. |
| * |
| * @return integer |
| * @access public |
| */ |
| public function getCe() { |
| $this->calculateDependencyMetrics(); |
| |
| return $this->ce; |
| } |
| |
| /** |
| * Returns the Class Size (CSZ) of the class. |
| * |
| * @return integer |
| * @access public |
| * @see http://www.aivosto.com/project/help/pm-oo-misc.html |
| */ |
| public function getCSZ() { |
| return count($this->methods) + $this->vars; |
| } |
| |
| /** |
| * Returns the Class Interface Size (CIS) of the class. |
| * |
| * @return integer |
| * @access public |
| * @see http://www.aivosto.com/project/help/pm-oo-misc.html |
| */ |
| public function getCIS() { |
| return $this->publicMethods + $this->varsNp; |
| } |
| |
| /** |
| * Returns the Code Coverage for the class. |
| * |
| * @return float |
| * @access public |
| */ |
| public function getCoverage() { |
| return $this->coverage; |
| } |
| |
| /** |
| * Returns the Depth of Inheritance Tree (DIT) for the class. |
| * |
| * @return integer |
| * @access public |
| * @see http://www.aivosto.com/project/help/pm-oo-ck.html |
| */ |
| public function getDIT() { |
| return $this->dit; |
| } |
| |
| /** |
| * Returns the Instability (I) for the class. |
| * |
| * The ratio of efferent coupling (Ce) to total coupling (Ce + Ca) such that |
| * I = Ce / (Ce + Ca). This metric is an indicator of the class' resilience |
| * to change. |
| * |
| * The range for this metric is 0 to 1, with I=0 indicating a completely |
| * stable class and I=1 indicating a completely instable class. |
| * |
| * @return float |
| * @access public |
| */ |
| public function getI() { |
| $this->calculateDependencyMetrics(); |
| |
| return $this->i; |
| } |
| |
| /** |
| * Returns the Number of Interfaces Implemented by the class (IMPL). |
| * |
| * @return integer |
| * @access public |
| * @see http://www.aivosto.com/project/help/pm-oo-misc.html |
| */ |
| public function getIMPL() { |
| return $this->impl; |
| } |
| |
| /** |
| * Returns the Method Inheritance Factor (MIF) for the class. |
| * |
| * @return float |
| * @access public |
| * @see http://www.aivosto.com/project/help/pm-oo-mood.html |
| */ |
| public function getMIF() { |
| return $this->mif; |
| } |
| |
| /** |
| * Returns the Method Hiding Factor (MHF) for the class. |
| * |
| * @return float |
| * @access public |
| * @see http://www.aivosto.com/project/help/pm-oo-mood.html |
| */ |
| public function getMHF() { |
| return $this->mhf; |
| } |
| |
| /** |
| * Returns the Number of Children (NOC) for the class. |
| * |
| * @return integer |
| * @access public |
| * @see http://www.aivosto.com/project/help/pm-oo-ck.html |
| */ |
| public function getNOC() { |
| return $this->noc; |
| } |
| |
| /** |
| * Returns the Polymorphism Factor (PF) for the class. |
| * |
| * @return float |
| * @access public |
| * @see http://www.aivosto.com/project/help/pm-oo-mood.html |
| */ |
| public function getPF() { |
| return $this->pf; |
| } |
| |
| /** |
| * Returns the Number of Variables (VARS) defined by the class. |
| * |
| * @return integer |
| * @access public |
| * @see http://www.aivosto.com/project/help/pm-oo-misc.html |
| */ |
| public function getVARS() { |
| return $this->vars; |
| } |
| |
| /** |
| * Returns the Number of Non-Private Variables (VARSnp) defined by the class. |
| * |
| * @return integer |
| * @access public |
| * @see http://www.aivosto.com/project/help/pm-oo-misc.html |
| */ |
| public function getVARSnp() { |
| return $this->varsNp; |
| } |
| |
| /** |
| * Returns the Number of Variables (VARSi) defined and inherited by the class. |
| * |
| * @return integer |
| * @access public |
| * @see http://www.aivosto.com/project/help/pm-oo-misc.html |
| */ |
| public function getVARSi() { |
| return $this->varsI; |
| } |
| |
| /** |
| * Returns the Weighted Methods Per Class (WMC) for the class. |
| * |
| * @return integer |
| * @access public |
| * @see http://www.aivosto.com/project/help/pm-oo-ck.html |
| */ |
| public function getWMC() { |
| return $this->wmc; |
| } |
| |
| /** |
| * Returns the Weighted Non-Private Methods Per Class (WMCnp) for the class. |
| * |
| * @return integer |
| * @access public |
| * @see http://www.aivosto.com/project/help/pm-oo-misc.html |
| */ |
| public function getWMCnp() { |
| return $this->wmcNp; |
| } |
| |
| /** |
| * Returns the Weighted Inherited Methods Per Class (WMCi) for the class. |
| * |
| * @return integer |
| * @access public |
| * @see http://www.aivosto.com/project/help/pm-oo-misc.html |
| */ |
| public function getWMCi() { |
| return $this->wmcI; |
| } |
| |
| /** |
| * Calculates the Attribute Inheritance Factor (AIF) and |
| * Attribute Hiding Factor (AHF) metrics for the class. |
| * |
| * @access protected |
| */ |
| protected function calculateAttributeMetrics() { |
| $attributes = 0; |
| $hiddenAttributes = 0; |
| $inheritedAttributes = 0; |
| |
| foreach ($this->class->getProperties() as $attribute) { |
| if ($attribute->isPublic()) { |
| $this->varsNp ++; |
| } else { |
| $hiddenAttributes ++; |
| } |
| |
| if ($attribute->getDeclaringClass()->getName() == $this->class->getName()) { |
| $this->vars ++; |
| } else { |
| $inheritedAttributes ++; |
| } |
| |
| $this->varsI ++; |
| $attributes ++; |
| } |
| |
| if ($attributes > 0) { |
| $this->aif = (100 * $inheritedAttributes) / $attributes; |
| $this->ahf = (100 * $hiddenAttributes) / $attributes; |
| } |
| } |
| |
| /** |
| * Calculates the Method Inheritance Factor (MIF) |
| * Method Hiding Factor (MHF), Weighted Methods Per Class (WMC), |
| * Weighted Non-Private Methods Per Class (WMCnp), and |
| * Weighted Inherited Methods Per Class (WMCi) metrics for the class. |
| * |
| * @access protected |
| */ |
| protected function calculateMethodMetrics() { |
| $numMethods = 0; |
| $hiddenMethods = 0; |
| $inheritedMethods = 0; |
| |
| $methods = array_merge($this->methods, $this->inheritedMethods); |
| |
| foreach ($methods as $method) { |
| $ccn = $method->getCCN(); |
| |
| if ($method->getMethod()->getDeclaringClass()->getName() == $this->class->getName()) { |
| $this->wmc += $ccn; |
| |
| if ($method->getMethod()->isPublic()) { |
| $this->publicMethods ++; |
| $this->wmcNp += $ccn; |
| } |
| } else { |
| $inheritedMethods ++; |
| } |
| |
| if (! $method->getMethod()->isPublic()) { |
| $hiddenMethods ++; |
| } |
| |
| $this->wmcI += $ccn; |
| $numMethods ++; |
| } |
| |
| if ($numMethods > 0) { |
| $this->mif = (100 * $inheritedMethods) / $numMethods; |
| $this->mhf = (100 * $hiddenMethods) / $numMethods; |
| } |
| } |
| |
| /** |
| * Calculates the Number of Children (NOC) metric for the class. |
| * |
| * @access protected |
| */ |
| protected function calculateNumberOfChildren() { |
| $className = $this->class->getName(); |
| |
| if (! isset(self::$nocCache[$className])) { |
| self::$nocCache = array(); |
| } |
| |
| if (empty(self::$nocCache)) { |
| foreach (get_declared_classes() as $_className) { |
| $class = new ReflectionClass($_className); |
| $parent = $class->getParentClass(); |
| |
| if ($parent !== FALSE) { |
| $parentName = $parent->getName(); |
| |
| if (isset(self::$nocCache[$parentName])) { |
| self::$nocCache[$parentName] ++; |
| } else { |
| self::$nocCache[$parentName] = 1; |
| } |
| } |
| } |
| } |
| |
| if (isset(self::$nocCache[$className])) { |
| $this->noc = self::$nocCache[$className]; |
| } |
| } |
| |
| /** |
| * Calculates the Polymorphism Factor (PF) metric for the class. |
| * |
| * @param ReflectionClass $class |
| * @access protected |
| */ |
| protected function calculatePolymorphismFactor() { |
| $parentClass = $this->class->getParentClass(); |
| |
| if ($parentClass !== FALSE) { |
| $overridableMethods = array(); |
| |
| foreach ($parentClass->getMethods() as $method) { |
| if (! $method->isPrivate() && ! $method->isFinal() && ! $method->isAbstract()) { |
| $overridableMethods[] = $method->getName(); |
| } |
| } |
| |
| if (! empty($overridableMethods)) { |
| $overriddenMethods = 0; |
| |
| foreach ($this->class->getMethods() as $method) { |
| if ($method->getDeclaringClass()->getName() == $this->class->getName()) { |
| $methodName = $method->getName(); |
| |
| if (in_array($methodName, $overridableMethods)) { |
| $overriddenMethods ++; |
| } |
| } |
| } |
| |
| $this->pf = (100 * $overriddenMethods) / count($overridableMethods); |
| } |
| } |
| } |
| |
| /** |
| * Calculates the Code Coverage for the class. |
| * |
| * @param array $codeCoverage |
| * @access protected |
| */ |
| protected function calculateCodeCoverage(&$codeCoverage) { |
| $statistics = PHPUnit_Util_CodeCoverage::getStatistics($codeCoverage, $this->class->getFileName(), $this->class->getStartLine(), $this->class->getEndLine()); |
| |
| $this->coverage = $statistics['coverage']; |
| $this->loc = $statistics['loc']; |
| $this->locExecutable = $statistics['locExecutable']; |
| $this->locExecuted = $statistics['locExecuted']; |
| } |
| |
| /** |
| * Calculates the dependencies for this class. |
| * |
| * @access protected |
| */ |
| protected function calculateDependencies() { |
| $parent = $this->class->getParentClass(); |
| |
| if ($parent && $parent->isUserDefined() && ! in_array($parent->getName(), $this->dependencies)) { |
| $this->dependencies[] = $parent->getName(); |
| } |
| |
| $interfaces = $this->class->getInterfaces(); |
| |
| foreach ($interfaces as $interface) { |
| if ($interface->isUserDefined() && ! in_array($interface->getName(), $this->dependencies)) { |
| $this->dependencies[] = $interface->getName(); |
| } |
| } |
| |
| $methods = array_merge($this->methods, $this->inheritedMethods); |
| |
| foreach ($methods as $method) { |
| foreach ($method->getDependencies() as $dependency) { |
| if (! in_array($dependency, $this->dependencies)) { |
| $this->dependencies[] = $dependency; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Calculates the dependency-based metrics for this class. |
| * |
| * @access protected |
| */ |
| protected function calculateDependencyMetrics() { |
| if ($this->ca == 0 && $this->ce == 0 && $this->i == 0) { |
| $className = $this->class->getName(); |
| $dependencies = $this->project->getDependencies(); |
| |
| foreach ($dependencies[$className] as $dependency) { |
| if ($dependency > 0) { |
| $this->ce ++; |
| } |
| } |
| |
| unset($dependencies[$className]); |
| |
| foreach ($dependencies as $_className => $_dependencies) { |
| if ($_dependencies[$className] > 0) { |
| $this->ca ++; |
| } |
| } |
| |
| $sum = $this->ce + $this->ca; |
| |
| if ($sum > 0) { |
| $this->i = $this->ce / $sum; |
| } |
| } |
| } |
| } |
| ?> |