Доменный роутинг для Symfony2

Вчера выложил в опен-сорс бандл для доменного роутинга для Symfony2.

https://github.com/megazoll/MegazollDomainedRoutingBundle

Мануал по установке есть на гитхабе, пожелания и баги можно заводить там же. Надеюсь это первый, но не последний проект с открытыми исходникам.

Объектный контекст в PHP

Недавно столкнулся с задачей вызвать в своем классе метод прародителя, минуя одноименный метод родителя. Кое-кто правильно подметил, что если встает такая задача, то что-то не так с архитектурой. Но оба родительских класса находились в сторонних бибиотеках, поэтому менять их код или копипастить их себе очень не хотелось. Решение должно было выглядеть примерно вот так:

parent::parent::method()

PHP естественно так не умеет, поэтому пришлось искать какие-то варианты. В каком-то треде на stackoverflow был предложен вариант:

Grandpa::method()

который сработал, что мне показалось странным — я считал что оператор :: это вызов статического метода. Пробуем разобраться:

Теперь видно что в методе A::test() доступна переменная $this, причем  она явно соответствует контексту объекта, из которого был вызван этот метод. Пробуем чуть более сложный пример:

Все логично, приватное поле перекрывает публичное поле родителя.

Из чего можно сделать что оператор :: это обычный callable, который получает доступ к контексту объекта, который вызывает этот метод. Сложилось мнение что это наследние PHP4. Наличие такой возможности не так уж и плохо, но в документации про это мало что написано, так что пришлось выяснять это опытным путем.

P.S. Пользуясь случаем передаю привет @DiVariable и @zryaneskazhev.

Работа с сессией в PHP не через стандартные настройки

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

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

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

(Проект написан на symfony 1.4, поэтому код будет оттуда)

$id = sfContext::getInstance()->getRequest()->getCookie($storage_param[‘session_name’]);
$data = $storage->getBackend()->get($id);

 PHP сохраняет сессию в сериализованном виде, но сериализует явно не функция serizlize():

login_ok|b:1;nome|s:4:”sica”;inteiro|i:34;

Оказывается для сериализации/десериализации сессий в php используются функции session_encode и session_decode. Но эти функции работают сразу с глобальным массивом $_SESSION, что нам не подходит, так как мы хотим иметь свою отдельную сессию. Поэтому мы напишем 2 своих костыля для этих функций которые будут работать с произвольными массивами:

/**
* Workaround for session_decode to return array
* instead of setting $_SESSION
*
* @param string $session_string
* @return array
*/
public static function decodeSession($session_string) {
$current_session = session_encode();
$_SESSION = array();

session_decode($session_string);
$restored_session = $_SESSION;

$_SESSION = array();
session_decode($current_session);
return $restored_session;
}

public static function encodeSession($session) {
$current_session = $_SESSION;

$_SESSION = $session;
$session_encode = session_encode();

$_SESSION = $current_session;
return $session_encode;
}

Собственно говоря все, теперь мы можем получать из memcached сериализованную сессию, десериализовать её, получать/изменять нужные значения и засовывать её обратно в memcached.

$id = sfContext::getInstance()->getRequest()->getCookie($storage_param[‘session_name’]);
$data = $storage->getBackend()->get($id);
$session = self::decodeSession($data);
if ($user_id) {
  $session[‘USERID’] = $user_id;
} else {
  unset($session[‘USERID’]);
}
  $storage->getBackend()->set($id, self::encodeSession($session));

P.S. Нативной подсветки кода тут нет, как прикручу, поменяю листинги.