Pull to refresh

Comments 102

>> Чтобы не возникало путаницы
Вот, золотые слова.

При всём при том, что PHP мой основной язык, я жду двух вещей от типажей:
* Новый тип говнокода с типажами, в котором будет сложно разобраться.
* Малая распространённость типажей, ибо не понятно зачем они нужны (для множественного наследования говорите? Как часто это вам надо?).

Ну понятно что для движка хоумпэйджа Васи Пупкина типажи не нужны. А вот для всяческих CRM,ERP (и т.п.) систем — очень даже надо. Конечно сейчас из этого добра мало что создается на PHP (процентов 20 от силы) — но так ведь развивается язык, типажи еще один шажок вперед.
Я думаю что многие бы предпочли увидеть другой «шажок вперёд» вместо типажей
что конкретно вам даст тот факт, что строки внутри будут храниться в UCS2?
увеличится скорость работы с ними? всё магически станет работать лучше?
это еще один чисто внутренний момент, который вас интересовать не должен.
Хотя бы то, что не нужно будет задумываться о том как называется та или иная функция, кроме того не для всех функций есть соответствующий аналог. Реальный пример — как вы сейчас получаете символ с определенной позицией из строки в UTF-8?
>Хотя бы то, что не нужно будет задумываться о том как называется та или иная функция
Т.е. при переходе на внутренний Unicode в мануал смотреть не надо будет?

>Реальный пример — как вы сейчас получаете символ с определенной позицией из строки в UTF-8?

$text = «тест»;
$second_utf8_symbol = substr($text, 1, 1);

Естественно, я предварительно добавляю это в конфиг:
mbstring.internal_encoding=utf8
mbstring.func_overload=2

А теперь давайте подумаем что реально получается при полном переходе на юникод внутри.
1) все операции со строками должны проходить через ICU (http://icu-project.org), которая отнюдь не самая быстрай библиотека в мире, в том числе и по объективным причинам — операции со строками замедляются и довольно чувствительно.
2) все хэш-лукапы, поиски методов в списках методов классов, поиски самих классов и т.п. тоже включают в себя операции сравнения строк, поэтому и они быстрее не станут.
3) поскольку юникод по определению больше размером, то и объемы потребляемой памяти растут.
4) массу уже существующего кода придется переписать из-за того, что люди изначально закладываются на тот факт, что строка это просто данные, а не корректная строка в определённой кодировке.
5) имеем массу веселья с кодировками:
— данные от юзера — в какой кодировке?
— текст скрипта — в какой кодировке?
— файловая система — в какой кодировке?
— вывод скрипта — в какой кодировке?
— данные в базе — в какой кодировке?
и т.д. и т.п.
Всё это надо привести к внутренней кодировке ICU, для всего этого нужны какие-то INI-опции.

При этом mbstring работает нормально, а есть еще и php.net/intl для более низкоуровневой работы с Юникодом.

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

Нет, я согласен, ПРАВИЛЬНО было бы именно так. Но действительность говорит сама за себя — на нативную поддержку Unicode сейчас нет спроса. Был бы спрос — уже бы всё сделали.

И да, если вам надо и вы готовы — я могу вам помочь со стартом, нет проблем.
> $second_utf8_symbol
А если нужен 10 символов? Или все символы в строке? Регекспы нам помогут?

Я бы предпочел нативную поддержку [].

> А теперь давайте подумаем
1) Почему именно должны? неужели нет ни одной альтернативы?

2) Не верю что это нельзя оптимизировать. Кэширование байткода разве не решает проблему?

3) В данном временном промежутке это не проблема (память копейки стоит), в тоже время вы упускаете тот факт, что всякие костыли типа регекпов для получения массивов символов также требую памяти и времени.

4) Ничего не придется переписывать, проблемы могут быть только в том, случае, если вы решитесь обновить древний скрипт работающий на древней версии PHP да еще и сохранённый в CP1251. Вот только зачем ему современные плюшки?

