Examples

Attention!

This document has been deprecated in favor of the Usage document.

Conventions

Each of the following examples (i. e., separate code snippets, not whole sections) assumes that no redefinitions are in effect before running the code inside them, which can be imagined as each of them having an implicit Patchwork\undoAll() call at the beginning.

On the other hand, all initial declarations and definitions of functions and classes are assumed to persist through all code snippets that contain or follow them.

Contents

Contents ↑

Basic Redefinition

You can replace any named user-defined function or method with any valid PHP callback, that is, an anonymous function, a named function, or a public method (either static or instance).

function babble()
{
    echo "foo";
}            

babble(); # prints "foo"

Patchwork\replace("babble", function()
{
    echo "bar";
});

babble(); # prints "bar"
function sayBaz()
{
    echo "baz";
}    

Patchwork\replace("babble", "sayBaz");

babble(); # prints "baz"
class Greeter
{
    private $name;
    
    function __construct($name)
    {
        $this->name = $name;
    }
    
    function greet()
    {
        echo "Hello ", $this->name, "!";
    }
}

Patchwork\replace("babble", array(new Greeter("World"), "greet"));

babble(); # prints "Hello World!"
Patchwork\replace("babble", "babble");

babble(); # Infinite recursion!
Contents ↑

Delayed Redefinition

Sometimes functions are defined and called in the same file. In such cases, we can use Patchwork\replaceLater to redefine the function in advance and catch these early calls.

# File: first.php

Patchwork\replaceLater("sayNumber", function()
{
    echo 1337;
};   

require "second.php"; # prints 1337
# File: second.php

function sayNumber()
{
    echo 0;
}

sayNumber();
Contents ↑

Arguments and Return Values

Every replacement function receives the same arguments as the original function, and is also allowed to return any value on behalf of the latter.

function size(array $array)
{
    return count($array);
}

size(array(1, 2)); # => 2

const EXAGGERATION_FACTOR = 10;

Patchwork\replace("size", function(array $array)
{
    return count($array) * EXAGGERATION_FACTOR;
});

size(array(1, 2)); # => 20
Contents ↑

Methods and Inheritance

As of version 1.2.0, Patchwork follows inheritance when redefining methods. This means that if Y extends X, then redefining X::foo also redefines Y::foo, unless the foo method is overridden in Y.

class A
{
    function __toString()
    {
        return "A";
    }
}

class B extends A
{
}

class C extends A
{
    function __toString()
    {
        return "C";
    }
}

Patchwork\replace("A::__toString", function()
{
    return "redefined";
});

echo new A; # prints "redefined"
echo new B; # prints "redefined"
echo new C; # prints "C"
Attention!

In Patchwork versions prior to 1.2.0, method redefinitions were not heritable. This means that if Y extends X, then redefining X::foo would not also redefine Y::foo, no matter if it were overridden in Y or not. In the example above, such behavior would present as the echo new B statement printing "A" and not "redefined".

Contents ↑

Falling Back to the Original Definition

Using Patchwork\pass, you can request Patchwork to terminate a replacement function and let the original definition run instead. Note, however, that this does not reverse the replacement altogether.

function sayBar()
{
    echo "bar";
}

Patchwork\replace("sayBar", function()
{
    echo "foo";
    Patchwork\pass();
    echo "This will never be printed";
});

sayBar(); # prints "foobar"
Contents ↑

Magic Methods

Method overloads, which are dispatched in __call and __callStatic magic methods, are not real named methods, so they cannot be redefined directly. In such cases, the respective "double-underscore" dispatchment methods should be redefined instead.

class MagicEcho
{
    function __call($method, $args)
    {
        echo $method . " ";
        return $this;
    }
}

$echo = new MagicEcho;

$echo->foo(); # prints "foo "

Patchwork\replace(array($echo, "__call"), function($method, $args) use ($echo)
{
    if ($method == "not") {
        # Skip the word
        return $echo;
    }
    Patchwork\pass();
});

$echo->I()->am()->not()->redefined(); # prints "I am  redefined "

Contents ↑

Undoing All Redefinitions

All redefinitions that have been performed since the beginning of runtime can be reversed at once by calling Patchwork\undoAll().

sayBar(); # prints "bar"
sayBaz(); # prints "baz"

function remainSilent()
{
    echo "...";
}

Patchwork\replace("sayBar", "remainSilent");
Patchwork\replace("sayBaz", "remainSilent");

sayBar(); # prints "..."
sayBaz(); # prints "..."

Patchwork\undoAll();

sayBar(); # prints "bar"
sayBaz(); # prints "baz"
Contents ↑

Undoing a Single Redefinition

Separate redefinitions can be undone by using the Patchwork\undo function.

sayBar(); # prints "bar"

$censorship = Patchwork\replace("sayBar", function()
{
    echo "censored";
});

sayBar(); # prints "censored"

Patchwork\undo($censorship);

sayBar(); # prints "bar"