LINUX.ORG.RU
ФорумTalks

всесторонняя критика PHP

 ,


0

1

Нашел прикольную статью с всесторонней и аргументированной критикой языка программирования PHP - http://me.veekun.com/blog/2012/04/09/php-a-fractal-of-bad-design/ Рекомендуется к прочтению всем, кто собирается изучать этот ЯП, с целью направить их энергию в более полезное русло.

Маленький отрывок для Ъ:

Что делает вот этот код?

  @fopen('http://example.com/not-existing-file', 'r');
  • Если PHP был скомпилирован с опцией --disable-url-fopen-wrapper, он не будет работать (при этом документация говоря «it won't work» не поясняет, каким именно образом он не будет работать: вернет null, выбросит исключение, и т. д.)
  • Если allow_url_fopen в php.ini выключен, то код тоже не будет работать, при этом совершенно непонятно как именно.
  • Из-за @ предупреждение о несуществующем файле не выведется
  • Но если scream.enabled включен в php.ini, то предупреждение выведется
  • Или если scream.enabled включен через ini_set.
  • Но оно не выведется, если задан неправильный error_reporting
  • Куда именно выведется предупреждение сказать нельзя, так как это зависит от опции display_errors в php.ini. Которая может быть переопределена через ini_set

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

Update: Полный перевод статьи на русский - http://habrahabr.ru/post/142140/

★★★★★

Последнее исправление: provaton (всего исправлений: 1)
Ответ на: комментарий от true_admin

я твою точку зрения понял, всё что в топике написано тебе кажется нормальным

Переустанови libastral, он тебя обманывает :)

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

KRoN73

А это в чём выражается?

ИМХО ЯП нужно либо с нуля делать с ООП, либо его _полностью_ переделывать, как в случае с C++. Иначе какая-то фигня получается, как в php... И похоже в perl.

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

Всё верно, но там упоминался и такой недостаток: «при этом документация говоря „it won't work“ не поясняет, каким именно образом он не будет работать: вернет null, выбросит исключение, и т.д.»

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

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

А в PHP можно или в браузер ошибки выводить (только зачем?) или в логи кидать.

Как считаешь, много ли пхп-макак в курсе насчет этой фичи?

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

много ли пхп-макак в курсе насчет этой фичи?

ну это уже совсем другой вопрос. Макаки они везде макаки.

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

почитал по сцылке - действительно, кривизна и нелогичность ООП в перловке сравнима с кривизной ООП в php...

В перловке она хотя бы поддается исправлению (хотя остается отдельный вопрос, а что мешало сразу сделать нормально). Просто оговариваешь, что магию использовать нельзя, и все ок. В пхп оговорить, в принципе, можешь, но говна на всех уровнях меньше не станет и какой-то undefined behavior в любой момент засунет тебе нож в спину.

shimon ★★★★★
()
Ответ на: Выброс от AptGet

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

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

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

Причем находятся идиёты, советующие их использовать в книгах — *slashes(), например, это ж такая срамота

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

json_decode может вернуть null в случае валидных данных и невалидных array_search и strpos когда искомый элемент не найден возвращают false, который часто неявно конвертируется в 0 (что означает, что искомый элемент находится в нулевой позиции) == не имеет свойства транзитивности («foo» == TRUE, and «foo» == 0… but, of course, TRUE != 0.) Оператор сравнения делает невозможным создания детерминированного метода сортировки (NULL < -1, and NULL == 0) использование глобальных переменных без global приводит к созданию локальной переменной Имена переменных зависят от регистра, функций - не зависят нет модулей много псевдофункций со специальными правилами парсинга. Например, empty($var || $var2) выдает parsing error. Нету stack traces и нечитабельные сообщения о ошибках парсинга (например, :: называется T_PAAMAYIM_NEKUDOTAYIM)

Ну это уже посерьёзнее претензии.

Однако:

использование глобальных переменных без global приводит к созданию локальной переменной

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

Suntechnic ★★★★★
()

например, :: называется T_PAAMAYIM_NEKUDOTAYIM

Сделало моё утро.

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

> *slashes(), например, это ж такая срамота

Жесть. Не знал, кстати.

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

> А как должно быть?

При отсутствии переменной в текущей области видимости идет обращение к следующей области видимости. И так идет до верхнего уровня. Это интуитивно-понятные правила работы с областями видимости во всех вменяемых ЯП.

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

Я в своё время много посвятил этому вопросу. На практике оно может EINTR вернуть? Я читал что нет и что в ядре всегда двух случаях возвращает ошибку: отвал блочного устройства и отвал NTFS. Т.е. в нормальной жизни вроде как не бывает, поэтому я везде или игнорю возвращаемое значение или log(«Achtung! Тут какая-то трава»);.