В нормальных скриптах разницы не будет, ибо mb_* останется и продолжить работать как раньше, а str* или все также будут перекрываться mbstring.func_overload или начнут нормально работать и без этой настройки.

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

5) Браузер посылает данные в той же кодировке что и станица (у форм, кстати, есть атрибут accept-charset), про скрипты см. выше, вывод — отдельная настройка, БД все равно нужно указывать. Не вижу здесь каких либо серьезных проблем.

> Вот и приходим мы к тому, что толком это никому не нужно.

OpenSource, реализуется в первую очередь то, что хотят сами разработчики языка или за что им платят, поэтому данное высказывание не корректно, и, ИМХО, многим пишущим на PHP это нужно, другое дело, что за прошедшее время каждый из них уже реализовал необходимые функции (=костыли).

Вдогонку, наткнулся на старую презентацию: «Unicode & PHP6» (http://www.slideshare.net/kfish/unicode-php6-presentation), там есть решения некоторых проблем. Да и ранее достаточно активно велась работа на юникодом, текущую печальную ситуацию кто-то описывал на в одном из комментариев к какой-то статье, найти, к сожалению, так и не смог.
>А если нужен 10 символов?

Поменяйте параметр «длина» у функции.

>Или все символы в строке? Регекспы нам помогут?

Все символы в строке? $text — даю гарантию, что все символы в строке — в строке.

>1) Почему именно должны? неужели нет ни одной альтернативы?

Потому, что там наиболее полная поддержка юникода и эта либа — стандарт де-факто.
Вы же, наверное, и на частичной поддержке не остановитесь, да?

>2) Не верю что это нельзя оптимизировать. Кэширование байткода разве не решает проблему?

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

>3) В данном временном промежутке это не проблема (память копейки стоит),
>в тоже время вы упускаете тот факт, что всякие костыли типа регекпов для
> получения массивов символов также требую памяти и времени.

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

>4) Ничего не придется переписывать, проблемы могут быть только в том, случае,
>если вы решитесь обновить древний скрипт работающий на древней версии PHP

>В нормальных скриптах разницы не будет, ибо mb_* останется и продолжить
>работать как раньше, а str* или все также будут перекрываться
>mbstring.func_overload или начнут нормально работать и без этой настройки.

А вы попробуйте, исходники же есть: svn.php.net/viewvc/php/php-src/branches/FIRST_UNICODE_IMPLEMENTATION/

>OpenSource, реализуется в первую очередь то, что хотят сами разработчики языка
>или за что им платят, поэтому данное высказывание не корректно, и, ИМХО,
>многим пишущим на PHP это нужно, другое дело, что за прошедшее время каждый
>из них уже реализовал необходимые функции (=костыли).

И судя по всему, они их устраивают, т.к. я именно про это и говорю — заинтересованных разработчиков нет (да и был один Змиевский по большому счету), а нанимать кого-то и платить за разработку никто не хочет. Вот это я и подразумеваю под «нет спроса».
> Поменяйте параметр «длина» у функции.
Вы не поняли, я про тот случай когда нужно преобразовать строку в массив символов, сейчас единственный способ это сделать — использование регеспов. Разве не костыль?

> А вы предлагаете всем пользователям принудительно докупить памяти.
Это все слова, как я понимаю, статистики по увеличению потребления памяти у вас нет? (у меня нет)

> А вы попробуйте
Нет, спасибо.

Если сами пробовали может быть поделитесь результатами?
Я сужу на основе своего опыта работы с PHP6 — я довольно много phpt-тестов под него правил и чуток участвовал в разработке.
Понятное дело, нигде в продакшене я его не поднимал.
unicode как описали ниже.
Упорядочивание каши с именами функций. и тэ дэ и тэ пэ
Давайте начнём упорядочивать кашу с C, на котором написан PHP.
O_CREAT — бардак! Где «E» на конце?
И надо не забыть сделать версию для camelCase-людей — oCreate, для ОО-людей — OpenAttributes::getInstance(O_CREATE), надо же учитывать эстетические вкусы всех.
Traits и mixins — дико полезные штуки, когда мы хотим сделать какое-то свойство (особенность), которую можно давать объектам. Напимер, в RoR через миксины сделаны расширения к моделям: можно к любой модели добавить какую-то опцию.

