4 * This file is part of Psy Shell.
6 * (c) 2012-2017 Justin Hileman
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Psy\Command\ListCommand;
14 use Psy\Formatter\SignatureFormatter;
16 use Psy\VarDumper\Presenter;
17 use Symfony\Component\Console\Input\InputInterface;
20 * Abstract Enumerator class.
22 abstract class Enumerator
25 const IS_PUBLIC = 'public';
26 const IS_PROTECTED = 'protected';
27 const IS_PRIVATE = 'private';
28 const IS_GLOBAL = 'global';
29 const IS_CONSTANT = 'const';
30 const IS_CLASS = 'class';
31 const IS_FUNCTION = 'function';
35 private $filter = false;
36 private $invertFilter = false;
40 * Enumerator constructor.
42 * @param Presenter $presenter
44 public function __construct(Presenter $presenter)
46 $this->presenter = $presenter;
50 * Return a list of categorized things with the given input options and target.
52 * @param InputInterface $input
53 * @param Reflector $reflector
54 * @param mixed $target
58 public function enumerate(InputInterface $input, \Reflector $reflector = null, $target = null)
60 $this->setFilter($input);
62 return $this->listItems($input, $reflector, $target);
66 * Enumerate specific items with the given input options and target.
68 * Implementing classes should return an array of arrays:
74 * 'style' => 'public',
80 * @param InputInterface $input
81 * @param Reflector $reflector
82 * @param mixed $target
86 abstract protected function listItems(InputInterface $input, \Reflector $reflector = null, $target = null);
88 protected function presentRef($value)
90 return $this->presenter->presentRef($value);
93 protected function showItem($name)
95 return $this->filter === false || (preg_match($this->pattern, $name) xor $this->invertFilter);
98 private function setFilter(InputInterface $input)
100 if ($pattern = $input->getOption('grep')) {
101 if (substr($pattern, 0, 1) !== '/' || substr($pattern, -1) !== '/' || strlen($pattern) < 3) {
102 $pattern = '/' . preg_quote($pattern, '/') . '/';
105 if ($input->getOption('insensitive')) {
109 $this->validateRegex($pattern);
111 $this->filter = true;
112 $this->pattern = $pattern;
113 $this->invertFilter = $input->getOption('invert');
115 $this->filter = false;
120 * Validate that $pattern is a valid regular expression.
122 * @param string $pattern
126 private function validateRegex($pattern)
128 set_error_handler(array('Psy\Exception\ErrorException', 'throwException'));
130 preg_match($pattern, '');
131 } catch (ErrorException $e) {
132 throw new RuntimeException(str_replace('preg_match(): ', 'Invalid regular expression: ', $e->getRawMessage()));
134 restore_error_handler();
137 protected function presentSignature($target)
139 // This might get weird if the signature is actually for a reflector. Hrm.
140 if (!$target instanceof \Reflector) {
141 $target = Mirror::get($target);
144 return SignatureFormatter::format($target);