Как стать автором
Обновить

Комментарии 76

Вот если бы еще кашу из функций как-то в порядок привели в 8-й версии. Разные стили именования, разная очередность параметров и прочие соглашения…
То получили бы полную и катастрофическую поломку обратной совместимости, ещё хуже чем в Python 2 -> Python 3

P.S. Да и статья как бы не об этом
Это достаточно просто сделать без поломки. Способ предлагался, почему-то по нему не пошли. Надо считать примитивные типы некими псевдообъектами с возможность вызова у них методов. Тогда ф-и можно оставить как есть, а новые методы проименовать нормально.

О каком способе идёт речь? Поделитесь ссылкой на rfc

RFC там не было, вроде, был какой-то модуль и идея за ним в виде какой-то статьи или сообщения в internal, не помню точно.

Ну это такое себе решение. Запихнуть в строку весь stdlib языка — сомнительный профит. Мне больше нравится с распихиванием функций по неймспейсам и прокидывание фоллбеков. Если я не путаю, то что-то в стиле Groovy, когда вызов println фактически ссылается на System.out.println. В PHP возможно реализовать такое же, где map([...]) будет ссылаться на какой-нибудь use function Core\Array\map

Так а почему бы не заалиасить? И тянуть какое-то время по 2+ наименований функций.

и не рассматриваете использование PHP в своём следующем проекте, то вы что-то делаете неправильно

Я понимаю использование в существующих проектах, которые уже написаны на PHP и работают. Но на кой мне PHP в следующем проекте, когда есть современные, намного лучше спроектированные языки, не обременённые обратной совместимостью с древним легаси.
У современных языков нет готовых фреймворков (даже если есть, то молодые) и решение тривиальных задач может требовать некоторых усилий. Вместе с легаси у старых языков (не мертвых) есть и сообщество, есть куча решений которые прошли не один бой и даже выиграли войну, когда у новых языков всего этого нет и там опять все это нужно строить. Я не совсем уверен, но думаю бизнес чаще будет предпочитать стабильность вместо современности, а мы разработчики чаще всего работаем на бизнес. Хотя сам пхп меня не очень радует.

Чем пхп лучше для веба по сравнению с питоном или руби?

Не знаю, разве в этом была тема? Тема была в том, чтоб уйти со старого языка на современные.

Окей, что вы называете "современными языками"?

Раст?

Для типовых веб-проектов не подходит совершенно. При всей моей любви к Rust, тут лучше подойдёт golang. Тем более, что он изначально под это делался.

Чем пхп лучше для веба по сравнению с питоном или руби?


Я извиняюсь за излишнюю резкость в суждениях, но: В PHP популярные фреймворки следуют хотя бы SOLID и GRASP (ну или пытаются), а в приведённых вами — я не видел ни одного решения, где бы был адекватный код. Лично у меня глаза кровоточат от засирания глобального пространства процедурками в Django или харкод с завязыванием на контроллеры внутри объекта реквеста в каком-нибудь RoR. Да и разработчики даже не слышали про инверсию зависимостей, учитывая то, что в этих языках даже интерфейсов нет.

Короче, как бы не смешно это звучало, но решения на PHP намного качественнее сабжей.
Интерфейсы — это концепция в голове у разработчика а вовсе не ключевое слово «interface» в языке. На python и ruby эта концепция прекрасно реализуется.

Допускаю. Можете привести пример инверсии контроля не на основе ключевого слова "interface"?


Ну, например, примитивный пример из мира PHP с ISP + DI:


Код
// Репа, которая предоставляет несколько возможностей
interface UsersRepository extends 
    FindableById, 
    ProvidesAuthentication, 
    ... { ... }

// Одна из возможностей - получение Authentcatable объекта по почте+паролю
interface ProvidesAuthentication 
{
    public function findUsingCredentials(string $email, string $password): ?Authentcatable;
}

+


class AuthController
{
    // Внедрение зависимостей объекта реквеста и репы 
    // для получения Authentcatable сущности
    public function login(RequestInterface $request, ProvidesAuthentication $repository)
    {
        $user = $repository->findUsingCredentials(
            ...$request->only('email', 'password')
        );
    }
}

Прошу заметить, что из подобной реализации мы можем двумя пинками подменить реализации и даже перейти с классических репозиториев на какой-нибудь CQRS, т.к. реализация нам не важна, а интерфейс с одним методом (за счёт ISP) вполне себе команда.