Но в PHP, как всегда, все сделано криво: нет функции, вызываемой при приаттачивании trait, нет возможности объекту опросить список своих trait. Соответственно, как наладить взаимодействие между базовым объектом и примесью, и как им узнать друг о друге, непонятно.
Что то похожее я видел в Yii, но там это называется Behaviors, и логика работы схожая.
Ага, очень удобная штука. Недостает только поддержки в IDE
ну IDE можно указать, через спец комментарии, как к примеру в NetBeans это делается
/* @var $varname ClassName */
Ключевое тут trait != mixin. Я не говорю, что примеси — плохо, я только говорю, что в PHP реализованы именно трейты — они не имеют состояния. (во всяком случае не должны иметь), поэтому подключаются во время компиляции, а не динамически.
Понятие DRY, как я вижу, вам неведомо.
Предвижу как минимум два типажа: CommentableEntity и TaggableEntity
Не выйдет т.к. trait фактически является копи-пейстом, а тут нужно состояние для того, чтобы данные entity сконфигурировать.
* Весь говнокод в голове. Никакая парадигма не спасет от этого.
* Нужны почти всегда если написать в MVC и DRY. При наличии типажей и примесей можно делать очень тонкие контроллеры. Вот например вам не нужно в каждом контролере аутентификация или сессии или мэйлер. Так почему бы не подключить когда они нужна user Session, Auth, Mailer;(конечно можно через глобальный реестр делать вызов их, но тут как кому нравиться) Или реализовать фильтры как цепочка вызовов use CSRFFilter, DoSFilter; Т.е. теперь не нужно лепить кучу статических методов чтоб может когда-то инициализировать какое то свойство. Вот в чем вся и прелесть.
UFO just landed and posted this here
Видимо вам не знакомо что такое псевдокод или… вы вообще не защищаете ресурсоемкие операции надеясь только на сервер :-)
DoS и DDoS это разные вещи. DoS-атакой может являться запуск любой ресурсоемкой операции злоумышленником (запрос картинки в 100500х100500 пикселей там, где она генерируется автоматически скриптом, специально сформированный запрос, который вызовет чтение большого кол-ва строк из БД и т.п.). От атак этого типа можно защититься с помощью проверки данных, полученных от пользователя, на попадание в допустимый диапазон. Естественно, такая проверка должна проводиться кодом, который обладает знаниями об это диапазоне.
Я с вами не соглашусь. Говнокод не в голове, а в коде. В голове наоборот все стройно и красиво.
Ваш подход к трейтам — это инклюды. Как раньше можно добавить своего функционала в выполняемом файлике, сделав инклюд с неким кодом, так и теперь, можно загрузить трейт, чтобы добавить функционала к существующему контроллеру.
Что будет на самом деле: некоторое время назад я столкнулся с подобным кодом: несколько сотен точек входа, порядка 50 таких магических файликов для инклюдов, в которых происходили танцы вокруг глобальных переменных, которые они либо предоставляли, либо модифицировали. Что бы добавить какой-то функционал в проект, надо было открыть соседнюю точку входа, скопировать из нее «шапку» — набор инклюдов для инициализаци в нужном порядке, и уже потом писать свой код. С вашими трейтами будет то же самое. Пока их не много — они помещаются у вас в голове(все пять). По мере развития проекта вы перестанете понимать что в них происходит. В них появятся костыли с неявной функциональностью, они будут частично дублироваться. А сколько информации нужно будет загрузить в мозг новичку в вашем проекте?
По большому счету — к пхп коду предъявляется только одно требование — понятность. Мое мнение — трейты понятность не увеличивают.
Причем тут инклуды вообще?! С вашей логикой можно сказать что и MVC это инклуды, а что разве нет? Те же инклуды только происходят в определенном порядке. Идя по вашей логике можно сказать что http это вообще набор слов и чисел, что будет верно но далеко от истины. Как вы приплели сюда к трэйтам стандартные голые включения php кода я не знаю. Вы пишите кроме пхп на каком то языке где есть трэйты? Как можно судить даже не попробовав, у меня это в голове не укладывается.
>> А сколько информации нужно будет загрузить в мозг новичку в вашем проекте
Так давайте вообще ООП c php выкинем, а то у бедного новичка мозг кипятится.
>> одно требование — понятность
Я может вам глаза приоткрою но пхп чуть ли не худший язык чтобы понимать что-то глядя на исходный код. Так как в большистве случаев без проверки var_dump вы даже не знаете какой тип имеет переменная или возвращает метод. А поскольку многие пхпшники не знают что такое тестирование баг и php код как брат с сестрой.
>> Пока их не много — они помещаются у вас в голове(все пять)
В голове абсолютно ничего держать не надо, если код покрыт тестами. Если вам нравиться держать все в голове это ваше право, если же у вас есть архитектура, есть тесты или например TDD, то вы не сможете по крупному наговнокодить. Поэтому говнокод только в голове.
В работе с ORM очень полезный функционал, очень удобно добавлять определенное поведение каким-то группам моделей, при этом не встраиваясь в цепочку наследования.
> Как часто это вам надо

