LINUX.ORG.RU

PHP < 5.3 и get_called_class(). В продолжение старого спора. Нужен концептуальный совет.


0

0

В продолжение старого спора о ненужности get_called_class() для статических методов.

Вот уткнулся в практическую задачу.

Есть понятие очереди запросов на изменение объектов. Есть базовый класс фреймворка bors_object_change_request. Есть его наследник в проекте - aviaport_object_change_request extends bors_object_change_request. Фактически наследник - это просто настроенный базовый класс, в котором прописано, какой БД и какой таблицей он должен пользоваться (в системе может быть более одного проекта, данные разных проектов должны взаимодействовать, но не конфликтовать).

Есть статический метод быстрого добавления запроса на изменение свойства объекта:

static function add($target, $property, $value, $user);
И вот тут наступает облом. Я не могу наследовать этот метод. Внутри происходит создание объекта = записи в БД, экземпляра нашего класса. Но какого? Пока нет get_called_class(), я могу создавать только записи для базового класса. Имя класса-наследника мне неизвестно.

Приходится лепить костыль. В базовом классе определять:

static function add($target, $property, $value, $user, $self_class_name);
В наследнике определять метод-заглушку:
static function add($target, $property, $value, $user) { return parent::add($target, $property, $value, $user, 'aviaport_object_change_request'); }
В общем - костыль.

Есть мысли, как без него обойтись, кроме как ждать повсеместного перехода на PHP 5.3?

★★★★★

Ответ на: комментарий от anonymous

почему метод статический?

Чтобы добавлять новую запись как

aviaport_object_change_request::add(...);
а не как
$tmp = new aviaport_object_change_request();
$tmp->add(...);

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Дело даже не в синтаксисе, а в самой логике. Вместо простого одношагового создания объекта с занесением его в БД имеем, как минимум, три шага - создание пустого объекта, наполнение его данными, сохранением его в БД. Или двух шагов, но ещё менее логичных - создание пустого объекта только для того, чтобы потом в один шаг создать уже заполненный объект.

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

> три шага - создание пустого объекта, наполнение его данными, сохранением его в БД.

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

isden ★★★★★
()
Ответ на: комментарий от isden

>а может быть просто запихать все это в конструктор?

Придётся в итоге делать слишком умный конструктор (слишком много вариантов инициализации и действий). Идёт вразрез с принципом KISS :)

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

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

ок, тогда обертку над new, и вызывать вроде того:

func_new(«class_name»);

если я правильно понял суть проблемы :)

isden ★★★★★
()
Ответ на: комментарий от isden

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

isden ★★★★★
()
Ответ на: комментарий от isden

>func_new(«class_name»);

У меня и есть для этого. object_new($class_name) и object_new_instance($class_name).

если я правильно понял суть проблемы :)


Не-а. Для упомянутых выше object_new* методов нужны дополнительно подготовленные данные. Ну, там, из объекта, модификация которого становится в очередь, извлечь имя класса и id объекта, данные, если их много, привести к единому формату - json и т.д.

Вот этим функции add* и занимаются.

Пока лучшее, что придумал - делать именно обёртку с переопределением функции в классе. Когда 5.3 станет всюду повсеместным, их можно будет просто выкинуть, ничего не переписывая, кроме add*() в базовых классах. Но это всё равно костыль, хоть и менее костыльный, чем альтернативы, которые я вижу.

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от isden

>а вообще, имхо правильнее делать базовый класс, в нем конструктор с минимальными необходимыми действиями для инициализации

Я выше писал, что конструкторы вообще почти не трогаю. Если через них всё делать - то конструктор сильно усложняется. А он должен быть максимально простой и быстрый. Скажем, у меня идёт ORM-загрузка 1000 объектов в цикле из mysql-хранилища. Если без всяких извращений, типа постобработки данных, то цикл предельно простой. Делаем mysql_fetch_array(), извлекая хэш с данными. Создаём новый объект. Записываем в свойство объекта data полученный хэш (присваиваем ссылку). Всё, объект готов. Если же будет сложный конструктор, то там каждая примитивная проверка уже ударит заметно по производительности.

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

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