Может быть еще на NFS можно EINTR получить, не уверен. В любом случае после close() в linux дескриптор уже невалидный, «что-то странное» можно отследить, да, а с дескриптором уже ничего не сделать.

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

Особенно круто с сигналами :) в linux у сигналов нормальное поведение, но кое-где сигналы превращаются в ад, и чсх все в рамках POSIX.

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

Казалось бы да, и на некоторых *nix'ах так и есть. Но на большинстве, в т.ч. и на линуксе, этот код может закрыть не тот дескриптор, тк после первого close() дескриптор освобождается.

Единственное, что можно совершенно точно сказать, что приведённый тобой код — некорректный кусок говна, потому что posix утверждает, что «If close() is interrupted by a signal that is to be caught, it shall return -1 with errno set to [EINTR] and the state of fildes is unspecified», поэтому виноват будет не posix и не язык C, а дебил-автор кода.

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

некорректный кусок говна

Если тред только один - то вполне корректный.

виноват будет не posix

http://austingroupbugs.net/view.php?id=529

А мужики-то и не знали!

То что «unspecified» может означать «дескриптор валидный, файл все еще открыт» ты не допускаешь?

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

Если тред только один - то вполне корректный.

Нет, некорректный

То что «unspecified» может означать «дескриптор валидный, файл все еще открыт» ты не допускаешь?

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

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

Это может означать, что с дескриптором может быть вообще всё что угодно, что это на усмотрение реализации.

Продолжи мысль. Может он быть еще валидным или нет? А если дескриптор валиндный то что с ним делать?

Ты как те мудаки из Adobe, которые затачиваются на конкретную реализацию, а потом верещат, что пришли плохие дяди и всё «поломали»?

Да, я затачиваюсь на реализацию linux/BSD и не закрываю дескриптор второй раз. Есть предложения что делать с дескриптором на обобщенной POSIX системе?

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

При отсутствии переменной в текущей области видимости идет обращение к следующей области видимости. И так идет до верхнего уровня. Это интуитивно-понятные правила работы с областями видимости во всех вменяемых ЯП.

% set r 10
10
% proc a {} {set r 20; puts $r; puts $::r}
% a
20
10

Слава богу, я пользуюсь не вменяемым языком.

А список вменяемых не приведете? Ну что бы знать где грабли зарыты. Я так понимаю он не должен быть большим...

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

Как считаешь, много ли пхп-макак в курсе насчет этой фичи?

А язык тут при чём?

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

ты можешь и не знать что у тебя в подсознании :)

Даже если и так, речь у нас пока о сознании.

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

По ссылке еще гораздо больше интерестностей, но все лень переводить.

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

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

Как считаешь, много ли пхп-макак в курсе насчет этой фичи?

Все, за исключением двух.

valich ★★★
()

php в своё время заменил perl потому, что perl - cgi, а на php можно было писать прямо в HTML не выкручиваю мозг всякими Content-Type. И работало в php всё из коробки, а в перл всякие не понятные use в начале, регэкспы перла вообще отдельная тема... не все могли осилить perl. Глупо конечно, но именно благодаря этому, появилось куча пхпешников которые клепали соответствующие сайты.

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

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

TDrive ★★★★★
()

добрые люди с лора не дают забывать о существовании habrahabr и xakep

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

> Слава богу, я пользуюсь не вменяемым языком.

Что будет, если сделать просто proc a {} { puts $r; } ?

> А список

python, c, lisp, *sh. ruby выдает ошибку, что тоже является вменяемым поведением. Невменяемо - это втихую создать локальную переменную.

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

Что будет, если сделать просто proc a {} { puts $r; } ?

% proc a {} {puts $r}
% a
can't read "r": no such variable

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

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

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

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

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

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

А разве в PHP будет создана перемнная с каким-то значением?

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

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

Только не хватало, что бы возникали неявные ссылки на глобальные переменные.

Глобальные переменные — это, вообще, зло. Зачем они нужны кроме редких хаков? Да и в этом случае лучше такие хаки поглубже заинкапсулировать. И за любое использование global/$GLOBALS вне таких строго описанных инкапсуляций — бить палкой по рукам :)

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

> разве в PHP будет создана перемнная с каким-то значением?

Смотрите:

php > $a = 5;
php > function bug() { echo $a + 5; }
php > bug();
5
provaton ★★★★★
() автор топика
Ответ на: комментарий от provaton

Смотрите:

Вы выключили зачем-то (ибо по умолчанию оно уже давно включено) E_NOTICE и чему-то удивляетесь. Вот так оно сегодня (и довольно давно) ведёт себя по умолчанию:

$ php -r '$a = 5; function bug() { echo $a + 5; } bug();'
PHP Notice:  Undefined variable: a in Command line code on line 1
KRoN73 ★★★★★
()
Ответ на: комментарий от provaton