P.S. Я на всякий случай хочу напомнить, что ни в питоне, ни в руби нельзя реализовать методы без их имплементации. Только суперкостылями в виде выкидывания исключений (ну или пилить декораторы, если мы про питон).

from abc import ABC, abstractmethod
from typing import Mapping, Optional
import hashlib


def hashfunc(string: str) -> str:
    return hashlib.md5(string.encode("utf-8")).hexdigest()


class Request(ABC):
    @property
    @abstractmethod
    def form(self) -> Mapping[str, str]:
        pass


class MockRequest(Request):
    def __init__(self, dummy_form: Mapping[str, str]) -> None:
        self.dummy_form = dummy_form

    @property
    def form(self) -> Mapping[str, str]:
        return self.dummy_form


class Identifiable(ABC):
    @abstractmethod
    def get_id(self) -> int:
        pass


class Authenticable(ABC):
    pass


class User(Identifiable, Authenticable):
    def __init__(self, id: int, email: str, password_hash: str
                 ) -> None:
        self.id = id
        self.email = email
        self.password_hash = password_hash

    def get_id(self) -> int:
        return self.id

    def get_email(self) -> str:
        return self.email

    def get_password_hash(self) -> str:
        return self.password_hash

    def __repr__(self) -> str:
        return f"id=={self.id}, email=={self.email}, password_hash=={self.password_hash}"


class FindableById(ABC):
    @abstractmethod
    def find_by_id(self, id: int) -> Optional[Identifiable]:
        pass


class ProvidesAuthentication(ABC):
    @abstractmethod
    def find_using_credentials(self, email: str, password: str
                               ) -> Optional[Authenticable]:
        pass


class MockUsersRepository(FindableById, ProvidesAuthentication):
    def __init__(self):
        self.dummy_users = (
            User(1, "example@company.ru", hashfunc("123")),
            User(2, "test@ya.ru", hashfunc("456")),
            User(3, "foobar@gmail.com", hashfunc("789")),
        )

    def find_by_id(self, id: int) -> Optional[Identifiable]:
        return next((
            user for user in self.dummy_users if user.get_id() == id),
            None
        )

    def find_using_credentials(self, email: str, password: str
                               ) -> Optional[Authenticable]:
        for user in self.dummy_users:
            if user.get_email() == email \
                    and user.get_password_hash() == hashfunc(password):
                return user
        return None


class AuthController:
    def login(self, request: Request,
              repository: ProvidesAuthentication):
        user = repository.find_using_credentials(
            request.form["email"], request.form["password"])
        # debug print:
        print(f"user: {user}")
        if user:
            ...  # login and redirect to '/index'
        else:
            ...  # render template login_form.html


if __name__ == "__main__":
    authController = AuthController()
    request = MockRequest({
        "email": "test@ya.ru",
        "password": "456",
    })
    users_repository = MockUsersRepository()

    authController.login(request, users_repository)

НЛО прилетело и опубликовало эту надпись здесь
Вполне.

Давайте посмотрим:
1) Множественное наследование.
2) Реализация абстрактных методов через декоратор + костыль с pass.


Т.е. никто не ударит по рукам, если реализация потеряется, только в рантайме во время вызова. Задача интерфейсов — гарантировать реализацию, а тут игра на внимательность. Ну такое, вроде и повторяет поведение, но костылями и половина плюшек срезается.


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

В какой-нибудь джаве было бы
class MockUsersRepository implements FindableByIdInterface, ProvidesAuthenticationInterface
что ровно то же самое множественное наследование, которое обозвали словом implements. Собственно, как написали в комменте ниже, наличие интерфейсов на уровне синтаксиса — результат того, что разработчики компилятора не шмогли или поленились реализовать полноценное множественное наследование и предоставили вместо него легковесный суррогат — интерфейсы.

Питон динамический язык. За строгими проверками во время компиляции — это к товарищам C#, Java…

pass — это просто элемент синтаксиса. Впрочем, в сколько-нибудь нетривиальных случаях вместо pass пишут док-строку к методу.
"""Method description."""

что ровно то же самое множественное наследование, которое обозвали словом implements.

Проблемы множественное наследования:
1) Не позволяет понимать какая реализация будет использована
2) Не позволяет ссылаться на родителя или потомка (через позднее статическое связывание)


Пересечение:

Интерфейсы и решают эту проблему, позволяя запросто пересекаться методам:


interface ProvidesUuid
{
    public function getId(): UuidInterface;
}

interface Identifiable
{
    public function getId();
}

class User implements Identifiable, ProvidesUuid
{
    ...
}

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


