КОнтакты, предложения, отзывы

.rar или .zip
Вложение
Онлайн-чат
На этом сайте, вы найдёте полезную информацию, практические советы в области веб-программирования, веб-дизайна и веб-разработок в целом. Мы с удовольствием поделимся с вами реальными примерами и решениями задач, связанных с jQuery , JavaScript , PHP и MySQL , версткой сайтов , поможем разобраться новичкам с современными технологиями, такими как Ajax , HTML5 , CSS3 и многими другими.

Исследование классов и Reflection API

Ку, друзья. :) Писать код самому и разбираться в чужом - две абсолютно разные вещи. Продумать и реализовать свой интерфейс намного легче и проще. Мне, к примеру, лучше самому написать свой собственный движок простым и понятным каждому программисту языком, чем использовать чужие движки и фреймворки, реализация методов в которых скрыта очень глубоко в мутной воде. Свой велосипед всегда самый лучший и надёжный, каждую спицу своими собственными руками шлифовал. К тому же такие сайты сможет поддерживать даже начинающий программист.

Но уж если вам выпала нелёгкая доля и приходится копать, умные люди сделали для нас отличный инструмент.
Программный интерфейс Reflection API для PHP - то же самое, что и пакет java.lang.reflect для Java. Он состоит из встроенных классов для анализа свойств, методов и классов. В некоторых отношениях он напоминает функции для работы с обьектами, такие как get_class_vars(), но является более гибким и позволяет учитывать больше нюансов. Он также прелназначен для более эффективной работы с обьектно-ориентированными средствами PHP, такими как управление доступом, интерфейсы и абстрактные классы. Старые, более ограниченные функции классов так роботать не могут. Давайте рассмотрим интерфейс, который готов к выполнению данной работы

Основные сведения

Интерфейс Reflection API можно использовать для иссследования не только классов. Например, класс ReflectionFunction предоставляет информацию о заданной функции, а ReflectionExtension - информацию о скомпилированных расширениях PHP.
Некоторые классы Reflection API
Класс ReflectionClass предоставляе методы, которые собирают информацию обо всех аспектах заданного класса, независимо от того, внутренний ли это класс или определённый пользователем. Конструктору класса ReflectionClass в качестве единственного аргумента передаётся имя класса, как показано ниже.
$prod_class = new ReflectionClass('CDProduct');
Reflection::export($prod_class);
Создав обьект типа ReflectionClass, мы можем использовать вспомогательный класс Reflection для создания итоговой информации о классе CDProduct. У класса Reflection есть статтический метод export(), который форматирует и создаёт дамп данных, содержащихся в обьекте типа Reflection. Этот метод даёт информацию почти обо всех аспектах класса, включая состояние доступа к свойствам и методам, аргументы, необходимые каждому методу и расположение каждого метода внутри файла сценария. Сравните это с традиционной функцией отладки. функция var_dump() - это инструмент общего назначения для выдачи итоговой информации о данных. Прежде чем получить итоговую информацию, вы должны создать экземпляр обьекта, но даже после этого var_dump() не даст настолько подробной информации, как метод Reflection::export().
$cd = new CDProduct("Пропавший без вести",
                    "ДДТ",
                    10.99, null, 60.33);
var_dump($cd);
Функция var_dump() и её "сестра" функция print_r() - невероятно удобные инструменты для отображения данных в сценарии. Но для классов и функций интерфейс Reflection API позволяет выйти на совершшенно новый уровень отладки.

Исследование класса

Метод Reflection::export() предоставляет много полезной информации для отладки, но интерфейс Reflection API можно использовать особым образом. Давайте будем работать непосредственно с классами Reflection.
Мы уже знаем, как создать экземпляр обьекта ReflectionClass. А теперь давайте используем обьект ReflectionClass, чтобы исследовать класс CDProduct в процессе выполнения сценария. Мы хотим узнать, к какому типу класса он относится и можно ли создать его экземпляр? Вот функция, которая поможет ответить на эти вопросы.
function classData(ReflectionClass $class){
    
  $details = '';
  $name = $class->getName();
  if($class->isUserDefined()){
    $details .= "$name - класс определён пользователем <br>";
  }
  if($class->isInternal()){
    $details .= "$name - встроенный класс <br>";
  }
  if($class->isInterface()){
    $details .= "$name - это интерфейс <br>";
  }
  if($class->isAbstract()){
    $details .= "$name - это абстрактный класс <br>";
  }
  if($class->isfinal()){
    $details .= "$name - завершенный класс <br>";
  }
  if(!$class->isInstance()){
    $details .= "$name - нельзя создать экземпляр класса <br>";
  }
  
  return $details;
    
}

