Протокол HTTP и работа с заголовками
Протокол HTTP
Как работает WWW (всемирная паутина, веб) в двух словах:
Иными словами, весь современный веб построен на модели клиент-серверного взаимодействия. И чтобы весь этот процесс оказался возможным, необходим универсальный язык-протокол, который будет понимать и сервер, и браузер. Такой протокол есть, а называется он HTTP.
Как работает HTTP, и зачем нам это знать
Программировать на PHP можно и без знания протокола HTTP, но есть ряд ситуаций, когда для решения задач нужно знать, как именно работает веб-сервер. Ведь PHP — это, в первую очередь, серверный язык программирования.
Протокол HTTP очень прост и состоит, по сути, из двух частей:
Сначала идёт список заголовков, затем пустая строка, а затем (если есть) тело запроса/ответа.
И клиент, и сервер могут посылать друг другу заголовки и тело ответа, но в случае с клиентом доступные заголовки будут одни, а с сервером — другие. Рассмотрим пошагово, как будет выглядеть работа по протоколу HTTP в случае, когда пользователь хочет загрузить главную страницу социальной сети «Вконтакте».
1. Браузер пользователя устанавливает соединение с сервером vk.com и отправляет следующий запрос:
2. Сервер принимает запрос и отправляет ответ:
3. Браузер принимает ответ и показывает готовую страницу
Больше всего нам интересен самый первый шаг, где браузер инициирует запрос к серверу vk.com
Рассмотрим подробнее, что там происходит. Первая строка запроса определяет несколько важных параметров, а именно:
GET — это метод (глагол), который мы применяем для доступа к указанной странице.
GET является самым часто используемым методом, потому что он говорит серверу о том, что клиент всего лишь хочет прочитать указанный документ. Но помимо GET есть и другие методы, один из них мы рассмотрим уже в следующем разделе.
Больше всего здесь интересен именно код состояния, он же код ответа сервера.
В этом примере код ответа — 200, что означает: сервер работает, документ найден и будет передан клиенту. Но не всегда всё идет гладко.
Например, запрошенный документ может отсутствовать или сервер будет перегружен, в таком случае клиент не получит контент, а код ответа будет отличным от 200.
Спецификация HTTP 1.1 определяет 40 различных кодов HTTP.
После стартовой строки следуют заголовки, а затем тело ответа.
Работа с заголовками в PHP
В PHP есть все возможности для взаимодействия с протоколом HTTP:
Разберём всё по порядку.
Получение тела запроса
Получение заголовков запроса
Пример, как получить предыдущую страницу, с которой перешёл пользователь:
Добавление/изменение заголовков ответа
В PHP-сценарии можно управлять всеми заголовками ответа, которые попадут к пользователю вместе с контентом страницы. Это возможно, потому что PHP работает на стороне веб-сервера и имеет с ним очень тесную интеграцию.
Вот примеры сценариев, когда пригодится управление заголовками ответа:
Управление телом ответа
Параметры запроса
На сайте дневника наблюдений за погодой мы сделали отдельную страницу, чтобы показывать на ней информацию о погоде из истории за один конкретный день. То есть страница одна, но показывает разные данные, в зависимости от выбранного дня.
Также пользователи хотят добавить в закладки адреса страниц с нужными им днями. Получается, что имея только один сценарий сделать страницу, способную показывать дневник погоды за любой день невозможно? Вовсе нет!
Из чего состоит URI
URI — это уникальный идентификатор ресурса. Ресурс в нашем случае — это полный путь до страницы сайта. И вот как может выглядеть ресурс для показа погоды за конкретный день:
http://weather-diary.ru/day.php?date=2017-10-15
В примере выше указывается два аргумента: дата и единица измерения температуры.
Параметры запроса как внешние переменные
Теперь в адресе страницы используются параметры запроса, но какая нам от этого польза? Она состоит в том, что если имя страницы вызывает к исполнению соответствующий PHP-сценарий, то параметры запроса превращаются в специальные внешние переменные в этом сценарии. То есть, если в адресе присутствуют такие параметры, то их легко получить внутри кода сценария и выполнить с ними какие-нибудь действия. Например, показать погоду за конкретный день в выбранных единицах измерения.
Получение параметров запроса
Формирование URI с параметрами запроса
Иногда нужно совершить обратную операцию: сформировать адрес страницы, включив туда нужные параметры запроса из массива.
Скажем, на странице погодного дневника надо поставить ссылку на следующий и предыдущий день. Нужно также сохранить выбранную единицу измерений. То есть необходимо сохранить текущие параметры запроса, поменять значение одного из них (день), и сформировать новую ссылку.
Вот как это можно сделать:
Здесь мы использовали две функции:
[Перевод] Магические методы в PHP
Если Вы когда-нибудь изучали PHP-код открытых проектов, то вы могли встречать методы, начинающиеся с двойного подчеркивания. Это и есть те самые магические методы, с помощью которых вы сможете определить поведение вашего объекта при различных манипуляциях с его экземпляром.
Предполагаю, что вы уже сталкивались с некоторыми из них, ведь существуют довольно распространенные методы, и тем не менее, я считаю, что компетентному программисту PHP необходимо уверенное владение всеми возможностями языка.
Я думаю, это можно считать, своего рода, отправной точкой в мир Магических методов.
Приступая к изучению
Когда я сам изучал этот материал, я использовал всевозможные учебники и статьи, в которых излагались довольно глупые или вообще бесполезные примеры. Я считаю, что для того чтобы понять что-то нужно попробовать это в контексте реальной задачи. Именно с этого мы и начнем.
Представим себе, что мы хотим получать все твиты, при помощи Tweeter Api. Мы получаем JSON всех твитов текущего пользователя и хотим превратить каждый твит в объект с методами, которые позволят проводить определенные операции.
Ниже, я представил базовый класс Tweet:
Теперь, когда мы создали объект, мы можем приступать к изучению самих методов. (Прим. переводчика — некоторые конструкции будут иногда опускаться, чтобы акцентировать на роли и возможностях каждого метода)
Конструкторы и Деструкторы
Пожалуй, одним из самых наиболее распространенных магических методов является конструктор ( __construct() ). Если вы достаточно внимательно следили за созданием приложения Cribbb в моем блоге, вы достаточно осведомлены об этом методе.
Метод __construct() автоматически вызывается, когда был создан экземпляр объекта. В нем вы можете задать начальные свойства объекта или установить зависимости.
Когда мы создаем экземпляр класса Tweet, мы можем передать параметры, которые поступят в метод __construct(). Из примера выше, вы можете видеть, что мы не вызываем этот метод и не должны вызывать — он вызывается автоматически.
Со временем у вас возникнет необходимость расширение класса путем его наследования. Иногда родительский класс так же имеет метод __construct(), который совершает определенные действия, таким образом чтобы не потерять функционал класса-родителя, нужно вызвать и его конструктор.
При попытке удалить объект будет вызван метод __destruct(). Опять же, по аналогии с конструктором — это не то что нужно вызывать, ведь PHP все сделает за вас. Этот метод позволит вам очистить все, что вы использовали в объекте, например соединение с базой данных.
Если быть честным, то большую часть метода __destruct(), изложенного выше я скрыл от вас. PHP на самом деле не из тех языков, где процесс будет существовать достаточно длительное время, так что я не думаю, что у вас будет что-либо для чего мог бы понадобиться деструктор. Сам по себе жизненный цикл запроса в PHP настолько мал, что от данного метода будет скорее больше хлопот, чем пользы.
Геттеры и сеттеры
Когда вы работаете с обьектами в PHP, вам бы очень хотелось обращаться к свойствам объекта как-то так:
Однако, если у свойства text установлен модификатор доступа protected, то такое обращение вызовет ошибку.
Магический метод __get() будет отлавливать обращения к любым не публичным свойствам.
Метод __get() приминает имя свойства, к которому вы обращаетесь, в качестве аргумента. В приведенном выше примере сначала проверяется существование свойства в объекте и если оно существует, то возвращается его значение.
Как и в примерах выше — вы не должны вызывать этот метод напрямую, PHP будет вызывать его каждый раз, при попытке получения доступа к не публичным свойствам класса.
В обратной ситуации — если вы попытаетесь установить значение свойства, которое не является публичным — вы получите ошибку. И опять же, в PHP есть свой метод, который будет вызван при попытке установить в не публичное поле какое-либо значение. Данный метод принимает 2 параметра в качестве аргументов — свойство, в которое хотели записать значение, и само значение.
Если вы хотите использовать данный метод, ваш класс получит свойство, на подобии этого:
В приведенных выше примерах я показал как можно получить или установить значения свойств, не имеющих модификатор доступа public. Однако работа с данными магическими методами не всегда будет лучшей идеей. Гораздо лучше иметь множество методов для получения и записи свойств, так как в этом случае они формируют определенный API и это означает, что при изменении способа хранения или обработки ваш код не будет сломан.
Впрочем, вы все равно иногда будете встречать методы __get() и __set(), которые принято называть геттерами и сеттерами соотвественно. Это довольно хорошее решение, если вы решили изменить какое-либо значение или добавить немножко бизнес-логики.
Проверка свойства на существование
Если вы знакомы с PHP, вы скорее всего знаете о существовании функции isset(), которую обычно применяют при работе с массивами. Вы так же можете использовать эту функцию, для того чтобы понять — задано свойство в обьекте или нет. Вы сможете определить магический метод __isset(), для того чтобы можно проверять не только общедоступные свойства, но и другие.
Как вы видите выше, __isset() метод отслеживает вызов функции на проверку существования и получает в качестве аргумента — название свойства. В свою очередь, в методе вы можете использовать функцию isset(), для проверки существования.
Очистка переменной
По аналогии с функцией isset(), функция unset() обычно используется при работе с массивами. Опять же, вы можете использовать функцию unset() для того чтобы очистить значение не публичного свойства. Чтобы применить данный метод на не публичные свойства, вам понадобиться метод __unset(), который будет отслеживать попытки очистить не публичный свойства класса.
Приведение к строке
Метод __toString() позволит вам определить логику работы вашего приложения, при попытке привести обьект к типу строке.
Например:
Можно сказать, что когда вы пытаетесь обратиться к обьекту, как к строке, например при использовании echo, обьект будет возвращен так, как вы определите в __toString() методе.
Хорошей иллюстрацией в данном случае может случить Eloquent Models из фреймворка Laravel. При попытке приведения обьекта к строке вы получите json. Если вы хотите увидеть как Laravel это делает, рекомендую обратиться к исходному коду.
Сон и пробуждение
Функция сериализации ( serialize() ), является довольно распространенным способом хранения обьекта. Например, если бы вы хотели сохранить обьект в базе данных, для начала вы должны были бы его сериализовать, затем сохранить, а когда бы он вам потребовался снова, вы должны были бы его получить и десериализовать ( unserialise() ).
Метод __sleep(), позволяет определить какие свойства должны быть сохранены. Если бы мы к примеру, не хотели сохранять какие-либо связи или внешние ресурсы.
Представим себе, что когда мы создаем обьект, мы хотим определить механизм его сохранения.
Когда мы готовим к сохранению обьект, нам естественно не нужно сохранить подключение к базе данных, ведь в будущем это будет бессмысленно.
Поэтому в методе __sleep() мы определим массив свойств, которые должны быть сохранены.
А после того как настанет время для пробуждения обьекта, нам могут понадобиться все то, что мы не сохранили при сериализации. В конкретном примере нам нужно установить соединение с базой данных. Это можно сделать, при помощи магического метода __wakeup().
Вызов методов
Магический метод __call(), будет перехватывать все попытки вызовов методов, не являющихся публичными. Например, у вас может быть массив данных, которые вы хотите изменить:
Еще один типичный пример это использование другого публичного API в своем обьекте.
В приведенном выше примере, мы можем вызвать метод getLocation на обьекте класса Tweet, но на самом деле мы его делегируем классу Location.
Если вы пытаетесь вызвать статический метод, вы можете так же воспользоваться __callStatic() магическим методом. Главное помните, что работает он лишь при вызове статичных методов.
Клонирование
Когда вы создаете копию объекта в PHP, по факту в переменную записывается не новый объект, а идентификатор, ссылающийся на оригинальный обьект. То есть любое изменение в ссылающимся объекте влечет за собой изменение первоначального объекта, однако удаление любого из объектов не повлияет на существование других:
Для того чтобы создать копию обьекта вам следует использовать ключевое слово clone.
Однако, если у нас есть несколько связанных обьектов, зависимости, которые находятся в них, так же будут скопированы.
Для того чтобы решить данную проблему мы можем определить метод __clone() для того чтобы определить правильное поведение:
Вызов обьекта как функции
Магический метод __invoke() позволяет определить логику работы обьекта, при попытке обратиться к обьекту как к функции.
Заключение
Как вы могли уже убедиться, PHP использует магические методы для реагирования на те или иные действия с методами или свойствами обьекта. Каждый из данных методов срабатывает автоматически, вы просто определяете что должно произойти, а об остальном позаботиться PHP.
В течении довольно длительного времени я не понимал истинного значения магических методов. Я думал, что они нужны, лишь для того чтобы делать какие-либо интересные вещи с обьектами. И когда я, наконец, понял их истинное предназначение, я смог писать более мощные обьекты в рамках более серьезных приложений.
Надеюсь, что в каждом из примеров, представленных в этом руководстве, я смог показать как магические методы могут помочь в повседневных задачах. И я буду не первым кто согласиться, что когда вам обьясняют какой-либо материал, но не обьясняют его практическое применение это реально раздражает.
Статические свойства и методы в PHP
Очень важной особенностью ООП является наличие статических свойств и методов. Главное, что необходимо сразу понять, что такие свойства и методы принадлежат не объекту, а классу. Это нужно понять с самого начала, а вот применение статических свойств и методов в PHP я рассмотрю в этой статье.
Давайте мы с Вами напишем уменьшенную копию данного класса, но только для PHP:
В данном коде я показал использование статических методов и свойств. Обратите внимание, что я реализовал классический способ счётчика объектов. Это получилось лишь благодаря тому, что поле count является статическим, и оно имеет одно и то же значение для всех объектов.
Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!
Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.
Если Вы не хотите пропустить новые материалы на сайте,
то Вы можете подписаться на обновления: Подписаться на обновления
Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.
Порекомендуйте эту статью друзьям:
Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):
Комментарии ( 4 ):
Уважаемый Михаил Русаков.Я не могу зайти к вам на страницу вконтакте и на ваш сайт ТНТ который вы зарегистрировали в интернете.По причине того что у меня стоит родительский контроль он ваши сайты считает сайтами для взрослых но он не только считает эти сайты взрослыми.free php hosting тоже считает таки.Пожалуйста свяжитесь со мной мой e-mail адрес dom.no.vlad@yandex.ru
Используйте анонимайзер для входа: http://anonymizer.ru/ или http://cameleo.ru/
Михаил Русаков спасибо вам огромное что вы не отказали мне в помощи,но для чего нужен сайт http://cameleo.ru/? он пишется как не рекомендуемый сайт.
Это анонимайзер, чтобы заходить на те сайты, которые с Вашего компьютера посещать нельзя.
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.
Copyright © 2010-2021 Русаков Михаил Юрьевич. Все права защищены.
Готовимся к собеседованию по PHP: ключевое слово «static»
Не секрет, что на собеседованиях любят задавать каверзные вопросы. Не всегда адекватные, не всегда имеющие отношение к реальности, но факт остается фактом — задают. Конечно, вопрос вопросу рознь, и иногда вопрос, на первый взгляд кажущийся вам дурацким, на самом деле направлен на проверку того, насколько хорошо вы знаете язык, на котором пишете.
Попробуем разобрать «по косточкам» один из таких вопросов — что значит слово «static» в PHP и зачем оно применяется?
Ключевое слово static имеет в PHP три различных значения. Разберем их в хронологическом порядке, как они появлялись в языке.
Значение первое — статическая локальная переменная
Однако всё меняется, если мы перед присваиванием поставим ключевое слово static:
Подводные камни статических переменных
Разумеется, как всегда в PHP, не обходится без «подводных камней».
Камень первый — статической переменной присваивать можно только константы или константные выражения. Вот такой код:
с неизбежностью приведет к ошибке парсера. К счастью, начиная с версии 5.6 стало допустимым присвоение не только констант, но и константных выражений (например — «1+2» или «[1, 2, 3]»), то есть таких выражений, которые не зависят от другого кода и могут быть вычислены на этапе компиляции
Камень второй — методы существуют в единственном экземпляре.
Тут всё чуть сложнее. Для понимания сути приведу код:
Такое поведение может быть неожиданным для неподготовленного к нему разработчика и послужить источником ошибок. Нужно заметить, что наследование класса (и метода) приводит к тому, что всё-таки создается новый метод:
Вывод: динамические методы в PHP существуют в контексте классов, а не объектов. И только лишь в рантайме происходит подстановка «$this = текущий_объект»
Значение второе — статические свойства и методы классов
В объектной модели PHP существует возможность задавать свойства и методы не только для объектов — экземпляров класса, но и для класса в целом. Для этого тоже служит ключевое слово static:
Для доступа к таким свойствам и методам используются конструкции с двойным двоеточием («Paamayim Nekudotayim»), такие как ИМЯ_КЛАССА::$имяПеременной и ИМЯ_КЛАССА:: имяМетода().
Само собой разумеется, что у статических свойств и статических методов есть свои особенности и свои «подводные камни», которые нужно знать.
Особенность вторая — static не аксиома!
Обратное не совсем верно:
И кстати, всё написанное выше относится только к методам. Использование статического свойства через «->» невозможно и ведет к фатальной ошибке.
Значение третье, кажущееся самым сложным — позднее статическое связывание
Разработчики языка PHP не остановились на двух значениях ключевого слова «static» и в версии 5.3 добавили еще одну «фичу» языка, которая реализована тем же самым словом! Она называется «позднее статическое связывание» или LSB (Late Static Binding).
Понять суть LSB проще всего на несложных примерах:
Ключевое слово self в PHP всегда значит «имя класса, где это слово написано». В данном случае self заменяется на класс Model, а self::$table — на Model::$table.
Такая языковая возможность называется «ранним статическим связыванием». Почему ранним? Потому что связывание self и конкретного имени класса происходит не в рантайме, а на более ранних этапах — парсинга и компиляции кода. Ну а «статическое» — потому что речь идет о статических свойствах и методах.
Немного изменим наш код:
Теперь вы понимаете, почему PHP ведёт себя в этой ситуации неинтуитивно. self был связан с классом Model тогда, когда о классе User еще ничего не было известно, поэтому и указывает на Model.
Для решения этой дилеммы был придуман механизм связывания «позднего», на этапе рантайма. Работает он очень просто — достаточно вместо слова «self» написать «static» и связь будет установлена с тем классом, который вызывает данный код, а не с тем, где он написан:
Это и есть загадочное «позднее статическое связывание».
Нужно отметить, что для большего удобства в PHP кроме слова «static» есть еще специальная функция get_called_class(), которая сообщит вам — в контексте какого класса в данный момент работает ваш код.
Ключевое слово static в PHP
Nov 24, 2019 · 4 min read
Сигнатура метода
Эту логику можно извлечь в отдельный класс, который известен как шаблон проектирования статическая фабрика (Static Factory):
Свойства
В отличие от обычных свойств, изменение значения статического свойства во время выполнения программы повлияет на все экземпляры содержащего свойство класса. Даже на те, для которых еще не созданы экземпляры. Таким образом, статические свойства можно рассматривать в качестве “констант изменяемого класса”. На статические свойства можно ссылаться только с помощью оператора разрешения области видимости.
Благодаря природе статических свойств их можно использовать для реализации шаблона одиночка (Singleton). Одиночка содержит один и тот же экземпляр класса на протяжении всего выполнения программы.
Переменные
В контексте статической функции переменные сохраняют свое значение даже после выхода программы из области видимости содержащей их функции. В контексте метода класса статические переменные обладают дополнительным поведением, подобным статическим свойствам: изменения их значений отражаются во всех экземплярах класса. Несмотря на схожесть со статическими свойствами, статические переменные доступны только в теле функции или метода.
Статические переменные часто используются в технике оптимизации под названием мемоизация. Ее целью является ускорение дорогостоящей операции за счет кэширования результатов и сохранения их для последующего вызова с теми же параметрами.
Анонимные функции
Статические анонимные функции не обладают такой широтой вариантов использования, как обычные анонимные функции. Стоит отметить, что статические анонимные функции немного улучшают производительность и могут использоваться в любых экземплярах при отсутствии необходимости привязки содержащего класса к анонимной функции.
Позднее статическое связывание
Позднее статическое связывание демонстрирует другой вариант использования ключевого слова static : в контексте наследования. В этом контексте static относится к вызываемому классу, а не к тому, для которого был определен метод: на него, в свою очередь, будет ссылаться self или __CLASS__ :
Заключение
Мы рассмотрели несколько примеров использования ключевого слова static в PHP. Хотя сценарии использования умозрительны, они очень реалистичны. Польза, которую они могут принести вашему коду, может быть огромной. По крайней мере, знакомство с этими способами использования static сделает вас сильным разработчиком.