Иерархия

Допустим, у нас есть потомок с переопределением метода:


class Storage {
    public function save(...) { ... }
}

class SomeAnotherStorage {
    public function save(...) { ... }
}

// Наследуемся от этих реализаций (в PHP так нельзя)
class FileStorage extends Storage, SomeAnotherStorage 
{
    final public function save(File $file)
    {
        $file->saveTo('some/directory');

        return parent::save($file); // И к какому parent должно быть обращение?
    }
}

Можно и обратно, из родителя к потомку через late-binding. Главное в том, что сохраняется чёткая иерархия в том случае, если "extends" допускает только одного родителя.


Питон динамический язык. За строгими проверками во время компиляции — это к товарищам C#, Java…

И PHP. Он тоже проверяет что всё корректно перегружено по LSP и все нужные методы имеют реализацию во время компиляции.

Вы видимо не захотели прочитать книгу «Паттерны проектирования» от банды четырех.
Там говорилось об одном важном пункте композиция вместо наследования.
Рекомендую почитать аргументацию, она развенчивает все мифы, указанные по вашей ссылке и дает понимание, когда использовать то или другое.

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

P.S. Строка выше относится к тому, что оригинальная статья опирается на синтаксис языка Java, которая не позволяет использовать множественное наследование. Кроме того, рекомендую прочитать википедию по поводу множественного наследования и убедиться, что оно далеко не так «красиво», как его изображают в вашем материале.
Композиция, как и само понятие «интерфейс», прекрасно существует и без ключевого слова «interface».
Статья написана человеком, сформулировавшим принципы SOLID. Он лжец?
Да, как бы странно это не было, я не считаю в данном случае Мартина правым в данной ситуации. Вернее, не согласен с тем, как этот материал повернут вами в контексте комментария, на который вы его отправили.

Смотрите. Кирилл говорит о том, что реализация на языке Python приводит к проблемам, которые будут найдены непосредственно в рантайме, что недопустимо. Что можно избежать в PHP использовав принципы того же Мартина — ISP + DI с использованием встроенных средств языка, а не внимательности разработчика. Кроме того, он апелирует к тому, что мы перестаем хардкодить и начинаем работать с абстракциями.

Суть комментария в том, что не важно, является ли ключевое слово вредным или нет: такое решение в языках есть и с ним мы живем. Если в Python реализовали множественное наследование через пень-колоду (к слову, сам автор в комментариях согласен с тем, что интерфейсы нужны), не дали нормального способа создавать абстрактные классы и методы, а в PHP это сделать реально, пусть и с использованием «вредного» interface (к слову, я не вижу дублирования кода в данном контексте, хотя если судить по Мартину оно здесь должно быть) — я выберу более безопасный, а как следствие, подходящий инструмент, который меня защитит от этого.

Кроме того. Мартин аппелирует к Eiffel, который решил проблему множественного наследования. Каким образом он это сделал? Мы можем указать, какие методы родительского класса мы наследуем. То есть потенциально доступна ситуация, когда родительский класс имеет какой-то метод, а дочерний — не имеет. Для меня такая ситуация является недопустимой и именно для этого принципиально и нужны интерфейсы. Это контракт, который гарантирует мне работу и ошибки компиляции.

P.S. Я не спорю с самой статьей и идеей. Если бы решилась проблема множественного наследования, принципиально у нас бы было всего два инструмента: класс и интерфейс, а абстрактный класс был бы не нужен, так как его функции перенял бы интерфейс. Ну или наоборот.
Спасибо за развернутый ответ.
Но PHP ведь не компилируется, и проверки тайпхинтов все равно происходят в рантайме. Или нет? Конечно, еще в редакторе будут ошибки подсвечиваться, это плюс, не спорю.
Вот тут вы правы. PHP — интерпретируемый язык программирования, несмотря на opcache и ввод JIT в 8 ветке языка. Но если у PHP есть что-то вроде php -f index.php где он ругнется на неверный синтаксис и бросит (сразу) error, то для python мы это увидим когда непосредственно столкнемся, что может произойти далеко не сразу (знатоки питона, если это не правда — поправляйте). Однако, и правда, все это происходит в рантайме.

Это дело решается тестами, но, поверьте, тесты не всегда хорошие и не всегда имеют 100% покрытия.
И да и нет. Вывод сигнатур языка происходит во время раннего связывания, так что язык знает о них ещё ДО того как что-либо стартануть.

Это можно запросто проверить написав:
return 42;

