lithium\analysis\Inspector::executable PHP Method

executable() public static method

Gets the executable lines of a class, by examining the start and end lines of each method.
public static executable ( mixed $class, array $options = [] ) : array
$class mixed Class name as a string or object instance.
$options array Set of options: - `'self'` _boolean_: If `true` (default), only returns lines of methods defined in `$class`, excluding methods from inherited classes. - `'methods'` _array_: An arbitrary list of methods to search, as a string (single method name) or array of method names. - `'filter'` _boolean_: If `true`, filters out lines containing only whitespace or braces. Note: for some reason, the Zend engine does not report `switch` and `try` statements as executable lines, as well as parts of multi-line assignment statements, so they are filtered out as well.
return array Returns an array of the executable line numbers of the class.
    public static function executable($class, array $options = array())
    {
        $defaults = array('self' => true, 'filter' => true, 'methods' => array(), 'empty' => array(' ', "\t", '}', ')', ';'), 'pattern' => null, 'blockOpeners' => array('switch (', 'try {', '} else {', 'do {', '} while'));
        $options += $defaults;
        if (empty($options['pattern']) && $options['filter']) {
            $pattern = str_replace(' ', '\\s*', join('|', array_map(function ($str) {
                return preg_quote($str, '/');
            }, $options['blockOpeners'])));
            $pattern = join('|', array("({$pattern})", "\\\$(.+)\\(\$", "\\s*['\"]\\w+['\"]\\s*=>\\s*.+[\\{\\(]\$", "\\s*['\"]\\w+['\"]\\s*=>\\s*['\"]*.+['\"]*\\s*"));
            $options['pattern'] = "/^({$pattern})/";
        }
        if (!$class instanceof ReflectionClass) {
            $class = new ReflectionClass(is_object($class) ? get_class($class) : $class);
        }
        $options += array('group' => false);
        $result = array_filter(static::methods($class, 'ranges', $options));
        if ($options['filter'] && $class->getFileName() && $result) {
            $lines = static::lines($class->getFileName(), $result);
            $start = key($lines);
            $code = implode("\n", $lines);
            $tokens = token_get_all('<' . '?php' . $code);
            $tmp = array();
            foreach ($tokens as $token) {
                if (is_array($token)) {
                    if (!in_array($token[0], array(T_COMMENT, T_DOC_COMMENT, T_WHITESPACE))) {
                        $tmp[] = $token[2];
                    }
                }
            }
            $filteredLines = array_values(array_map(function ($ln) use($start) {
                return $ln + $start - 1;
            }, array_unique($tmp)));
            $lines = array_intersect_key($lines, array_flip($filteredLines));
            $result = array_keys(array_filter($lines, function ($line) use($options) {
                $line = trim($line);
                $empty = preg_match($options['pattern'], $line);
                return $empty ? false : str_replace($options['empty'], '', $line) !== '';
            }));
        }
        return $result;
    }

Usage Example

Example #1
0
 /**
  * Analyzes code coverage results collected from XDebug, and performs coverage density analysis.
  *
  * @param object $report The report instance running this filter and aggregating results
  * @param array $classes A list of classes to analyze coverage on. By default, gets all
  *              defined subclasses of lithium\test\Unit which are currently in memory.
  * @return array|void Returns an array indexed by file and line, showing the number of
  *                    instances each line was called.
  */
 public static function analyze($report, array $classes = array())
 {
     $data = static::collect($report->results['filters'][__CLASS__]);
     $classes = $classes ?: array_filter(get_declared_classes(), function ($class) use($data) {
         $unit = 'lithium\\test\\Unit';
         return !is_subclass_of($class, $unit) || array_key_exists($class, $data);
     });
     $classes = array_values(array_intersect((array) $classes, array_keys($data)));
     $densities = $result = array();
     foreach ($classes as $class) {
         $classMap = array($class => Libraries::path($class));
         $densities += static::_density($data[$class], $classMap);
     }
     $executableLines = array();
     if (!empty($classes)) {
         $executableLines = array_combine($classes, array_map(function ($cls) {
             return Inspector::executable($cls, array('public' => false));
         }, $classes));
     }
     foreach ($densities as $class => $density) {
         $executable = $executableLines[$class];
         $covered = array_intersect(array_keys($density), $executable);
         $uncovered = array_diff($executable, $covered);
         $percentage = round(count($covered) / (count($executable) ?: 1), 4) * 100;
         $result[$class] = compact('class', 'executable', 'covered', 'uncovered', 'percentage');
     }
     $result = static::collectLines($result);
     return $result;
 }
All Usage Examples Of lithium\analysis\Inspector::executable