Зачем же их в пхп так много? :)

Для удобства быдлокодеров :) Но никто же не заставляет эти переменные использовать? Впрочем, даже их использование не так уж криминально, они строго описаны, имеют синтаксис, отличный от типового, так что перепутать что-то (скажем, завести собственную переменную $_GET) — довольно сложно.

А вот свои собственные глобальные переменные заводить не нужно. Ни в каком языке, если только этого позволяет избежать его архитектура. В PHP — позволяет. Так что за использование собственных глобальных переменных — нужно наказывать :)

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

У меня есть простенький фреймворк. Он держит все данные в глобальных переменных. Например страница собирается в глобальном массиве, где отдельно лежат заголовки http, доктайп, head и body страницы. Благодаря этому сборщик-шаблонизатор и прототипы (не знаю - аналоги там всяких модулей и компонентов) имеют к ней свободный доступ. Такой же доступ есть и у диспетчера отправки. В итоге все работают над одним общим делом без тасования параметров туда сюда. Шедулер спокойно запускает прототипы, те собирают страницу и кстати обмениваются данными через PROTOBUS - еще один глобальный массив. Диспетчер отправки спокойно видит по блокировкам (они тоже в глобальном массиве) кто над чем работает и какие части уже готовы и могут быть отправлены клиенту. Очень удобно - каждый делает свое маленькое дельце и не надо заботится о передаче параметров... Не думаю что это зло.

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

Вот так оно сегодня (и довольно давно) ведёт себя по умолчанию:

Впрочем, сорри, это оно так по умолчанию в дистрибутивах (Gentoo и Ubuntu, в частности). А официально значения рекомендованы такие:

; error_reporting
;   Default Value: E_ALL & ~E_NOTICE
;   Development Value: E_ALL | E_STRICT
;   Production Value: E_ALL & ~E_DEPRECATED

Так что при следовании рекомендациям PHP, при разработке или в продакшне NOTICE будет выпадать, а при «бытовом наколенном» использовании — нет.

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

И где тут в этом коде создание переменной? В функции попытка чтения переменной которая пуста, суммирование и естественный ответ 5. То же будет и в баше, например.

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

Он держит все данные в глобальных переменных.

Ну так ССЗБ же :)

Очень удобно - каждый делает свое маленькое дельце и не надо заботится о передаче параметров

Удобно, до тех пор, пока не придётся искать ошибку в одном из модулей, портящую работу других модулей.

Или до тех пор, пока сложность системы не превысит возможность держать её в голове целиком (а этот момент обычно наступает довольно быстро).

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

Или пока в проекте не появится второй человек…

В общем, маленькое удобство (которое легко решается иными способами), которое в будущем чревато большими проблемами.

KRoN73 ★★★★★
()

Купил книжку по PHP, чтобы не быть профаном. Но программировать на нём у меня нет времени.

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

> и естественный ответ 5

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

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

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

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

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

Берёте плоскогубцы, у которых нет зазубрин; они плоские и гладкие. Не так полезно, как могло бы быть, но ими всё ещё можно выкручивать болты.

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

Теперь представьте себе миллионы плотников, использующих такой вот набор инструментов и говорящих вам: «А что не так с этими инструментами? Я никогда не использовал ничего другого и они отлично работают!». И плотники показывают вам, построенные ими дома с пятиугольными комнатами и крышей кверху ногами. Вы стучитесь в дверь, она просто падает внутрь и они орут на вас за то, что вы сломали их дверь.

Вот что не так с PHP.

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

Ну костыль же. Нафиг ворнинг (хотя какой ворнинг, так нотис. Видно в среде пхп-программеров нормально суммировать невесть-что с натуральным числом, это достойно всего лишь скромного нотиса) в месте, где 100% ошибка?

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

Удобно, до тех пор, пока не придётся искать ошибку в одном из модулей, портящую работу других модулей.

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

Или до тех пор, пока сложность системы не превысит возможность держать её в голове целиком (а этот момент обычно наступает довольно быстро).

В том-то и дело, что держать в голове приходится очень мальенькую часть - начальную инициализацию, работу планировщика и диспетчера. Все. После того как запущен планировщик можно уже ни о чем не заботится. Он не даст упасть ядру, и разрулит все остальное. Падение модуля не приведет ни к чему кроме того, что планировщик вернет в страницу пустую строку вмето его данных, добавит в список DEBAUG(MESSAGES) свою интерпритацию ошибки и в DEBAUG(ERRORS) - ошибку выбрашенную модулем. А там уже в зависимости от настроект это улетит либо в лог, либо в страницу в div отладки, либо вообще в /dev/null

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

Документация и комменты рулят.

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