class Example {}

Класс Example будет доступен всегда, т.к. это инструкция раннего этапа, а return — позднего (рантайма).
Заголовок спойлера
Это почти всегда так за редкими исключениями, декларации в сочетании с if:
return 42;

if (true) {
    class Example {}
}



Построение иерархии зависимостей и перегрузки (переопределения) методов происходят точно так же на раннем этапе. Т.е. язык уже перед тем как запустить какой-либо код внутри файла (файл в PHP это единица компиляции) заранее знает правильно ли сделано наследование/имплементация.

Ну а затем уже происходит рантайм с проверками типов. И вот на этом этапе могут возникнуть другие ошибки типизации.

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

Заголовок спойлера
Ну и вот, например, вдогонку чуть-чуть. Ещё примеры того, как работает php внутри.
const SOME = 'hello' . 42 . 'world';


Эта конструкция выполняется после парсинга, но до рантайма, собираясь в одну единственную инструкцию виртуальной машины. Любая ошибка в ней приведёт к её возникновению ещё до того как код запустился. Если мы добавим что-то спереди — оно выполнено не будет.

$var = 'hello' . 42 . 'world';


А вот это уже инструкция рантайма (т.е. набор инструкций для VM) и поломать её до запуска самой VM могут лишь синтаксические ошибки.
Ну, если совсем грубо — то никто не мешает сделать ровно то же самое на любом друом языке (включая python/ruby), только без сахара в виде вынесения единственного публичного метода класса в интерфейс и проверки типов. Можно точно так же определить соглашение, точно так же реализовать это соглашение в классах, точно так же подменять конкретную реализацию, и т.п. Язык в этом никак не поможет, да, но сделать это всё равно можно, и кода будет написано плюс-минус столько же.
засирания глобального пространства процедурками в Django

Что? В Питоне нет глобального пространства имен, все имена в модулях.

Да, это правда. Я некорректно выразился, имел ввиду вроде таких вот файликов: github.com/django/django/blob/master/django/middleware/csrf.py Где вперемешку кони и люди. Это всё действительно скрыто и наружу отправится только при явном импорте, но выглядит всё равно довольно стрёмно и с повышенной связанностью (cohesion который).
В этом файлике две публичные функции get_token, rotate_token и один публичный класс CsrfViewMiddleware. Прочие функции приватные в соответствии с соглашением об именовании.
Тут просто нужно смириться, что файлики в пайтоне — это не файлики в пхп, а модули и тогда станет легче это воспринимать)
Так я же не кричу во всю глотку что это говнокод (хотя он действительно попахивает магическими константами и хардкодом логики с нарушением open/close). Я просто написал выше, что тем, кто привык к строгости Java/C#/PHP, где один файл — один класс подобные простыни в стиле Python/JS доставляют моральные страдания.

P.S. А не, действительно в самом первом моём комментарии я излишне эмоционально всё это расписал со словами «засирание глобального пространства», что вполне интерпретируется как «говнокод». Только кто-то (не будут тыкать в себя пальцем) забыл про то, что этот код инкапсулируется с помощью магии модулей и PEP во что меня можно смело тыкать носом. В любом случае он лучше того, что обычно творится в JS с теми самыми же модулями. Но всё равно плохой. =)))

Так вроде кричите

Угу, я уже дописал в «P.S.» это. С кем не бывает?

«Нет, с ним всё в порядке, проблем никаких, делает то, что нужно, неудобств не доставляет. Но всё равно плохой.»


Так и скажите, что не нравится, но ещё не придумали, почему.

Ну я же придумал, в самом начале коммента выше отписал:
1) Магические константы
2) Нарушение open/close с харкодом логики

В пыхе для таких штук вначале создаётся интерфейс, а на него уже навешиваются реализации. Отдельно для сессий, отдельно для флеш-токенов, отдельно для…

Вон, у зенда даже зависимости на request нет: github.com/zendframework/zend-expressive-csrf/blob/master/src/SessionCsrfGuard.php Можно прикрутить к консольке. Не знаю зачем, но главное что можно.

P.S. Знаю даже зачем. Можно запилить интеграционное тестирование без селениума и даже без запуска HTTP слоя.

Что такое «попахивает магическими константами»? Там либо есть магические константы, либо нет. В данном случае я ничего такого не вижу. Если вам «попахивает магическими константами», возможно это где-то рядом с вами чем-то пахнет.

Рискну спросить: а как бы вы это написали на PHP?

