Pull to refresh

Comments 66

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

Статику надо уметь готовить ))

А приведите примеры. Причем лично меня интересуют именно те примеры, которые обладают состоянием.

Вам чтобы поспорить? Или действительно интересно?

Ну ОК, состав первичного ключа (список полей, входящих в него) — это свойство* класса моделей, а не конкретной модели. Не нужно, как в Ларавеле, создавать объект-модель, чтобы просто узнать, какой у нее ПК.

* «свойство» здесь вполне может быть публичным методом, возвращающим разный результат в зависимости от get_called_class(), например
Эмм… Не хочу спорить, но пытаюсь понять, чем тут поможет статик-метод…
Правильно я понимаю, что для получения состава PK необходимо сделать запрос в базу и получить информацию по определенной таблице (которая, возможно, лежит в каком-то методе или свойстве — их тоже статиком делать из-за вашего сценария)? И подобный запрос (с кешированием) делается в ларавеле при создании модели? Тогда почему не воспользоваться этим (что и делает ларавел)?

А что если модель может получать данные из нескольких разных таблиц, в которых разные PK. Какая именно таблица выбирается по внешним факторам. В этом случае проще и правильнее именно создавать объект модели, а не эмулировать такое поведение.

Если я прав — статический метод не нужен, скорее вреден.

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

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

Неважно.

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

Ну тогда проще и правильнее константу, не? Ну а если вам нужен именно какой-то метод — правильнее вынести его в хелпер и вызывать с передачей в него параметров, от которых зависит результат. Собственно, я про такое использование и говорил выше ;)

Важно то, что состав первичного ключа — свойство не объекта, но класса.

На самом деле — нет. По вашему примеру — состав ключа вообще не относится к моделям.

Это свойство не столько класса, сколько метаданных объекта. Их можно получать из объекта, из класса, откуда-то ещё.

это свойство* класса моделей, а не конкретной модели.

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

Сравнение на свехмалых числах не только не даёт полной картины, но и при следующем запуске результат может оказаться противоположным

Конкретно по вашему кейсу gogle for: "Lazy Load", "DI containers".


А вообще судить по набору говнокода о чём бы то ни было — мягко говоря странно.

Я не знаю, как в php, но в js чтобы два объекта заняли 200 КБ, нужно иметь в каждом из них по 25 тыс собственных полей.

Обычный объект в js занимает 40–80 байт.

Это не два объекта, а весь рантайм.

Поток несвязного сознания, имхо.

Читаем в коде:
echo A::someStatic()->prop;

и тут же, ниже:
не обязательно создавать объекты в ООП, и можно обходиться без них экономя память


Вы серьезно верите в то, что в вашем примере объект не создается?

Я вас огорчу, пожалуй. Создается, занимает память, требует лишнего времени на возврат из локального контекста метода в вышележащий контекст (в отличие от конструктора) и будет в память торчать, пока не придет к вам GC.

То, что вы суслика не видите — не значит, что его нет!

P.S. Статья, конечно же, не уровня хабра…

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

Вы немного преувеличиваете «масштабы бедствия». Статика наследуется, у статики есть LSB, есть области видимости (это вы отметили) и автозагрузка (тоже отметили, очень важно), не забывайте еще про пространства имён.

Не надо считать, что мол «статический метод — всегда зло». Вы же в курсе, что в PHP нет по-настоящему динамических методов, они все по факту статические?
не забывайте еще про пространства имён.

а у функций с этим какие-то проблемы?


«статический метод — всегда зло»

никто никогда такого и не говорил. Разве что те, кто не понимают разницу между статическими методами и глобальным стэйтом. Если статика не имеет сайд эффектов — то все хорошо.

а у функций с этим какие-то проблемы?

Да, нет их автозагрузки.

автозагрузка это да, и то значение автозагрузки как по мне сильно преувеличено в этом контексте. Я конкретно про функции и пространства имен.

Толку от наследования, если нет нормального способа передать «инстанс» класса-наследника параметром как «инстанс» базового. Или вернуть, присвоить переменой и т. п. Классы в PHP не сущности первого класса в отличии от объектов.

Да, у них есть применение в текущей ситуации, но в большинстве случаев оно приносит больше проблем чем решает.
Или вернуть, присвоить переменой и т. п.