Постоянно. Попробуйте один разок и уже не сможете без этого жить. В yii это сейчас эмулируется, а теперь можно будет дождаться натиную реализацию.
Не заработает. Для того, чтобы заменить behavior нужны mixin, а не trait.
Зря. Очень даже много поводов использовать. Говнокода, конечно, станет больше, как от любого другого мощного синтаксиса.
Хорошая и полезная фича. Скорее бы стабильный релиз, на продакшн бета не годиться к сожалению.

З.Ы. Вот еще бы множественные конструкторы запилили
Динамическая типизация мешает перегрузке конструкторов и методов.
Пожалуйста раскройте — почему так?
Например в яве компилятор определяет какую функцию вызвать по сигнатуре (имя функции, количество и тип аргументов). В php перегрузку можно было бы сделать по количеству аргументов, но почему то предпочли сделать аргументы со значениями по умолчанию и я думаю у них были причины на этот счет.
При чём здесь динамическая типизация? Авторы, скорее, не захотели ограничивать людей, которые исторически работали с func_get_args. Да и с точки зрения прекомпиляции гораздо проще ходить по детерминированному дереву операций, нежели в процессе ещё и подбирать с помощью паттерн-матчинга нужную сигнатуру.

PHP — это не питон, где можно поломать что-то на грани версий и сказать «Ок, живите с этим». Это колоссальное сообщество с миллиардами легаси-скриптов, которые нельзя ломать. Если делать перегрузку так, как это происходит в других языках, то надо в случае ненахождения сигнатуры метода не вызывать метод, а аргументы передавать опциональными, а бросать ыксепшон, перед этим вызвав какой-нибудь magic method. Представляете, что начнётся с легаси-кодом?

Вон, кошмарная смесь дженериков и интерфейсов, помноженная на слой замещающего наследования вынесена в топик. Как вы думаете, будет в языке со столь богатым прошлым оно работать на благо?

Сколько можно умным людям (не мне, а всяким малоизвестным Грэмам, например; или Кеям) писать: объектно-ориентированное программирование — это парадигма, идеология, стиль мышления. Это не виртуальные таблицы методов с сахаром для перегрузки в локальном контексте переменных this, self и прочих им подобных. Это не замещающие дженерики. Это представление мира в виде сущностей, имеющих интерфейсы для обмена данными. В крайнем случае это данные, имеющие правила, по которым идёт их обработка в суперпозиции с другими данными. Это не типизация, это не наследование, это не замыкание данных.

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

