Можно ли заменить (monkeypatch) функции PHP?

Вы можете сделать это в Python, но возможно ли это в PHP?

>>> def a(): print 1
... 
>>> def a(): print 2
... 
>>> a()
2

e.g.:

<? function var_dump() {} ?>
Fatal error: Cannot redeclare var_dump() in /tmp/- on line 1

person gak    schedule 10.02.2009    source источник


Ответы (6)


Это немного поздно, но я просто хочу отметить, что, начиная с PHP 5.3, можно переопределить внутренние функции без использования расширения PHP.

Хитрость в том, что вы можете переопределить внутреннюю функцию PHP внутри пространства имен. Он основан на том, как PHP разрешает имена для функций:

Внутри пространства имен (скажем, A\B) вызовы неквалифицированных функций разрешаются во время выполнения. Вот как разрешается вызов функции foo():

  1. Он ищет функцию из текущего пространства имен: A\B\foo().
  2. Он пытается найти и вызвать глобальную функцию foo().
person Silviu G    schedule 08.08.2013
comment
Скорее всего, потому что он был опубликован почти через четыре года после вопроса, а принятый ответ был, вероятно, наиболее актуальным на тот момент. - person Silviu G; 26.03.2015
comment
Я все еще на ТАК... Принято! - person gak; 14.01.2016

Нет, это невозможно сделать, как вы могли ожидать.

Из manual:

PHP не поддерживает перегрузку функций, а также невозможно отменить или переопределить ранее объявленные функции.

ОДНАКО, вы можете использовать runkit_function_redefine и его аналоги, но это конечно не очень элегантно...

Вы также можете использовать create_function, чтобы сделать что-то вроде этого:

<?php
$func = create_function('$a,$b','return $a + $b;');
echo $func(3,5); // 8
$func = create_function('$a,$b','return $a * $b;');
echo $func(3,5); // 15
?>

Как и в случае с runkit, это не очень элегантно, но дает нужное вам поведение.

person Paolo Bergantino    schedule 10.02.2009
comment
Вы сказали это дважды, но почему это не очень элегантно? - person Pacerier; 25.03.2015
comment
@Pacerier: Ну, во-первых, желание сделать это с самого начала немного пахнет кодом, и это определенно отпугнет любого, кто идет за вами, чтобы посмотреть на ваш код, но если вы пройдете через это вам придется вводить код функции в виде строкового аргумента в обоих случаях, что неприглядно для всего, кроме самых коротких функций. - person Paolo Bergantino; 25.03.2015
comment
Наверняка мы как минимум на PHP 5.3, String больше никто не делает, код функции можно предоставить как анонимную функцию. - person Pacerier; 29.03.2015
comment
@Pacerier: я никогда не использовал эту функцию, и этот ответ был написан 6 лет назад, и мне не особо интересно его изучать, но в руководстве говорится, что в качестве аргумента для него принимается только строка. Однако анонимные функции можно/нужно использовать для решения подобных задач в ›5.3. - person Paolo Bergantino; 29.03.2015

Я понимаю, что этот вопрос немного устарел, но Patchwork — это недавно выпущенный PHP 5.3. проект, поддерживающий переопределение пользовательских функций. Хотя, как отмечает автор, вам нужно будет прибегнуть к runkit или php-test-helpers для обезьяны -патч ядра/библиотеки функций.

person jmikola    schedule 02.11.2010
comment
Очень хорошая маленькая библиотека. Спасибо, что поделился :) - person maček; 08.12.2011

Вроде. См. http://dev.kafol.net/2008/09/php-redefining-deleting-adding.html.

person Sophie Alpert    schedule 10.02.2009
comment
Ссылка мертва. - person Mikaël Mayer; 11.05.2021

Как упомянул jmikola, Patchwork — хорошее решение, если вы хотите добавить код в функцию.

Вот статья о том, как это работает: http://phpmyweb.net/2012/04/26/write-an-awesome-plugin-system-in-php/

Он поставляется с некоторым образцом кода. Я думаю, что версия phpmyweb использует немного лучший код, потому что он не использует код eval(), в отличие от пэчворка. Вы можете кэшировать коды операций при использовании eval().

person Vivendi    schedule 27.04.2012
comment
почему вам нужно беспокоиться о кеше кода операции при модульном тестировании? Или что... вы используете исправление обезьяны для чего-то другого, кроме тестирования?? в этом случае у вас есть проблемы посерьезнее, чем eval(), о которых нужно беспокоиться. - person Spudley; 15.05.2012
comment
@Spudley Очевидно, статья, которую я разместил, не предназначена для модульного тестирования (отсюда и название «Напишите потрясающую систему плагинов»). Он просто показывает другой способ создания архитектуры плагинов. И еще он говорит, что просто хочет показать еще один способ создания такой архитектуры. Конечно, это обсуждается, если это хороший способ. Хотя я не вижу в этом никаких проблем. --- О каких "проблемах" вы говорите? Как сказал автор, кэширование кода операции не должно быть проблемой, поскольку eval() вообще не используется (в отличие от пэчворка). - person Vivendi; 15.05.2012
comment
@Vivendi, использует ли пэчворк функции runkit для внутреннего использования? - person Pacerier; 07.04.2015
comment
@Pacerier Нет, он использует класс streamWrapper. При этом вы можете в основном переписать включенные исходные файлы, прежде чем они будут проанализированы интерпретатором PHP. - person Vivendi; 08.04.2015
comment
@Pacerier Потому что вы не можете создать экземпляр класса StreamWrapper. Вы можете переопределить его, только зарегистрировав собственную реализацию класса streamWrapper с помощью stream_wrapper_register. Вы знаете, какие методы вы можете переопределить, потому что PHP сообщает вам, какие методы доступны по ссылке, которую вы разместили. - person Vivendi; 15.04.2015

Принятый ответ отличный!!! Я просто добавлю, что вы можете поместить свои коды в скобки пространства имен, а затем по умолчанию GLOBAL-SPACE сбрасывается.

некоторые другие способы:

1) rename_function($old_name,$new_name)

2) override_function($old_name, $parameters, $new_func)

и редко используется:

3) runkit_function_rename(...)

4) runkit_function_redefine(...)

person T.Todua    schedule 17.11.2016