$className = getSomeClassName();
$className::someMethod;

// или

getSomeClassName()::someMethod();


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

Завязка на имя класса это в целом очень и очень жесткое ограничение. Вы не находите?

Нахожу, но отношусь философски — таков уж PHP.

Поясните свою философию, будьте добры. Ибо мне, например, непонятно и я могу сделать неправильные выводы из фразы "таков уж PHP". Например "и так сойдет".

Это язык. Сложившийся. Который давно на рынке. И меня нет среди его разработчиков.

Как бы он ни был плох, он занимает около 90% мирового рынка веб-разработки и немалую долю в других нишах.

Можно бесконечно хейтить. А можно изучить и пользоваться.

Я за второй вариант.
А вы?
и немалую долю в других нишах
Это в какой нише, кроме веба, PHP имеет немалую долю?
Мне последние годы доводится заниматься именно не-веб-PHP.
В основном это различная потоковая обработка данных, нормализация, загрузка из в БД, агрегация в БД и построение различных отчетных данных.
Сплошной cli.

Мм… а что тогда web php? Просто то что вы перечислили — это обычное дело в контексте web разработки.

Так нет у этих проектов веб-морд. Какая же это веб-разработка?

следуя этой логике любой проект под мобилки это не web (что в целом правильно).


Или же, если у меня есть морда, которая представляет из себя простенький дашборд, а под копотом десяток демонов которые занимаются обработкой данных — это уже не web или уже web?


Я больше о том что делить web и не web если по итогу делается одно и то же (работа с базой данных, обработка данных)?


Вот если бы вы сказали что под десктопы на php пишите — тут да, "другие ниши".

Под десктоп пока не писал. А вот проектов без интерфейса — было довольно много…
UFO just landed and posted this here

"web php" принимает на вход прежде всего всякие $_GET, $_POST и т. п.
не "web php"их игнорит


:)

Почему PHP выбран для cli? Основная причина, когда могут на этот вопрос ответить что-то кроме "а больше я ничего не знаю на достаточном уровне", это "на 90% кодовая база пересекается".

Нет, не всё так просто. Выбран в первую очередь из соображений производительности, как бы для вас это странно ни звучало. И уже во вторую очередь — из-за скорости разработки.
Вы удивитесь, но PHP7 по производительности во многих случаях обходит Python и Ruby. Я уже не говорю про Перл.
Естественно, если сравнивать более или менее одинаково (по качеству) написанный код.
Например, вот в этой инфографике в самом конце есть пример по скорости построения фрактала Мандельброта.

вот только в подавляющем большинстве случаев вам CLI приложение не фракталы Мандельброта строят, а с IO взаимодействуют, и тут php начинает сильно проигрывать тем же python/ruby в плане экосистемы.


У меня как-то был CLI скриптик на php который kmeans класстеризацией занимался, и да, на 7.0 оно делало 400KK итераций примерно за 3 минуты. Но я бы не совсетовал другим так делать.


p.s. в последних версиях cruby появился jit. Для python и что бы строить фракталы есть pypy. Ну это что бы было чуть более честно.

Я за второй вариант.
А вы?

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


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


он занимает около 90% мирового рынка веб-разработки

80% из которой можно вообще в расчет не брать.

У PHP есть такие возможности, относящиеся скорее к "хакам", чем к "лучшим практикам", но из этого не следует, что нужно на них строить архитектуру приложения в целом.

Из чего не нужно строить архитектуру? Из того, что имя класса — это string? Или нельзя использовать константу SomeClass::class?

Будьте добры поясните, что вы считаете хаком, недопустимым к использованию в архитектуре?

Спасибо

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


Как локальное решение, например, в DI-контейнере, выдающим по SomeInterface::class инстанс реализации — вполне. Как основной способ передачи ссылок на данные — очень усложняет понимание.

Теряя многие возможности, включая автодополнения и рефакторинг в IDE тайп-хинтинга в рантайме, статанализ и т. п. Я же говорю, приносит проблем больше чем решает обычно :)
Ну, скажем, не все. С дженерикоподобными типами вы ничего не поделаете, разве что юнион прописать, но там сложная история…