$prod_class = new ReflectionClass('CDProduct');
print classData($prod_class);
Можно исследовать даже исходный код класса, определённого пользователем. Объект ReflectionClass позволяет получить имя файла класса и номера первой и последней строк в этом файле, в которых этот классс определяется.
class ReflectionUtil{
  static function getClassSource(ReflectionClass $class){
    $path = $class->getFileName();
    $lines = @file($path);
    $from = $class->getStartLine();
    $to = $class->getEndLine();
    $len = $to - $from + 1;
    return implode(array_slice($lines, $from - 1, $len));
  }
}


print ReflectionUtil::getClassSource(new ReflectionClass('CDProduct'));

Исследование методов

Так же как ReflectionClass используется для исследования класса, обьект типа ReflectionMethod применяется для исследования методов.
Ссылку на обьект ReflectionMethod можно получить двумя способами. Во-первых, можно получить массив обьектов ReflectionMethod, вызвав метод ReflectionClass::getMethods(). А во-вторых, если вас интересует конкретный метод, то передайте его имя методу ReflectionClass::getMethod(), который и вернёт соответствующий обьект типа ReflectionMethod.
Давайте воспользуемся методом ReflectionClass::getMethods(), чтобы проверить возможности класса ReflectionMethod.
$prod_class = new ReflectionClass('CDProduct');
$methods = $prod_class->getMethods();

foreach($methods as $method){
  print methodData($method);
  print "<br><br>";
}

function methodData(ReflectionMethod $method){
  $details = "";
  $name = $method->getName();
  // isUserDefined, isInternal, isAbstract, 
  // isPublic, isProtected, isPrivate
  // isStatic, isFinal
  if($method->isConstructor()){
    $details .= "$name - метод конструктора <br>";
  }
  if($method->returnsReference()){
    $details .= "$name - метод возвращает ссылку, а не значение <br>";
  }
}
Как и можно было ожидать, доступ к исходному коду метода можно получить тем же способом, который использовался ранее с ReflectionClass для доступа к классу.
class ReflectionUtil{
  static function getMethodSource(ReflectionMethod $method){
    $path = $method->getFileName();
    $lines = @file($path);
    $from = $method->getStartLine();
    $to = $method->getEndLine();
    $len = $to - $from + 1;
    return implode(array_slice($lines, $from - 1, $len));
  }
}

$class = new ReflectionClass('CDProduct');
$method = $class->getMethod('getSummaryLine');
echo ReflectionUtil::getMethodSource($method);

Исследование аргументов методов

Теперь, когда стало возможным ограничивать типы аргументов с помощью сигнатур методов, чревычайно полезной кажется возможность исследования аргументов, обьявленных в сигнатуре метода. В интерфейсе Reflection API именно для этой цели предусмотрен класс ReflectionParameter. чтобы получить обьект типа ReflectionParameter, нам понадобится помощь обьекта ReflectionMethod. Метод ReflectionMethod::getParameters() возвращает массив обьектов типа ReflectionParameter.
Имея обект ReflectionParameter, можно узнать следующее: имя аргумента, была ли переменная передана по ссылке, информацию о классе, который используется для уточнения типа аргумента и будет ли метод по умолчанию назначать нулевое значение для аргумента.
Ниже приведен пример использования некоторых методов класса ReflectionParameter.
$prod_class = new ReflectionClass('CDProduct');
$method = $prod_class->getMethod("__construct");
$params = $method->getParameters();

foreach($params as $param){
  print argData($param)
}

function argData(ReflectionParameter $arg){
  $details = "";
  $declaringclass = $arg->getDeclaringClass();
  $name = $arg->getName();
  $class = $arg->getClass();
  $position = $arg->getPosition();
  $details .= "\$$name находится в позиции $position\n";
  if(!empty($class)){
    $className = $class->getName();
    $details .= "\$$name должен быть обьектом типа $className\n";
  }
  if($arg->isPassedByReference()){
    $details .= "\$$name передан по ссылке\n";
  }
  if($arg->isDefaultValueAvailable()){
    $def = $arg->getDefaultValue();
    $details .= "\$$name по умолчанию равно: $def\n";
  }
  return $details;
}
2015.11.15 102

В течение пяти минут я смотрел на свой собственный код и думал - что, ч..ерт возьми, написал этот программист?
Войдите или Зарегистрируйтесь чтобы оставить комментарий

Комментарии


    Яндекс.Метрика Яндекс.Метрика