if (get_parent_class($className) != 'MyProject\Cli\AbstractCommand' ) {
throw new \MyProject\Exceptions\CliException('Class "' . $className . '" not a subclass of AbstractCommand');
}
Я думал над этим, долго) Но не мог понять как решить эту проблему, а с этой наводкой сделал моментально, мало ещё опыта, не все инструменты держатся в голове) bin/cli.php
...
$reflectionOfClassName = new ReflectionClass($className);
if (!$reflectionOfClassName->isSubclassOf('MyProject\Cli\AbstractCommand')) {
throw new \MyProject\Exceptions\CliException('Class "' . $className . '" not a subclass of AbstractCommand');
}
...
if (in_array(\MyProject\Cli\AbstractCommand::class, class_parents($className))){
throw new \MyProject\Exceptions\CliException('Class AbstractCommand is not a parent of class ' . $className);
}
$checkClassAbstract = new ReflectionClass($className);
if (!$checkClassAbstract->isSubclassOf(MyProject\Cli\AbstractCommand::class)) {
throw new \MyProject\Exceptions\CliException('Class "' . $className . '"is not subclass of AbstractCommand');
}
$obj = new ReflectionClass($className);
if(!$obj->isSubclassOf(MyProject\Cli\AbstractCommand::class)){
throw new MyProject\Exceptions\CliException('Сlass '. $className . ' is not a descendant of the AbstractCommand class ');
}
// Проверяем, является ли класс подклассом AbstractCommand
$obj = new ReflectionClass($className);
if (!$obj->isSubclassOf(\MyProject\Cli\AbstractCommand::class)) {
throw new \MyProject\Exceptions\CliException($className . ' not extend AbstractCommand');
}
private function getParam(string $paramName)
{
return $this->params[$paramName] ?? null;
}
private function ensureParamExists(string $paramName)
{
if (!isset($this->params[$paramName])) {
throw new CliException('Param with name "' . $paramName . '" is not set!');
}
}
Если устанавливать значение элемента массива в null, почему бы это не делать сразу в методе ensureParamExists?
private function ensureParamExists(string $paramName)
{
if (!isset($this->params[$paramName])) {
$this->params[$paramName] = null;
throw new CliException('Param with name "' . $paramName . '" is not set!');
}
}
А вообще, зачем эта установка в null? Ведь при проверке
(!isset($this->params[$paramName]))
в случае отсутствия этого элемента в массиве вылетит все равно исключение?
Речь идёт только о проверке только обязательных параметров, а не вообще всех. Метод, который называется ensure... Не должен менять состояние проверяемых данных, это сайд-эффект, никак не отражаемый в его названии.
$reflectionOfClass=new ReflectionClass($className);
if (!$reflectionOfClass->isSubclassOf(MyProject\Cli\AbstractCommand::class)){
throw new \MyProject\Exceptions\CliException('Класс '.$className.' не является наследником AbstractCommand');
}
$reflectionClass = new ReflectionClass($className);
if (!$reflectionClass->isSubclassOf(MyProject\Cli\AbstractCommand::class)) {
throw new \MyProject\Exceptions\CliException('Class "' . $className . '" not a subclass of AbstractCommand');
}
Хм, думаю я не корректно написал. Почему не срабатывает throw new Exception, когда мы ввели не правильно класс, а появляются ошибок Warning и Fatal. После я понял что class_exists запускает автозагрузку (class_exists ( string $class_name [, bool $autoload = TRUE ] ) : bool), но если я ставлю в false, ругается на каждый класс. Хотя автозагрузка в bin/cli.php уже есть и файлы подключены, осталось только проверить существует ли класс? )). Хочу просто получать корректную ошибку: 'Class Summat not found', а не ошибки (Warning и Fatal error). Пока что я переписал, так что у меня один класс и методы(команды) которые проверяю (method_exists) и если команды нет, то просто вывожу 'Операция Summat не найдена'. Еще можно добавить --help (c инструкцией и операциями )
Думаю, можно обойтись без рефлексии. И кода меньше...
if (!is_subclass_of($className, AbstractCommand::class)) {
throw new \MyProject\Exceptions\CliException('Class "' . $className . '" is not subclass of AbstractCommand');
}
$reflectionClass=new ReflectionClass($className);
if (!$reflectionClass->isSubclassOf(MyProject\Cli\AbstractCommand::class)) {
throw new MyProject\Exceptions\CliException('Class "' . $className . '" is not inherited AbstractCommand' );
}
$parentClasses = class_parents($className);
if (!in_array('MyProject\\Cli\\AbstractCommand', $parentClasses)) {
throw new MyProject\Exceptions\CliException('Class "' . $className . '" не имеет родителя');
}
Извините, я немного затупил, понял что нужно использовать get_parent_class($className) но почему то ловил вывод в функции spl_autoload_register и теперь мне непонятно почему в ней var_dump(get_parent_class($className)); выдает - bool(false)?
И второй вопрос, а разве CLI это продвинутый уровень PHP? Я еще тот говнокодер, но уже написал уже несколько сотен скриптов и парсеров на фрилансе, и постоянно запускаю скрипты из консоли, но только пару раз мне приходилось их запускать с параметрами. В реальной работе разве это нужно?
bin/cli.php
Хорошо, а если он является наследником через несколько классов? Подумайте в сторону PHP Reflection API.
Я думал над этим, долго) Но не мог понять как решить эту проблему, а с этой наводкой сделал моментально, мало ещё опыта, не все инструменты держатся в голове)
bin/cli.php
Супер! Вместо строки 'MyProject\Cli\AbstractCommand' лучше использовать MyProject\Cli\AbstractCommand::class
Хорошо, буду знать и использовать)
Исключение будет бросаться для всех наследников этого класса, а нужно наоборот.
$classReflector = new ReflectionClass($className);
Такой вопрос, можно как то вызвать методы класса ReflectionClass статически, без создания объекта?
Не знаю, почитайте документацию. Но непонятно для чего вам это.
Отлично
Отлично
Отлично
Спасибо за урок!
Отлично
Если устанавливать значение элемента массива в null, почему бы это не делать сразу в методе ensureParamExists?
А вообще, зачем эта установка в null? Ведь при проверке
в случае отсутствия этого элемента в массиве вылетит все равно исключение?
Речь идёт только о проверке только обязательных параметров, а не вообще всех. Метод, который называется ensure... Не должен менять состояние проверяемых данных, это сайд-эффект, никак не отражаемый в его названии.
Отлично
Отлично!
Как избавиться от ошибок (Warning и Fatal error), если вводишь не правильный класс?
А смысл от них избавляться?
Хм, думаю я не корректно написал. Почему не срабатывает throw new Exception, когда мы ввели не правильно класс, а появляются ошибок Warning и Fatal. После я понял что class_exists запускает автозагрузку (class_exists ( string $class_name [, bool $autoload = TRUE ] ) : bool), но если я ставлю в false, ругается на каждый класс. Хотя автозагрузка в bin/cli.php уже есть и файлы подключены, осталось только проверить существует ли класс? )). Хочу просто получать корректную ошибку: 'Class Summat not found', а не ошибки (Warning и Fatal error). Пока что я переписал, так что у меня один класс и методы(команды) которые проверяю (method_exists) и если команды нет, то просто вывожу 'Операция Summat не найдена'. Еще можно добавить --help (c инструкцией и операциями )
Ну так это в автозагрузчике дело. Он почему-то делает require сразу, хотя сначала должен проверить сущетсвование файла
Отлично!
Думаю, можно обойтись без рефлексии. И кода меньше...
Хорошее решение
Классное решение!
cli.php
Отлично!
bin/cli.php
Норм, хотя ожидал применение instanceof
Норм!
Извините, я немного затупил, понял что нужно использовать get_parent_class($className) но почему то ловил вывод в функции spl_autoload_register и теперь мне непонятно почему в ней var_dump(get_parent_class($className)); выдает - bool(false)?
И второй вопрос, а разве CLI это продвинутый уровень PHP? Я еще тот говнокодер, но уже написал уже несколько сотен скриптов и парсеров на фрилансе, и постоянно запускаю скрипты из консоли, но только пару раз мне приходилось их запускать с параметрами. В реальной работе разве это нужно?
Смотрим доку
If the object does not have a parent or the class given does not exist false will be returned.
Нужно :)