Поиск по сайту:

Что такое «отражение» в программировании?


Рефлексивное программирование — это механизм, который позволяет процессу интроспективно анализировать свои возможности. API отражения, встроенные в языки программирования, позволяют проверять код во время выполнения. Вы можете использовать эту возможность, чтобы узнать об окружающей кодовой базе и ее содержимом.

Об отражении часто говорят в контексте объектно-ориентированного программирования. Вы часто используете отражение для обнаружения сущностей кодовой базы во время выполнения. API отражения языка позволит вам проверять классы, методы, свойства и типы из вашей системы. Это позволяет создавать более динамичные функции.

Системы, использующие отражение, способны исследовать и модифицировать свою собственную среду. В этом отличие рефлексии от простого ценностного самоанализа. Язык с полной поддержкой отражения позволит модифицировать кодовую базу во время выполнения, эффективно позволяя исходному коду переписывать аспекты самого себя.

Пример отражения

Одно из распространенных применений отражения — во время тестирования. Рефлексия может помочь вам имитировать классы, раскрывая их внутреннее поведение. Метод класса, который является защищенным или частным, обычно не поддается тестированию; используя отражение, вы можете переопределить ограничение видимости, чтобы оно стало public в ваших модульных тестах.

class Test {
 
    protected int $Value;
 
    public function __construct(int $Value) {
        $this -> Value = $Value;
    }
 
    protected function computeValue() : int {
        return ($this -> Value * 2);
    }
 
}
 
/**
 * Without Reflection
 */
 
$t = new Test(10);
 
// Error - the method isn't publicly accessible
assert($t -> computeValue() === 20);
 
/**
 * Using Reflection
 */
 
$reflectionMethod = new ReflectionMethod(Test::CLASS, "computeValue");
$reflectionMethod -> setAccessible(true);
 
$t = new Test(10);
 
// This now works!
assert($reflectionMethod -> invoke($t) === 20);

В этом примере с использованием PHP класс Test определяет метод protected, который используется внутри. Поскольку метод выполняет вычисления, вы можете захотеть провести его модульное тестирование. Вы не можете вызывать метод извне, но PHP Reflection API позволяет обойти ограничения видимости. Экземпляр ReflectionMethod предоставляет информацию о методе и позволяет вызывать измененную версию.

Хотя это полезно, вы должны осознавать, что этим можно злоупотребить. Широкое использование отражения при тестировании часто указывает на более серьезные проблемы в вашей кодовой базе. Это означает, что интерфейс класса чрезмерно ограничителен и не подходит для его обязанностей. Во многих случаях более целесообразно преобразовать защищенный метод в новый класс, который предоставляет свой собственный открытый интерфейс.

Вот как это может выглядеть для примера, показанного выше:

class Calculator {
 
    public function computeValue() : int {
        return ($this -> Value * 2);
    }
 
}
 
class Test {
 
    protected int $Value;
 
    protected Calculator $Calculator;
 
    public function __construct(int $Value, Calculator $Calculator) {
        $this -> Value = $Value;
        $this -> Calculator = $Calculator;
    }
 
}

Компонент калькулятора теперь является отдельной автономной единицей с общедоступным интерфейсом, который можно тестировать. Это идет рука об руку с внедрением зависимостей — классу Test теперь предоставляется Calculator, который реализует логику вычислений.

Использование отражения с непредсказуемыми значениями

Отражение также полезно, когда вы пишете общий код внутри фреймворка. Возможно, вам придется взаимодействовать с пользовательскими типами, которые вы не можете предвидеть. Отражение может помочь, когда вы не знаете, какие методы и свойства предоставляет тип.

Вы можете получить представление о функциональных возможностях типа без каких-либо предварительных знаний об его источнике. Это полезно в контексте компонентов ведения журналов и отчетов об ошибках, которые могут захотеть вывести список членов любого переданного им класса.

Таким же образом часто реализуются и системы ранжирования данных. Представьте себе маршаллер, который берет класс и преобразует его в представление JSON. Вы можете определить соглашение о том, что любой метод с префиксом get и заканчивающийся на Json (например, getUserJson()) должен вызываться маршалером и добавлено к его выходу. Отражение предоставляет механизм для получения списка методов. Затем вы должны реализовать логику для определения тех, которые вы должны вызывать.

Рефлексия, компиляция и сборки

Reflection предоставляет дополнительные возможности в скомпилированных языках, использующих связанные библиотеки и сборки. API-интерфейсы Reflection позволяют проверять содержимое загруженных сборок. В таких языках, как C#, вы можете динамически загружать дополнительные сборки с помощью API Reflection.

Этот подход может быть полезен, если вы реализуете систему плагинов с пользовательскими сборками. Ваша программа не будет знать, какие плагины доступны, когда она скомпилирована. Каждый раз, когда он запускается, ему нужно будет проверять файловую систему, чтобы найти доступные сборки плагинов. Как только плагин найден, Reflection предоставляет механизм для загрузки и создания экземпляров его членов.

Вы можете проверить плагин, найти классы, которые он предоставляет, и зарегистрировать его в своем приложении. Дальнейшая проверка сборки может предоставить имя и версию плагина для отображения в ваших журналах и пользовательском интерфейсе.

Отражение также можно использовать для переключения сборок на основе внешней конфигурации. Допустим, вы пишете приложение, которое сохраняет файлы изображений в хранилище. У вас могут быть LocalStorageDriver, FtpStorageDriver и AmazonS3StorageDriver, каждый из которых содержится в собственной сборке (.dll в C#). ).

Используя отражение, вы можете предложить ключ «драйвера хранилища» в файле конфигурации вашей системы. Соответствующая сборка будет загружаться динамически в зависимости от значения вашего файла конфигурации. Вы должны изучить сборку, чтобы обнаружить класс, который реализует ваш интерфейс StorageDriver.

Этот подход позволяет вам переключать компоненты вашей системы во время выполнения. Вам не нужно перекомпилировать или перезапускать программу для переключения между сборками. Это дает вам повышенную гибкость и помогает реализовать директивы конфигурации.

Оценочные операторы

Отражение тесно связано с eval. Многие языки программирования позволяют выполнять динамические строковые значения как исходный код.

Eval — это перестановка отражения с почти безграничной силой. Он позволяет создавать и запускать новый код в программе, работающей в режиме реального времени. Это создает потенциально катастрофическую проблему безопасности, если пользовательский ввод передается в строку eval.

Оператор eval следует использовать, когда у вас нет других вариантов. Вы должны убедиться, что оператор выполняется в ограниченном контексте, который не может быть использован пользователями. Помните, что успешная инъекция кода даст злоумышленнику те же возможности, что и ваш обычный код приложения.

Заключение

Рефлексия — это метод программирования, который дает возможность интроспективного анализа кода. Эффективное использование отражения позволяет вам писать более динамичные системы и получать выгоду от повышенной автоматизации. Вы также можете использовать отражение для модульного тестирования недостижимого частного кода.

Вам нужно проявлять осторожность. API-интерфейсы Reflection в языках программирования являются мощными, поэтому с ними приходит ответственность. Самая большая проблема — это способность отражения подрывать защиту, обеспечиваемую вашим языком программирования.

Отражение допускает существование сценариев, которые в противном случае были бы невозможны, таких как запись в «неизменяемые» переменные и широкое публичное использование закрытых методов. Вы должны быть уверены, что ваш код соблюдает правила своего языка. Поэтому использование API-интерфейсов отражения должно быть тщательно продумано и ограничено конкретными разделами вашей системы.




Все права защищены. © Linux-Console.net • 2019-2024