Я пишу на PHP уже 13 лет. Не то, чтоб это много, но я застал ещё php 3.0 и успел поковыряться в её внутренностях, потом изредка посматривая на внутренности следующих поколений. Это замечательный инструмент, который внутри недалеко ушёл по сложности устройства от консоли Quake 2. Это автомат Калашникова. И не надо обвешивать замечательный инструмент тем, для чего созданы более впечатляющие и более подходящие как по внутреннему устройству так и по идеологии языки. И старое испортите и новое потеряете.

Вы извините за эмоции, надоело смотреть на реплики «АВТОРЫ ГОРИТЕ В АДУ БЕЗ МНОЖЕСТВЕННОГО НАСЛЕДОВАНИЯ У НАС ЕСТЬ ПАТТЕРНЫ КОТОРЫЕ МЫ РЕАЛИЗУЕМ. НАМ НАДО ИХ ПОМНОЖИТЬ И ПОЛУЧИТЬ СУПЕРОБЪЕКТЫ СУПЕРРЕАЛЬНОСТИ ДЛЯ АБСТРАКЦИЙ ОТ АБСТРАКЦИЙ!». У вас есть интерфейсы, у вас есть наследование, у вас есть магические методы. Да, для них надо писать абстракции. Да, в этом случае вы становитесь ответственны за архитектуру. Но, блин, этого же никто не хочет, для этого есть паттерны, есть строгая типизация и оптимизирующие компиляторы, умеющие связывание по сигнатурам.

Плохому программисту типизация мешает, простите.

Минусуйте, гоните, насмехайтесь.
Все это очень интересно и я во многом с вами согласен, но какое отношение ваш опус имеет к моему ПРЕДПОЛОЖЕНИЮ «почему в php нет перегрузки функций»?
Вчитайтесь в мой опус ещё раз, пожалуйста. Прочитайте труды Кэя, Грэма, Абельсона, Себесту. Почитайте код PHP. Оцените трудозатраты. Оцените профит. Оцените нужность этого и риски. Все ответы перед вами, нужно только подумать.

Мой опус — исключительно ответ на ваше, скажем так, не очень обоснованное высказывание про то, что, мол, динамическая типизация мешает сделать перекрытие/перегрузку функций. Думать за вас и обосновывать ваши ПРЕДПОЛОЖЕНИЯ я не собираюсь, у вас для этого есть своя голова. Приведите аргументацию, пожалуйста. Мифическая невозможность сигнатурного матчинга в данном случае не аргумент, поскольку а) PHP поддерживает уточнение типизации при вызове методов, б) даже если предыдущий пункт чем-то смущает вас, то есть мнение, что сигнатуры при динамической типизации не требуют спецификации типов.

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

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

Я бы мог уместить содержание своего опуса в пять слов — «Потому что это не нужно». Я не стал сознательно этого делать, потому что если есть возможность совратить с пути «потенциально гнездового» мышления заблуждающегося человека — ему нужно подставить видимую подножку, дав при этом возможность её увидеть и понять, как больше не натыкаться на такие подножки.

Почитайте литературу по Smalltalk, например. Она замечательно объясняет, почему ООП Страуструпа — это не ООП, а PHP — это не то, чему нужна перегрузка методов.
Или во мне проснулся талант тонкого тролинга, или у вас что-то с нервами.
Дорогой пожалейте себя, я не нуждаюсь в жалости. Это вы тут испытываете жуткий батхерт и катаете стены текста.
> а) PHP поддерживает уточнение типизации при вызове методов
Ну, я конечно, надеюсь, что когда нибудь можно будет использовать скалярные типы, но в данный момент это не так.

> б) даже если предыдущий пункт чем-то смущает вас, то есть мнение, что сигнатуры при динамической типизации не требуют спецификации типов.
Интересное мнение, и как, простите, определить, что Test::test($a) требуется параметр типа int, а Test::test($b) типа string?
а) Начнём с того, что при динамической типизации скаляров смысла в матчинге по ним нет. Для этого есть олдскульные проверки is_*.

б) Смысл? Тут же все ратуют за ООП. В данный момент (и этого более чем достаточно) PHP поддерживает специфицирование параметра классом или признаком кортежа. Этого чуть более, чем достаточно.

