HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-26
1 <p>Многие объекты в ООП не являются абстракцией данных, а используются как способ сохранить конфигурацию для выполнения повторяющихся действий, таких как генерация HTML из Markdown или определение города по IP. Конфигурация осуществляется через передачу опций в конструктор объекта, а сами опции хранятся внутри и используются для всех последующих вызовов.</p>
1 <p>Многие объекты в ООП не являются абстракцией данных, а используются как способ сохранить конфигурацию для выполнения повторяющихся действий, таких как генерация HTML из Markdown или определение города по IP. Конфигурация осуществляется через передачу опций в конструктор объекта, а сами опции хранятся внутри и используются для всех последующих вызовов.</p>
2 <p>Но что, если для конкретного запроса нужно временно установить опции, отличные от тех, что были переданы в конструктор? В этом уроке мы рассмотрим способы временно изменять эту конфигурацию для конкретного вызова.</p>
2 <p>Но что, если для конкретного запроса нужно временно установить опции, отличные от тех, что были переданы в конструктор? В этом уроке мы рассмотрим способы временно изменять эту конфигурацию для конкретного вызова.</p>
3 <h2>Создание нового объекта</h2>
3 <h2>Создание нового объекта</h2>
4 <p>Мы можем создать новый объект с нужной нам конфигурацией там, где это требуется:</p>
4 <p>Мы можем создать новый объект с нужной нам конфигурацией там, где это требуется:</p>
5 <p>Здесь мы создаем новый объект Request с новым параметром таймаута. Затем выполняется HTTP GET-запрос на http://example.com с использованием этого объекта.</p>
5 <p>Здесь мы создаем новый объект Request с новым параметром таймаута. Затем выполняется HTTP GET-запрос на http://example.com с использованием этого объекта.</p>
6 <p>Это простое решение. Но у него есть ряд недостатков. Главный недостаток - невозможно подменить реализацию, так как объект создается не на этапе конфигурирования системы, а в том месте, где происходит вызов. Из-за этого придется дублировать общие опции, а тестирование станет затруднительным или невозможным.</p>
6 <p>Это простое решение. Но у него есть ряд недостатков. Главный недостаток - невозможно подменить реализацию, так как объект создается не на этапе конфигурирования системы, а в том месте, где происходит вызов. Из-за этого придется дублировать общие опции, а тестирование станет затруднительным или невозможным.</p>
7 <p>Здесь речь идет про тот самый полиморфизм, о котором мы будем говорить в будущем.</p>
7 <p>Здесь речь идет про тот самый полиморфизм, о котором мы будем говорить в будущем.</p>
8 <p>Теперь рассмотрим следующий способ.</p>
8 <p>Теперь рассмотрим следующий способ.</p>
9 <h2>Использование сеттеров</h2>
9 <h2>Использование сеттеров</h2>
10 <p>Следующий подход включает использование сеттеров, что позволяет изменять опции уже существующего объекта:</p>
10 <p>Следующий подход включает использование сеттеров, что позволяет изменять опции уже существующего объекта:</p>
11 <p>В данном случае мы начинаем с того же объекта Request, что и в предыдущем примере. Но теперь мы используем сеттер set_timeout(), чтобы изменить таймаут с одной до десяти секунд для этого объекта. Затем мы снова выполняем GET-запрос, и этот запрос теперь будет использовать новое значение таймаута.</p>
11 <p>В данном случае мы начинаем с того же объекта Request, что и в предыдущем примере. Но теперь мы используем сеттер set_timeout(), чтобы изменить таймаут с одной до десяти секунд для этого объекта. Затем мы снова выполняем GET-запрос, и этот запрос теперь будет использовать новое значение таймаута.</p>
12 <p>Изменяемое состояние - это одна из самых сложных концепций в программировании. Именно оно может привести к большинству проблем, с которыми сталкиваются программисты. Оно может создать трудноуловимые и опасные баги.</p>
12 <p>Изменяемое состояние - это одна из самых сложных концепций в программировании. Именно оно может привести к большинству проблем, с которыми сталкиваются программисты. Оно может создать трудноуловимые и опасные баги.</p>
13 <p>Объект request используется совместно всеми частями системы. Это означает, что его изменение в одном месте повлияет на все последующие вызовы.</p>
13 <p>Объект request используется совместно всеми частями системы. Это означает, что его изменение в одном месте повлияет на все последующие вызовы.</p>
14 <p>В реальной жизни такие вещи могут приводить к еще более серьезным последствиям. Допустим, мы работаем с классом MarkdownRenderer, который отвечает за рендеринг markdown в HTML. Этот класс имеет опцию sanitize, которая отвечает за включение или отключение безопасного рендеринга.</p>
14 <p>В реальной жизни такие вещи могут приводить к еще более серьезным последствиям. Допустим, мы работаем с классом MarkdownRenderer, который отвечает за рендеринг markdown в HTML. Этот класс имеет опцию sanitize, которая отвечает за включение или отключение безопасного рендеринга.</p>
15 <p>Если мы случайно отключим эту опцию, то теги &lt;script&gt;, вставленные в Markdown, отобразятся как есть. Это может быть допустимо для текста, который мы контролируем, например, для уроков на нашем сайте. Но это недопустимо для текста, введенного пользователями. Изменение опции sanitize в объекте MarkdownRenderer может создать уязвимость для<a>межсайтового скриптинга (XSS)</a>.</p>
15 <p>Если мы случайно отключим эту опцию, то теги &lt;script&gt;, вставленные в Markdown, отобразятся как есть. Это может быть допустимо для текста, который мы контролируем, например, для уроков на нашем сайте. Но это недопустимо для текста, введенного пользователями. Изменение опции sanitize в объекте MarkdownRenderer может создать уязвимость для<a>межсайтового скриптинга (XSS)</a>.</p>
16 <p>Чтобы избежать этого, мы можем попытаться вернуть опцию обратно после того, как мы ее изменили:</p>
16 <p>Чтобы избежать этого, мы можем попытаться вернуть опцию обратно после того, как мы ее изменили:</p>
17 <p>При этом программист может забыть это сделать. Код, в котором сначала что-то меняется в одну сторону, а затем возвращается обратно, почти всегда указывает на проблемы архитектуры. И существуют способы переписать его более безопасным образом.</p>
17 <p>При этом программист может забыть это сделать. Код, в котором сначала что-то меняется в одну сторону, а затем возвращается обратно, почти всегда указывает на проблемы архитектуры. И существуют способы переписать его более безопасным образом.</p>
18 <h2>Передача опций при каждом вызове</h2>
18 <h2>Передача опций при каждом вызове</h2>
19 <p>Лучшим решением данной проблемы может быть передача дополнительных параметров при каждом вызове метода:</p>
19 <p>Лучшим решением данной проблемы может быть передача дополнительных параметров при каждом вызове метода:</p>
20 <p>В данном случае во втором вызове метода get мы передаем дополнительный параметр timeout со значением 10. Это изменение затрагивает только данный вызов, а не весь объект request.</p>
20 <p>В данном случае во втором вызове метода get мы передаем дополнительный параметр timeout со значением 10. Это изменение затрагивает только данный вызов, а не весь объект request.</p>
21 <p>Таким образом, когда мы возвращаемся к третьему вызову метода get, первоначальное значение timeout (1) остается неизменным. Это предотвращает возможные проблемы, связанные с изменением состояния объекта. Еще это позволяет гибко управлять настройками для каждого вызова.</p>
21 <p>Таким образом, когда мы возвращаемся к третьему вызову метода get, первоначальное значение timeout (1) остается неизменным. Это предотвращает возможные проблемы, связанные с изменением состояния объекта. Еще это позволяет гибко управлять настройками для каждого вызова.</p>
22 <h2>Выводы</h2>
22 <h2>Выводы</h2>
23 <p>В этом уроке мы обсудили различные подходы к управлению настройками объекта: от создания нового объекта до использования сеттеров и передачи дополнительных параметров при каждом вызове метода. Передача опций при каждом вызове - наиболее предпочтительный подход, так как он избегает проблем, связанных с изменяемым состоянием, и позволяет сохранять гибкость кода.</p>
23 <p>В этом уроке мы обсудили различные подходы к управлению настройками объекта: от создания нового объекта до использования сеттеров и передачи дополнительных параметров при каждом вызове метода. Передача опций при каждом вызове - наиболее предпочтительный подход, так как он избегает проблем, связанных с изменяемым состоянием, и позволяет сохранять гибкость кода.</p>