Проблема с serialize и __sleep

Как всем наверное известно в РНР5 перед сериализацией объекта вызывается __sleep.
В исходном коде движка ни одного слипа я не нашел. Но, что происходит внутри — удивляемся:
Дело в кеше доходит до сериализации и вызывается __sleep, функции, которой в ни в одном классе нет.
После этого делается TopicEntity_Topic->__call('__sleep', Array) — видимо где-то стоит какой-то хук на вызов неизвестных функций. И пошло-поехало —

	/**
	 * Ставим хук на вызов неизвестного метода и считаем что хотели вызвать метод какого либо модуля
	 */
	public function __call($sName,$aArgs) {
		return $this->oEngine->_CallModule($sName,$aArgs);
	}

Модуль не находится, лезут ошибки, эксепшены и т.п.
Вопрос — как на PHP5 нормально настроить кеширование? Как убрать все эти псевдо-нужные хуки (а они видимо здорово по коду раскиданы)?

Ниже собственно трасер ошибки:

<b>Fatal error</b>:  Uncaught exception 'Exception' with message 'Не найден класс модуля - ' in /var/www/web674/web/classes/engine/Engine.class.php:97
Stack trace:
#0 /var/www/web674/web/classes/engine/Engine.class.php(97): Engine::LoadModule()
#1 /var/www/web674/web/classes/engine/Engine.class.php(185): Engine->LoadModule('', true)
#2 /var/www/web674/web/classes/engine/Entity.class.php(61): Engine->_CallModule('__sleep', Array)
#3 /var/www/web674/web/classes/modules/sys_cache/Cache.class.php(129): TopicEntity_Topic->__call('__sleep', Array)
#4 /var/www/web674/web/classes/modules/sys_cache/Cache.class.php(129): TopicEntity_Topic->__sleep()
#5 /var/www/web674/web/classes/modules/sys_cache/Cache.class.php(129): serialize(Array)
#6 /var/www/web674/web/classes/engine/Engine.class.php(189) : eval()'d code(1): LsCache->Set(Array, 'topic_filter_a:...', Array, 300)
#7 /var/www/web674/web/classes/engine/Engine.class.php(189): eval()
#8 /var/www/web674/web/classes/engine/Module.class.php(37): Engine->_CallModule('Cache_S in <b>/var/www/web674/web/classes/engine/Engine.class.php</b> on line <b>97</b><br />

16 комментариев

avatar
проблема в чем?
Как всем наверное известно в РНР5 перед сериализацией объекта вызывается __sleep.

Дело в кеше доходит до сериализации и вызывается __sleep

__sleep вызывает только тогда, кода этот метод существует в классе, это наверно тоже всем известно
  • ort
  • 0
avatar
Кеширования данных мало, есть желание кешировать конкретные экземпляры объектов?
avatar
собственно объекты в движке и кешируются
avatar
Разве? Глубоко не копал, конечно, но мне казалось, что кешируются наборы данных, массивы.
avatar
массивы(и то не везде), а элементы его — объекты
avatar
Вопрос — как на PHP5 нормально настроить кеширование?


Учтите, что PHP5 не имеет нативного механизма кеширования. Любое кеширование, которое вы используете, создается с помощью: стандартных средств языка — чтение/запись файлов, либо интерфейса доступа (читай api) к специализированным программам кеширования данных (например, memcached). Поэтому ваш вопрос не очень понятен — разрабатывайте механизм (алгоритм) кеширования, если предложенный вас не устраивает, и формализуйте это в PHP5 код.

Как убрать все эти псевдо-нужные хуки (а они видимо здорово по коду раскиданы)?

Эти «псевдо-нужные», как вы выразились, хуки нужны для того, чтобы вызывать из любого action`a функции любого модуля. Например, экшн топика получает пользователя $this->User_GetUserById($sId) ну и дальше по сценарию. Но ведь, нельзя «зашить» все эти методы прямо в класс Engine, так как мы потеряем масштабируемость. Для перенаправления вызова используется магический метод __call.

Если такой подход вас не устраивает — могу предложить zend-стандарт, который часто используется при проектировании архитектуры с использованием Zend Framework — вы делаете основные функции модели статическими. И тогда обращаетесь к ним так: UserModel::GetUserById(). Плюсы и минусы статических вызовов — отдельная история и в комментарий не поместиться.
avatar
Насчет кэширования — я в курсе, это не средство языка.
Но проблему мою Вы, как человек несомненно понимающий, осознали — вместо обычной сериализации объекта вызывается слип (что нормально), дальше этот слип не находится в методах класса и вызывается как модуль (что видимо логично для движка ЛС).
Вопрос: изначально предусмотренную в движке возможность кеширования посредством файлов как-то можно сделать рабочей на хосте с PHP 5+?

А насчет хуков мне действительно пока непонятно… Постараюсь разобраться
avatar
слип не находится в методах класса и вызывается как модуль

Вы уверены? Не определение __sleep в классе не должно приводить к ошибке. Так как это магический метод, и выполняется только тогда, когда он определен.

Вопрос: изначально предусмотренную в движке возможность кеширования посредством файлов как-то можно сделать рабочей на хосте с PHP 5+?

У меня на сервере стоит 5.3.0 — полет нормальный :)
avatar
Вот именно это меня и удивляет! Большое спасибо, что действительно пытаетесь помочь.
Действительно ни одного упоминания о __sleep || __wakeup в коде нет, но почему происходит следующее:
Вполне логичный вызов
TopicEntity_Topic->__sleep()
TopicEntity_Topic->__call('__sleep', Array)

перед сериализацией.
И опаньки (странная вещь!):
Engine->_CallModule('__sleep', Array)

стоит вполне обычный классический пхп 5.0.4, честное слово классы не трогал :) Только шаблоны немного
avatar
Не знаю, почему у вас так происходит, и, к сожалению, негде проверить. Сделайте «костыль». Тупо, конечно, но должно в вашем случае помочь — дополните определение той функции, о которой вы писали в топике до такого:

public function __call($sName,$aArgs) {
    if(substr($sName, 0, 2)!='__')   
        return $this->oEngine->_CallModule($sName,$aArgs);
}

Сейчас негде проверить, но по идее это должно предотвратить перенаправления при обращении к магическим методам.
avatar
Спасибо большое! Как-то до __call я не добирался, я все больше пытался забраться в абстракции повыше (намример до класса Object) и там метод __sleep сделать.
Еще раз спасибо!
avatar
Если будете делать __sleep, то помните — он должен вернуть все сериализируемые переменные. Если __sleep вернет null или false, то сериализация не пройдет — так как интерпритатор посчитает, что объект уже серриализован.
avatar
Вот поэтому я и обратился с вопросом на сайт — со __sleep есть тонкости — например, уверяют люди в комментариях на php.net, для прайват свойств нужно возвращать их обязательно с именем класса.
В общем я отказался от гиблой идеи реализовать свой глобальный слип.
avatar
:) Разбирайтесь понемногу. Это действительно сложные вопросы.
Буду рад если мои советы чем-то вам помогли!

P.S. а коммент мой все равно заминусовали, странные тут порядки.
avatar
Хм, а я думал — Вы в core-team состоите, уж больно хорошо все знаете.
avatar
:) Неа, я просто веб-разработчик — фрилансер, который кучу заданий уже по этому движку выполнил. Да и с PHP5 давно общаюсь.
А за комплимент спасибо, это редкость в наших кругах.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.