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

Adelf

Administrator
Команда форума
@grigori, мы Entity и VO отбросили уже. Если я правильно понимаю, то говорим о классах без состояний.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
:eek: функциональное программирование на php?
 
Последнее редактирование:

Adelf

Administrator
Команда форума
Ну у меня всегда были проблемы с выражением мыслей :)
Я могу попытаться перефразировать некоторые предложения, если у кого-то есть желание это читать :)
 

Вурдалак

Продвинутый новичок
Плюс погуглил тут специально, в C# библиотеке для моков Moq, чтобы мокать методы реального класса, нужно чтобы они были virtual. В PHP понятное дело такой проблемы нет, у нас все виртуальное. Но там это мешает. Поэтому у меня и образуются такие привычки, переходящие в другие языки.
Если я правильно понимаю, то C# даже с помощью рефлексии не позволит это сделать.

Мне это кажется немного странным. Я не вижу разумных причин делать такое жёсткое разграничение между interface и class. Для меня class — это interface, куда заинлайнили реализацию. Для низкоуровневых вещей типа моков и прокси можно было бы разрешить обходить различные keywords типа final/virtual, как мы обходим private с помощью той же рефлексии.
 

флоппик

promotor fidei
Команда форума
Партнер клуба
Ну так PHP-шный reflection этого и не позволяет сделать :) В смысле, снять final. А CLR Profiling API позволяет?
Эм. В дотнете вообще нет final. Но если считать что final это без virtual методов и с const - то да, позволяет.
 

Вурдалак

Продвинутый новичок
Эм. В дотнете вообще нет final. Но если считать что final это без virtual методов и с const - то да, позволяет.
Ну, sealed он там называется.

То есть, технически можно написать библиотеку для моков на C#, которая бы мокала какой угодно класс с какими угодно методами? Я просто так погуглил, все говорят, что такой технической возможности нет. Если метод, допустим, не virtual, то иди гуляй, либо делай отдельный interface.
 

флоппик

promotor fidei
Команда форума
Партнер клуба
Думал, sealed можно только целиком класс запечатать, но нет, можно методы. Но да, он тоже перекрывается.
 

флоппик

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

Вурдалак

Продвинутый новичок
Собственно, логично, что язык выполняющийся в виртуальной машине и реверсящийся до комментариев, можно перекрыть как угодно?
Я так погуглил, это из разряда runkit/uopz/goaop, если сравнивать с PHP тулзами.

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

Т.е. это уже здорово, что есть какая-то техническая возможность, но по-моему выглядит немного тёмной магией. И похоже выходит за рамки самого языка (C#).
 

Adelf

Administrator
Команда форума
Ну если знать как виртуальные и невиртуальные методы устроены в С++, например(а в C# наверняка примерно также), то становится понятным, что для мока невиртуального метода нужно переколбасить(или перекомпилировать) вызывающий код. Ибо в случае невиртуального метода вызывающему коду вообще плевать на объект, который ему передали - он вызывает конкретный метод конкретного класса напрямую. И заставить его вызвать что-то другое - это реально черная магия.
 

Вурдалак

Продвинутый новичок
@Adelf я так подозреваю, что тут всё вертится по сути вокруг производительности: virtual и заинлайнить не получится и плюс одна проверка в рантайме.
В случае же с более высокоуровневыми языками типа PHP, вероятно, этим можно было бы и пожертвовать (считать все методы виртуальными на уровне байт-кода).
Хотя я вот не в курсе, а вдруг в PHP 7 подобные оптимизации с final уже есть?

FYI в Hack final можно обойти с помощью спец. атрибута у класса-наследника: https://docs.hhvm.com/hack/attributes/special#uncommon
Это наводит на мысль, что там подобных оптимизаций нет.
 

Adelf

Administrator
Команда форума
@Вурдалак, ну в сях вызов обычного метода - это определенный на этапе компиляции прямой вызов по адресу нужной функции = метода класса, что разумеется максимально быстро. Вызов виртуального - обращение к таблице виртуальных методов, и лишь затем вызов метода указанного там. по большому счету, пару тактов процессора + пару чтений памяти, пойти по ссылке на таблицу виртуальных, отсчитать смещение и найти указатель на нужную функцию(метод). Но тогда это было очень много для каждого вызова метода. Сейчас - терпимо.
В PHP 7 - врядли. Есть у меня мнение, что там на анализ возможности оптимизировать больше потратится чем удастся сэкономить.
Upd: хотя про php7 глупость сказал. Почти 100% вероятность BC сломать для всяких мок-библиотек и других тулз поважнее аргумент.
 
Последнее редактирование:

fixxxer

К.О.
Партнер клуба
В php никаких JIT нету, так что рассуждения про вызовы по адресу к нему не применимы.
Другое дело, что для final или private можно использовать ту же логику, что и при вызове функции, а для всего остального надо знать, что у нас там в this такое, так что теоретически могут быть два разных опкода.
 

fixxxer

К.О.
Партнер клуба
Другое дело, что для final или private можно использовать ту же логику, что и при вызове функции, а для всего остального надо знать, что у нас там в this такое, так что теоретически могут быть два разных опкода.
Посмотрел в исходниках - кажется, что-то похожее на то. Но что там дальше внутрях zend_compile_call_common происходит, я, честно говоря, не осилил.
 

Adelf

Administrator
Команда форума
Подозреваю это влияет на то, будет вызов прямым или нет(т.е. то о чем говорил Вурдалак). В этой функции https://github.com/php/php-src/blob/7a73c5f6bba386e0d82dd467e9dacceb10b851e3/Zend/zend_compile.c#L3242 ретурнится код опкода, который будет для вызова этой функции. И он либо ZEND_DO_UCALL, либо ZEND_DO_FCALL[_BY_NAME].
UCALL выглядит как раз прямым вызовом, в отличие от конкурентов. Вот тут - https://github.com/php/php-src/blob/3d84aef55d88753638a5692a98b1ad5dc0e7c242/Zend/zend_vm_def.h#L3467 они описаны.

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