Опишите мне интерфейс для функции через phpdoc. А потом попробуйте описать дженерики для коллекций/промисов/etc. Спойлер — у вас не получится.

Какой тег PhpDoc документирует переменную, параметр или результат как содержащую имя класса?


Какой тег PhpDoc проводит проверку в рантаймк параметра или результата на содержание имени класса, унаследованного от базового?

не смотря на то что я с вами согласен, относительно


Какой тег PhpDoc проводит проверку в рантаймк параметра

AOP + Design By Contract покрывает все эти вещи и даже больше.

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

Это не работает с кодогенерацией. Т.е. кусок симфони и почти вся доктрина идут лесом.

В какой-то мере ровно наоборот. Те же роуты в виде аннотаций в классах контроллера относятся скорее к AOP, чем к классическим парадигмам.

Вот прямо сейчас сижу и отлавливаю баг, который скорее всего с этим связан. :(

ты про прокси классы?

Налицо явное непонимание идеи ООП.


но это тот самый оверхэд от которого можно отказаться.

если вас парит факт оверхэда на создание объектов — почему бы не отказаться от пересоздания объектов на каждый запрос? Вот это было бы разумно и реально давало бы профит. А так — это просто стыд.

не обязательно создавать объекты в ООП

вот только это не ООП а структурное программирование в лучшем случае. Идея ООП в том, что у вас не просто есть объекты, а в том что они взаимодействуют между собой, что есть late binding. Что до оверхэда — если данные не будут покидать приделов объектов, и если вы выкидываете из уравнения модель выполнения "обработай и умри" — то оверхэд будет как раз таки не в вашей реализации.


то есть банальный пример. Продемонстрируйте мне как будет выглядеть late biding в контексте статических методов? Скажем, такой простой шаблон как декоратор реализуйте.

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

В таком случае я рекомендую заняться рефакторингом втихую, чуть понизив свою производительность, при этом чуть пожертвовав своей свободой. понемногу, не спеша, умело расставляя такие «костыли», которые в нужный момент превратятся в более соответствующую архитектуру. Вряд ли внутренний перфекционист будет доволен поностью, но самые вопиющие недостатки, влияющие на ясность кода и производительность, будут сглажены.
Поверьте, таким образом уже был «спасен» не один проект.
Согласен, за рефакторинг такого лучше не приниматься — захочется убивать людей.
Код друзей таких авторов
BaseClass, ClassA : BaseClass, ClassB : BaseClass, ...
ClassA a;
ClassB b;
ClassC c;
if(a != null)
{
a->someMethod();
} // Даже без else, хотя инициализируется только одна переменная и группы
if(b != null)
{
b-> someMethod();
}

Тоже не понимают что такое ООП, потому как делали только простые программки с парой функций, а что такое сложная система даже не представляют.

PS. Это, конечно, не без создания объектов, но проблемы там примерно те же.
создавался объект mysqli и присваивался свойству sql каждого объекта. Можно только представить сколько лишних действий в пустую и какой перерасход оперативной памяти происходит.

Да, ссылки нынче дорогие(((


Наверно сравнение на «сверхмалых» числах не дает полной картины

И смысла не имеет, если на то пошло


но это тот самый оверхэд от которого можно отказаться.

Это экономия на спичках


Причина не любви к работе с объектом (при передаче другому методу), в том что у меня есть фобия что он не тот за кого себя выдает

Type hinting появился еще в 5.1


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

Как же инкапсуляция?


Я не спорю, бывают ситуации, когда статика оправдана, например методы стандартной библиотеки, и то далеко не всегда. Но память — это вообще не тот случай. То, что парни из вашей работы не смогли в lazy load — это печально.


Но, в большинстве случаев статика приводит к:


  1. Бесконтрольной связности и хрупкости проекта

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


  1. Экспоненциальному росту сложности тестирования

Ваши тесты будут на прямую зависеть от реализации статических методов и вы их не сможете подменить.


  1. Статика с состоянием — это пичалька

Вы просто должны верить, что она как-то работает и ниоткуда она не будет вызвана не правильно, или не в той последовательности.

Стоит всё таки разобраться в ООП прежде чем его хаять. Касается, впрочем, не только ООП.
Sign up to leave a comment.

Articles