Не делайте из сильных мест языка слабые.
Не понимаю я вас, вы сами выше написали «Мифическая невозможность сигнатурного матчинга в данном случае не аргумент, поскольку… (а) и (б)» из этого предложения мною и был сделан вывод о том что реализация этого все же возможна.

> Смысл?
Не знаю. Но это был вопрос к возможности определения требуемой сигнатуры без полноценного type hinting-а.

> Для этого есть олдскульные проверки is_*.

Есть чуть менее олдскульный оператор instanceof.

> Тут же все ратуют за ООП. В данный момент (и этого более чем достаточно) PHP поддерживает специфицирование параметра классом или признаком кортежа. Этого чуть более, чем достаточно.

Только цель у этого сейчас совсем другая.

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

И это не помеха перегрузке конструкторов и методов.
Насколько мне известно php — интерпретируемый язык. Полагаю, определение, какую функцию вызвать можно делать в момент ее вызова, разве нет?
Так и знал, что обязательно синглтон засунут…
Это же главный паттерн PHP :) Ибо при каждом запросе поднимается вся система. А чтобы лишних объектов не создавать давайте сделаем всё синглтонами :)
UFO just landed and posted this here
Множественное наследование есть гут. У нас, например, есть кучка полезнейших классов (Singleton, Request, Traversable, Iterator, e.t.c.) и теперь очень просто добавить разрабатываемому классу нужное поведение. Пока это приходится реализовывать через Dependency Injection.
Про синтаксис и механику понятно написано. Дайте больше жизненных примеров!
Пожалуй, это будет тема отдельного топика, но не раньше чем через полгода-год, когда я смогу с типажами поработать «в поле».
Полгода+год прошли, давайте уже :)
За прошедшее время полностью перешёл на другие языки программирования. Так что теперь уже врядли. Но домаю найдётся кому подхватить флаг.
Это что-то типа Behaviors в Yii, насколько я понял.
Я правильно понял что это костыль вместо множественного наследования?
Да, насколько я понимаю разработчики языка именно эту проблему и решали.

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

Тем не менее некоторые не сложные задачи, которые можно было бы решить множественным наследованием типажи покрывают.
Как ни обидно, но очередной костыль впилили вместо того чтоб сделать все «официально» и добавить таки множественное наследование, без костылей, чтоб наследуемые методы появлялись в порядке очереди.
Да Вы что? А дальше почитать там не хватило желания?
ru.wikipedia.org/wiki/Ромбовидное_наследование#.D0.A0.D0.B5.D1.88.D0.B5.D0.BD.D0.B8.D1.8F
Есть куча вариантов решения этой проблемы, вхять хотябы самый простой, который используют в питоне: берем первое вхождение.
Да вы что? А подумать, не? Неоднозначность в том, что мне приходится думать какая именно ветка наследуется.
И зачем вам ванильное множественное наследование вообще? Так просто потроллить? Трэйты абсолютно точно так же решают все проблемы.
Я не троллю, я просто не понимаю зачем делать нечто что эмулирует множественное наследование, если можно сделать множественное наследование?
«Неоднозначность в том, что мне приходится думать какая именно ветка наследуется.»
Какой класс первый в обьявлении родителей того метод и будет использоваться при совпадении, в чем проблема то? Много думать надо? Достаточно лишь посмотреть на обьявление. В других языках от этого избавились а тут не смогли бы?
Вторая – воспользоваться толи фичей, толи багой php, которая связана с использованием ключевого слова static при объявлении переменной.

Вы же используете типаж в своем последнем примере, т.е. copy-paste. Чему вы удивляетесь? Вполне ожидаемое поведение.
Такое поведение не является особенностью типажей. Если взять «чистый» класс, внутри метода написать при объявлении переменной static, затем сделать класс наследованный от первого – поведение будет аналогичным, переменная будет инициализирована отдельно в родительском классе и в дочернем.

