Интерфейсы, именование, равнозначность с абстрактными классами

  • Автор темы Автор темы Adelf
  • Дата начала Дата начала
@grigori, мы Entity и VO отбросили уже. Если я правильно понимаю, то говорим о классах без состояний.
 
:eek: функциональное программирование на php?
 
Последнее редактирование:
Ну у меня всегда были проблемы с выражением мыслей :)
Я могу попытаться перефразировать некоторые предложения, если у кого-то есть желание это читать :)
 
Плюс погуглил тут специально, в C# библиотеке для моков Moq, чтобы мокать методы реального класса, нужно чтобы они были virtual. В PHP понятное дело такой проблемы нет, у нас все виртуальное. Но там это мешает. Поэтому у меня и образуются такие привычки, переходящие в другие языки.
Если я правильно понимаю, то C# даже с помощью рефлексии не позволит это сделать.

Мне это кажется немного странным. Я не вижу разумных причин делать такое жёсткое разграничение между interface и class. Для меня class — это interface, куда заинлайнили реализацию. Для низкоуровневых вещей типа моков и прокси можно было бы разрешить обходить различные keywords типа final/virtual, как мы обходим private с помощью той же рефлексии.
 
Ну так PHP-шный reflection этого и не позволяет сделать :) В смысле, снять final. А CLR Profiling API позволяет?
Эм. В дотнете вообще нет final. Но если считать что final это без virtual методов и с const - то да, позволяет.
 
Эм. В дотнете вообще нет final. Но если считать что final это без virtual методов и с const - то да, позволяет.
Ну, sealed он там называется.

То есть, технически можно написать библиотеку для моков на C#, которая бы мокала какой угодно класс с какими угодно методами? Я просто так погуглил, все говорят, что такой технической возможности нет. Если метод, допустим, не virtual, то иди гуляй, либо делай отдельный interface.
 
Думал, sealed можно только целиком класс запечатать, но нет, можно методы. Но да, он тоже перекрывается.
 
Собственно, логично, что язык выполняющийся в виртуальной машине и реверсящийся до комментариев, можно перекрыть как угодно?
 
Собственно, логично, что язык выполняющийся в виртуальной машине и реверсящийся до комментариев, можно перекрыть как угодно?
Я так погуглил, это из разряда runkit/uopz/goaop, если сравнивать с PHP тулзами.

Тут ещё вопрос нормально ли это использовать в production (для всяких прокси) или это носит примерно тот же характер, что и runkit/uopz: только для тестов.

Т.е. это уже здорово, что есть какая-то техническая возможность, но по-моему выглядит немного тёмной магией. И похоже выходит за рамки самого языка (C#).
 
Ну если знать как виртуальные и невиртуальные методы устроены в С++, например(а в C# наверняка примерно также), то становится понятным, что для мока невиртуального метода нужно переколбасить(или перекомпилировать) вызывающий код. Ибо в случае невиртуального метода вызывающему коду вообще плевать на объект, который ему передали - он вызывает конкретный метод конкретного класса напрямую. И заставить его вызвать что-то другое - это реально черная магия.
 
@Adelf я так подозреваю, что тут всё вертится по сути вокруг производительности: virtual и заинлайнить не получится и плюс одна проверка в рантайме.
В случае же с более высокоуровневыми языками типа PHP, вероятно, этим можно было бы и пожертвовать (считать все методы виртуальными на уровне байт-кода).
Хотя я вот не в курсе, а вдруг в PHP 7 подобные оптимизации с final уже есть?

FYI в Hack final можно обойти с помощью спец. атрибута у класса-наследника: https://docs.hhvm.com/hack/attributes/special#uncommon
Это наводит на мысль, что там подобных оптимизаций нет.
 
@Вурдалак, ну в сях вызов обычного метода - это определенный на этапе компиляции прямой вызов по адресу нужной функции = метода класса, что разумеется максимально быстро. Вызов виртуального - обращение к таблице виртуальных методов, и лишь затем вызов метода указанного там. по большому счету, пару тактов процессора + пару чтений памяти, пойти по ссылке на таблицу виртуальных, отсчитать смещение и найти указатель на нужную функцию(метод). Но тогда это было очень много для каждого вызова метода. Сейчас - терпимо.
В PHP 7 - врядли. Есть у меня мнение, что там на анализ возможности оптимизировать больше потратится чем удастся сэкономить.
Upd: хотя про php7 глупость сказал. Почти 100% вероятность BC сломать для всяких мок-библиотек и других тулз поважнее аргумент.
 
Последнее редактирование:
В php никаких JIT нету, так что рассуждения про вызовы по адресу к нему не применимы.
Другое дело, что для final или private можно использовать ту же логику, что и при вызове функции, а для всего остального надо знать, что у нас там в this такое, так что теоретически могут быть два разных опкода.
 
Другое дело, что для final или private можно использовать ту же логику, что и при вызове функции, а для всего остального надо знать, что у нас там в this такое, так что теоретически могут быть два разных опкода.

Посмотрел в исходниках - кажется, что-то похожее на то. Но что там дальше внутрях zend_compile_call_common происходит, я, честно говоря, не осилил.
 
Подозреваю это влияет на то, будет вызов прямым или нет(т.е. то о чем говорил Вурдалак). В этой функции https://github.com/php/php-src/blob...467e9dacceb10b851e3/Zend/zend_compile.c#L3242 ретурнится код опкода, который будет для вызова этой функции. И он либо ZEND_DO_UCALL, либо ZEND_DO_FCALL[_BY_NAME].
UCALL выглядит как раз прямым вызовом, в отличие от конкурентов. Вот тут - https://github.com/php/php-src/blob...692a98b1ad5dc0e7c242/Zend/zend_vm_def.h#L3467 они описаны.

По поводу BC - я был уверен что мокеры в PHP умеют финальные методы переопределять. Гляну попозже... интересно.
 
Сверху