> Придётся в итоге делать слишком умный конструктор (слишком много вариантов инициализации и действий). Идёт вразрез с принципом KISS :)

Ваша любовь лизать яйца от нечего делать - идет в ещё больший вразрез с принципом KISS.

У меня и есть для этого. object_new($class_name) и object_new_instance($class_name).

Упаси боже так делать, разве код набирать в каком-нибудь фаре. Использование стандартных new и autoload дает возможность использовать современные IDE с их автодополнением, отслеживанием иерархии классов и т.п. Вашу же муть не возможно отследить, ибо это апофеоз пренебрежения типизацией.

Перестаньте экономить на строчках кода. Посмотрите как делаются _нормальные_ ООП фреймворки - Yii, ZF. Их удобно использовать людям с опытом, они сделаны стандартными способами.

Либо переходите уже на Perl и пишите всё в одну строчку, наслаждайтесь. Просто таки BDSM и некрофилия в одном флаконе.

PavelR
()
Ответ на: комментарий от KRoN73

>Вместо простого одношагового создания объекта с занесением его в БД имеем, как минимум, три шага - создание пустого объекта, наполнение его данными, сохранением его в БД

Не уловил, в чём разница, кроме длины клиентского кода.

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

>Не уловил, в чём разница, кроме длины клиентского кода.

Ну, например, если не нравится объяснение по поводу логичности, я позже давал объяснение по поводу сильной потери производительности :)

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

Я сейчас немного медленнее прочитал пост, поковырял. Короче, решение с обёрткой мне даже и костылём почти не кажется (но только почти). Но вот чего я не пойму, так это откуда взялись объекты? По сути bors_object_change_request - это неймспейс, ему и инстансы то не нужны. (кстати, подход, когда в php класс-по-сути-неймспейс-все-функции-статические используется то так, то эдак меня всегда жутко раздражал).

Асло, как же хорошо писать на плюсах - о производительности не нужно так много думать :)

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

>Асло, как же хорошо писать на плюсах - о производительности не нужно так много думать :)

Ой-ой-ой, вот где о производительности больше всего думал - так это когда на Плюсах писал. Соответствующий инструмент используется под соответствующие задачи. Мне скорости Си++ почти никогда не хватало. А вот на PHP - почти никогда ломать голову о скорости не приходится :D Задачи разные...

По сути bors_object_change_request - это неймспейс, ему и инстансы то не нужны


Ну как же не нужны. А пройтись по выборке объектов в цикле? «по сути неймспейс» (кстати, в любом случае, они в PHP только в 5.3 появились) - это когда в потрохах одна статика :)

...

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

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

>А вот на PHP - почти никогда ломать голову о скорости не приходится

Я про то, что в C++ есть inline, на который почти всегда можно твёрдо рассчитывать. Например, в таких врапперах.

Ну как же не нужны. А пройтись по выборке объектов в цикле?

Я не понимаю такую архитектуру. add(...) для работы не требует объект. Тогда что он делает? Пинает глобальный (фуууу :) ) или статический объект? А почему тогда add - не функция член этого статического?

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

>Я про то, что в C++ есть inline, на который почти всегда можно твёрдо рассчитывать

Да мало всё равно от него пользы было :)

Я не понимаю такую архитектуру. add(...) для работы не требует объект.


add - это да, статический метод. Но он создаёт конкретный объект своего типа. Нет смысла разделять статический метод, создающий объекты от класса объектов. Будет только создание лишних сущностей :)

KRoN73 ★★★★★
() автор топика
Ответ на: комментарий от KRoN73

>add - это да, статический метод. Но он создаёт конкретный объект своего типа.

Аааа! Так это по по сути перегрузка конструкторов для бедных :) Теперь понял.

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

>Аааа! Так это по по сути перегрузка конструкторов для бедных :)

Ну... Где-то можно и так назвать :) Только не перезагрузка (с ней-то в PHP всё хорошо), а полиморфизм.

KRoN73 ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.