Конкретно этот кейс? Тогда за предоставление csrf токена должен отвечать соответствующий интерфейс:


interface CsrfProviderInterface
{
    public function getToken(): string;
}

Заголовок спойлера
// Для HTTP реквеста
class RequestCsrfProvider implements CsrfProviderInterface
{
    // Можно в константу с переопределением через наследование.
    // А можно и в переменную.
    protected const CSRF_REQUEST_ATTRIBUTE = 'CSRF_COOKIE';

    public function __construct(ServerRequestInterface $request) { ... }
    public function getToken(): string { ... };
}

// Блокирующий (для тестов, например)
class FlushCsrfProvider implement CsrfProviderInterface
{
    public function getToken(): string
    {
        return \random_bytes(32);
    }
}

class ConstantCsrfProvider implements CsrfProviderInterface {}

Конечно, это адовый оверинжинеринг в рамках обычных проектов, где можно просто TODO оставить и переписать код в любой момент. Но именно так и обязаны писать внутри фреймворков и ядре, где предполагается то, что всё можно заменить. А "META", если не путаю (поправьте) — это HTTP заголовки, которые обязаны быть заменяемыми.

привык к строгости Java/C#/PHP, где один файл — один класс

Не могу перестать удивляться с вашего комментария. В приведенном вами в пример файле ровно один класс.


Но вы не задумывались отчего в PHP (про остальные не скажу) такая строгость (один файл — один класс)? Она там далеко не от излишнего удобства. Просто в PHP есть такое понятие, как автолоад. Если класс не будет лежать в строго определенном месте, он просто не будет найден.


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

Но вы не задумывались отчего в PHP (про остальные не скажу) такая строгость (один файл — один класс)? Она там далеко не от излишнего удобства. Просто в PHP есть такое понятие, как автолоад. Если класс не будет лежать в строго определенном месте, он просто не будет найден.


Класс будет вполне найден. Как раз из-за удобства так и сделано. Автолоад не влияет на ограничения по количеству кода в файлах, их внутренности, никак не влияет на именование и вообще ни на что. Автолоад — это императивная функция языка, которой достаточно подсунуть нужный файл во время триггера события «Class not found»: www.php.net/manual/ru/function.spl-autoload-register.php

Вы путаете инструкцию автолоадинга со стандартами PSR-0 и PSR-4. Ну или PHP перепутали с Java. Т.е. это примерно как сказать то, что все приватные методы должны быть с нижним подчёркиванием. Спека (это в PEP кажется?) говорит одно, а на деле никто не ограничивает.

Не могу перестать удивляться с вашего комментария. В приведенном вами в пример файле ровно один класс.


И две публичные функции с захардкоженными внутри строчками.
для руби есть hanamirb.org

Судя по всему, современный веб развивается настолько бурно, что «готовые решения» существуют только для legacy проектов.


Приведём в пример graphql. С чего бы гипотетический «другой язык», появившийся в 2013 году может иметь менее зрелое решение, чем PHP, если graphql появился в 2015?


Если говорить о «хорошо спроектированных языках», то Laravel появляется в 2011 году, в то время как Rails — в 2005. И Django в 2005. Symphony правда тоже появляется в 2005, но даже если считать что это технологии одного поколения — о каком отсутствии фреймворков вы говорите? А ведь в этих Питонах и Рубях всегда были ООП, и история «объектно ориентированного проектирования» у них побольше чем у PHP.


Кроме того, сегодня среды череды бесконечных одинаковых MVC фреймворков каждый пытается предложить свой изюм. Кто-то говорит «интегрируй АИ легко и нативно» как фреймворка на Python. Кто-то говорит «разрабатывай фронт и бэк одинаково» как нода решения. Кто-то гонится за бешеной скоростью работы на Го. Или бешеной скоростью разработки на рельсах. Или горизонтальным масштабированием из коробки у Erlang/Elixir… Где изюмчик у PHP — для меня загадка. И поэтому слышать «PHP всегда фигурирует при выборе стека разработки» для меня тоже загадка.

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

Конечно, иначе какой в нём смысл?
Не хотим хвастаться, но PHP доминирует в вебе. Если вы занимаетесь веб-разработкой и не рассматриваете использование PHP в своём следующем проекте, то вы что-то делаете неправильно.


Простите, при всей моей ностальгической любви к PHP, вы тег «ирония» потеряли. Осторожнее, люди же читают и верят.
Есть ложь, есть наглая ложь, а есть статистика.