Хуже всего, что это поведение, не документировано и на php.net я встречал комментарии, что это ошибка. А что не документировано, может быть изменено в последующем.
Давайте обратимся к документации. Вот пример оттуда:

<?php
trait Counter {
    public function inc() {
        static $c = 0;
        $c = $c + 1;
        echo "$c\n";
    }
}

class C1 {
    use Counter;
}

class C2 {
    use Counter;
}

$o = new C1(); $o->inc(); // echo 1
$p = new C2(); $p->inc(); // echo 1


Т.е. это все-таки ожидаемое поведение, разве нет?
Спасибо, не нашёл этого ранее. Если я не ошибаюсь документацию по типажам выложили только вчера.

Теперь можно утвердать наверняка, поведение ожидаемое.
Хотя, с обычными классами — такое же поведение (проверил на 5.3.6). Удивлен.
Ничего удивительного: переменная же относится к scope функции, а не объекта. В С++ так же:
#include <iostream>

class C {
public:
    void test(int set_value = 0) {
        static int i = 0;
        if (set_value) {
            i = set_value;
        }
        std::cout << i << "\n";
    }
};

int main() {
    C A, B;
    A.test();
    B.test();
    A.test(1);
    B.test();
    return 0;
}

~/tmp$ g++ test.cpp && ./a.out
0
0
1
1
Если бы было так же — у вас было бы 0 0 1 0.
Так, секундочку, а что тогда проверяли на обычных классах, и какое там было поведение?

<?php
class C {
    public function test($set_value = null) {
        static $i = 0;
        if ($set_value) {
            $i = $set_value;
        }
        echo $i, "\n";
    }
}
$A = new C;
$B = new C;
$A->test();
$B->test();
$A->test(1);
$B->test();

~/tmp$ php test.php #PHP 5.3.8 
0
0
1
1
О, а с трейтами ж действительно забавно. Копипаст, точно :)

<?php
trait T {
    public function test($set_value = null) {
        static $i = 0;
        if ($set_value) {
            $i = $set_value;
        }
        echo $i, "\n";
    }
}
class A { use T; }
class B { use T; }
$A1 = new A;
$A2 = new A;
$B1 = new B;
$B2 = new B;
$A1->test(1);
$B1->test(2);
$A2->test();
$B2->test();

~/tmp/php-5.4.0beta2$ ./sapi/cli/php ../test.php 
1
2
1
2
<?php
class A {
    function test($set_value=0) {
        static $i = 0;
        if($set_value) {
            $i = $set_value;
        }
        echo $i.PHP_EOL;
    }
}

class B extends A {}
class C extends A {}

$b = new B();
$c = new C();
$b->test();
$c->test();
$b->test(1);
$c->test();


php test.php                #PHP 5.3.6
0
0
1
0
О, блин, как забавно. Получается, что в случае с методами это аналог статического члена класса, видимый только внутри функции. Видимо, как-то так внутри и реализовано. Особо неочевидно, кстати, если вспомнить LSB, в контексте которого ключевое слово static означает ровно противоположное. :)

С++ с таким подходом не согласен, кстати:
#include <iostream>

class C {
public:
    virtual void test(int set_value = 0) {
        static int i = 0;
        if (set_value) {
            i = set_value;
        }
        std::cout << i << "\n";
    }
};

class C1 : public C {};

int main() {
    C A;
    C1 B;
    A.test();
    B.test();
    A.test(1);
    B.test();
    return 0;
}

0
0
1
1
Да, я этот вариант в C++ тоже проверил.
С PHP штука в том, что переменная должна быть статичной, но она статична только в пределах текущего класса. Причем, если объявить её статичным полем класса (а не метода) — все работает как надо.
Свойства в типажах

Поразмыслил. Думается мне, что использовать их стоит только для внутренних состояний, о которых классу знать и не надо. Благо, что абстрактные методы в трейтах использовать никто не запрещает, вот, например, примитивная базовая реализация этакого минималистичного IDatasource:
<?php

interface IDataSource {
    public function has($key);
    public function get($key, $default_value = null);
}

