19

I would like to redefine certain functions in PHP that are already built for example, echo() or time() - I don't need to define these functions globally, just within a single script for testing.

I think this can be done in Perl but in PHP - Is this possible?

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Abs
  • 56,052
  • 101
  • 275
  • 409
  • 1
    possible duplicate of [Is it possible to replace a function in php (such as mail) and make it do something else?](http://stackoverflow.com/questions/1837184/is-it-possible-to-replace-a-function-in-php-such-as-mail-and-make-it-do-someth) – outis Feb 10 '12 at 17:13
  • 1
    ... [Is it possible to replace (monkeypatch) PHP functions?](http://stackoverflow.com/q/530649/), [Php redefine Class Methods OR Class](http://stackoverflow.com/q/137006/) – outis Feb 10 '12 at 17:22
  • ... why would someone do that? – John Dvorak Nov 30 '14 at 21:22

3 Answers3

18

runkit_function_redefine — Replace a function definition with a new implementation

Note: By default, only userspace functions may be removed, renamed, or modified. In order to override internal functions, you must enable the runkit.internal_override setting in php.ini.

Johannes Gorset
  • 8,715
  • 4
  • 36
  • 34
  • Does this have a global effect on all PHP scripts, or is this specific to a particular script? – Abs Feb 24 '10 at 14:57
  • 4
    Editing the php.ini file will affect all PHP scripts running on that particular installation of PHP. The function redifinition itself, however, is exclusive to the scripts that call `runkit_function_redefine()`. – Johannes Gorset Feb 24 '10 at 14:58
  • +1 for runkit - APD is a bit clunky, and it messes up the process exit code, which is going to break using it in test cases. I use the runkit at https://github.com/zenovich/runkit to intercept mt_rand() and time() in test cases, and I'm a happy camper. – Chris Nash Aug 07 '12 at 19:33
  • 1
    Besides testing purposes, does Runkit is a valable solution for a production environnment ? I would like to use it with a solution I can not modify to permits back-office users to preview their front office in the future by rewriting time() and any other function related. Should I stop thinking at Runkit and begin to rewrite most classes of the product ? – JBreton Nov 27 '12 at 09:37
  • @ChrisNash, Happy camper... meaning? – Pacerier Oct 20 '14 at 16:14
  • @JBreton, I believe the purpose of runkit is meant to fix bugs within PHP itself. Making it easy to "patch" a flawed functionality. It doubles up as a stopgap solution for testing purposes too. – Pacerier Oct 20 '14 at 16:15
6

You might also want to check out

override_function() — Overrides built-in functions

from the Advanced PHP debugger package.

Having to redefine native PHP functions or language statements should ring an alarm bell though. This should not be part of your production code in my opinion, unless you are writing a debugger or similar tool.

Another option would be to use http://antecedent.github.io/patchwork

Patchwork is a PHP library that makes it possible to redefine user-defined functions and methods at runtime, loosely replicating the functionality runkit_function_redefine in pure PHP 5.3 code, which, among other things, enables you to replace static and private methods with test doubles.

The latter doesn't work for native functions though

Gordon
  • 312,688
  • 75
  • 539
  • 559
  • @Gordon - thanks for the suggestion. I just want to do this for testing purposes and not production code - you are right it does ring alarm bells! – Abs Feb 24 '10 at 15:19
1

echo is not a function, it's a language construct. I don't have anything for that.

But function calls like time() can be overridden since PHP-5.3's namespace fallback policy:

For functions […], PHP will fall back to global functions […] if a namespaced function […] does not exist.

E.g. for the unqualified function call time() in the non global namespace foo you can provide foo\time().

Personally I'm using this to mock e.g. time() for unit test. I published those mocks in the library PHP-Mock:

namespace foo;

use phpmock\phpunit\PHPMock;

class FooTest extends \PHPUnit_Framework_TestCase
{

    use PHPMock;

    public function testBar()
    {
        $time = $this->getFunctionMock(__NAMESPACE__, "time");
        $time->expects($this->once())->willReturn(3);
        $this->assertEquals(3, time());
    }
}
Markus Malkusch
  • 7,738
  • 2
  • 38
  • 67