public static function executable($class, array $options = []) {
		$defaults = [
			'self' => true,
			'filter' => true,
			'methods' => [],
			'empty' => [' ', "\t", '}', ')', ';'],
			'pattern' => null,
			'blockOpeners' => ['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('|', [
				"({$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 += ['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 = [];

			foreach ($tokens as $token) {
				if (is_array($token)) {
					if (!in_array($token[0], [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;
	}
public static function executable($class, array $options = []) {
		$defaults = [
			'self' => true,
			'filter' => true,
			'methods' => [],
			'empty' => [' ', "\t", '}', ')', ';'],
			'pattern' => null,
			'blockOpeners' => ['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('|', [
				"({$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 += ['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 = [];

			foreach ($tokens as $token) {
				if (is_array($token)) {
					if (!in_array($token[0], [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;
	}
public static function executable ( $ class , array $ options = [ ] ) { $ defaults = [ 'self' => true , 'filter' => true , 'methods' => [ ] , 'empty' => [ ' ' , "\t" , '}' , ')' , ';' ] , 'pattern' => null , 'blockOpeners' => [ '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 ( '|' , [ "({$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 += [ '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 = [ ] ; foreach ( $ tokens as $ token ) { if ( is_array ( $ token ) ) { if ( ! in_array ( $ token [ 0 ] , [ 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 ; }
Gets the executable lines of a class, by examining the start and end lines of each method.

@param mixed $class Class name as a string or object instance.
@param array $options 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.
Gets the executable lines of a class by examining the start and end lines of each method .