trait TDataSource {
    public function has($key) {
        return array_key_exists($key, $this->getInternalValues());
    }

    public function get($key, $default_value = null) {
        return $this->has($key) ? $this->getInternalValues()[$key] : $default_value; // one more php 5.4 feature
    }

    abstract protected function getInternalValues();
}

class Storage implements IDataSource {
    use TDataSource;

    protected $values = array();

    public function __construct(array $data) {
        $this->values = $data;
    }

    protected function getInternalValues() {
        return $this->values;
    }
}


Еще такая мысль — учитывая нестрогую и динамическую типизацию, вполне себе получается этакая своеобразная замена плюсовых темплейтов (в контексте реализации обобщенных алгоритмов).
use блиа. Раз тырили у Scala, так тырили бы уже и with, а не выдумывали новый синтаксис.
Гляжу на PHP и все больше он превращается в непонятно что, ну если хочется сделать множественное наследование, почему бы его и не сделать.
А при чем тут Руби? И чем костыль в виде добавление кода препроцессором лучше множественного наследования?
не буду говорить про Traits, но mixin'ы в руби — средство намного более опрятное и гибкое, чем множественное наследование.
Не знаю как в руби, а в c++ шаблоны + множественное наследование дает обалденный результат, а в PHP в данном случае гибкости нет, просто некоторое снижение сложности разработки при кривом проектировании.

Я к примеру не вижу плюсов в данном варианте, есть шаблон Dependency Injection, который в свою очередь даст гораздо большую гибкость.
мне кажется, что последнем примере (с синглтоном) поведение как раз правильное, так как образованный MyExtClass это новая сущность отличающаяся от MyClass. И не важно то, что она наследуется.
Можно ли указывать trait как тип в аргументах? И есть какие-то методы определить используется ли в классе trait определенный или нет (instanceof)?
<?php
trait Counter {
    public function inc() {
        static $c = 0;
        $c = $c + 1;
        echo "$c\n";
    }
}

class C1 {
    public function doSomething( Counter $obj ){ ... }
}
Для этого лучше подходят интерфейсы.
Вы решили поумничать? Я спросил совершенно другой вопрос, и меня именно ответ на него интересует =)
Нет, я высказал свое мнение о целесообразности данной фичи. А что оно не работает, выясняется запуском приведенного вами кода :)
Это только альфа, там многого еще нет того что есть в планах на пхп 3.4 =) Вообще хотелось бы проверять, но с другой стороны если таки сделают фичу чтоб трейты требовали интерфейсов от классов, тогда такая нужда отпадет сама собой.
Нет, нет.

По второму можно только хаками, например, в каждом типаже объявлять свойство, типа $__trait_[TraitName]. Затем, вытащив массив всех свойств класса, распознать подключённые типажи (это достаточно сделать для каждого класса только один раз). Возможно что-то можно получить рефлексией.

Типажи скорее всего не для этого создавались, возможно более красивым решением будет иметь соотвествующий каждому типажу интерфейс или запись списка типажей класса в явном виде.
Да, только что прочитал что можно будет указывать «обязательное» наличие интерфейса в классе который использует данный типаж =)
trait IteratorUser require Iterator {} // как-то так
Кстати, о трейтах.
Вот тут переводчики документации обсуждали, как правильно перевести «trait»: news.php.net/php.doc.ru/2908
Я со своей высокой башни влез и сказал, что traits они и есть трейты. Возможно, был не прав.
Если у кого-то есть обоснованные возражения на эту тему — скажите им, можно прямо в этом треде, Irker, я вижу, тут в комментах есть.
Транслитерация английских слов не улучшает понимание.
Если если русское соответствие, то почему его не использовать?
«Типаж» достаточно точно передает смысл слова «trait».
Тем более если это термин уже используется в программировании.
Можно ли использовать динамическое подключение типу function a() { use B; } и будет ли доступен типаж, подключенный в предке?
Эти типажи очень похожи на дельфовые интерфейсы.
Sign up to leave a comment.

Articles