Убираем из этой статистики друпалы, вордпрессы, битриксы и так далее — получим совершенно другую картину.
Ну или можно пойти от обратного — как много вы знаете крупных порталов, продуктов и систем, которые написаны на PHP?

Если кто-то правда сидит и думает, на чём ему написать очередной CRUD — да, PHP отлично под это подходит. Но разбрасываться фразами про «доминирование» и «делаете неправильно» — это очень странно. Причём вне зависимости от контекста.
Тем не менее тезисы «PHP доминирует в вебе» и «PHP занимает 80% рынка» и имеют схожий смысл.
Я к тому что эти «80% рынка» не имеют отношения к разработке, и являются готовыми настроенными решениями. Что никак не должно влиять на решение выбора языка при разработке своего проекта.

Если мы хотим узнать, что именно «на рынке» — можно, посмотреть последний опрос на stackoverflow по используемым языкам, например. Или зайти на hh и сравнить количество вакансий по разным языкам. И увидеть, что там и в помине нет никаких 80% PHP.
Убираем из этой статистики друпалы, вордпрессы, битриксы и так далее — получим совершенно другую картину.


А заодно RoR, Django, .NET… да давайте вообще всё уберём. Ну просто почему бы и нет? За компанию. И вообще интернет — это миф, его не существует!

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


Я так понимаю, что какие-то левые ресурсы mail, yandex и rambler не в счёт? Так же как и госуслуги, ну или кусок vk, кусок facebook, кусок youtube, продукты 1c (тьфу-тьфу), badoo, альфа-банк, delicious, wikipedia, dailymotion, w3 counter, photobucket, avito, lamoda, yahoo, ted, roave, onliner, skyeng, blablacar, pornhub… Кстати, а habr считается крупным или toster? Так-с, дайте подумать, даже не знаю, вроде Вы действительно правы, таких сайтов не существует в природе!

Добавьте в списки Ali и Lazada, ozone...

Если честно, чем дальше идет развитие PHP — тем сильнее он становится похожим на Java/Net. Т.е. если мы условно отходим от парадигмы того, что PHP — это для небольших сайтов, а PHP — это интерпрайз, ПХП просто забирает проверенные фичи из Java/.Net

Например, если мы сравниваем Spring /.Net / Symfony — они как браться близнцы уже=) Особенно если учитывать магию конфигов и аннотаций.

Почему это плохо! Чем сильнее php будет становиться интерпрайз языком, тем выше станут требования к уровню разработчика. А если граница между ПХП и Java станет очень близкой, смысл учить ПХП про пропадет, ведь за тот же уровень усилий за Java платят лучше.

Например, если сейчас попытаться найти разработчика на Symfony, который могет в ООП, Паттерны, Стратегию развития интерпрайз проектов и прочее — вы поймете, что на рынке единицы таких разработчиков, а их уровень оплаты 120 + (что уже не сильно отличается от Java).

т.е. смотрите, почему умер Ruby c ROR (не умер, а потерял популярность) — он оказался сложнее, чем ПХП для тех же задач, и он не мог быть универсльным, как Python.

Если ПХП потеряет свою простоту для веба, у него ничего не будет против Java/.Net
+1, как бы не получили две официальные версии PHP: энтерпрайз решение для нагруженных проектов (платную?), а вторую лайтовую для простых страничек и шард-хостингов (айфон 8? :) ). Как несколько лет назад простой PHP vs PHP-phalcon, HHVM (бесплатные решения, но точка выхода выше)
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь

Надо сделать jit, и написать на пхп интерпретатор питона. Во будет срача..

Мне честно кажется, что python уже опоздал. Пока народ холиварил о "красоте" python, PHP выкатило много крутых обновлений и системы типов, и объектов и производительности. Тот же python ничего сравнимого за эти годы, скажем с PHP 5.5, не сделал.

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

Тогда его пора убирать из списков языков общего назначения.

НЛО прилетело и опубликовало эту надпись здесь

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

Как-то их сайт не очень быстро работает, для компилируемого языка. Или дело в Microsoft Azure на котором их сайт лежит?
Если говорить про такие решения, то есть ещё KPHP. По крайней мере был.
Для своих задач PHP отличный язык, который стремиться всё больше и больше расширить свою сферу применения, не смотря на огромную армию хейтеров. (предлагаю о вкусах не спорить)

А вот чего хочется видеть, так это некого аналога go-рутин и каналов(нативно, без смс, костылей и регистрации)

Зарегистрируйтесь на Хабре , чтобы оставить комментарий