Is it possible to replace (monkeypatch) PHP functions?
This is a bit late, but I just want to point out that since PHP 5.3, it is actually possible to override internal functions without using a PHP extension.
The trick is that you can redefine an internal PHP function inside a namespace. It's based on the way PHP does name resolution for functions:
Inside namespace (say A\B), calls to unqualified functions are resolved at run-time. Here is how a call to function foo() is resolved:
- It looks for a function from the current namespace: A\B\foo().
- It tries to find and call the global function foo()
Is it possible to overwrite a function in PHP
Edit
To address comments that this answer doesn't directly address the
original question. If you got here from a Google Search, start here
There is a function available called override_function that actually fits the bill. However, given that this function is part of The Advanced PHP Debugger extension, it's hard to make an argument that override_function()
is intended for production use. Therefore, I would say "No", it is not possible to overwrite a function with the intent that the original questioner had in mind.
Original Answer
This is where you should take advantage of OOP, specifically polymorphism.
interface Fooable
{
public function ihatefooexamples();
}
class Foo implements Fooable
{
public function ihatefooexamples()
{
return "boo-foo!";
}
}
class FooBar implements Fooable
{
public function ihatefooexamples()
{
return "really boo-foo";
}
}
$foo = new Foo();
if (10 == $_GET['foolevel']) {
$foo = new FooBar();
}
echo $foo->ihatefooexamples();
monkey patching in php
In the case of http://till.klampaeckel.de/blog/archives/105-Monkey-patching-in-PHP.html what actually makes the difference is the \ character used in front of the second strlen.
When you are using namespaces you can either use
a namespace and directly invoke the methods/classes declared in the namespace:
use TheNamespace;
$var = new TheClass();
Or invoke the class explicitly by using something like:
$var = new \TheNamespace\TheClass();
So by invoking \strlen()
instead of strlen()
you are explicitly requesting PHP to use the default strlen and not the strlen defined for this namespace.
As for monkey patching you could use runkit (http://ca.php.net/runkit). Also with regards to patchwork there are a fair amount of examples in their website (http://antecedent.github.com/patchwork/docs/examples.html). You could check the magic method example that is replacing a function in a class.
Monkey patching in PHP 7
You might wanna use smth like:
class Module
{
private $version;
public function __construct($version){
$this->version = $version;
}
public function methodToTest()
{
if ($this->version === '4.0.0') {
// allow for additional options/methods
} else {
// use a subset
}
}
}
or another option would be injecting not version but a provider for that (if you know you will have some bit of complicated logic for versioning control -- so you can split the logic between Module
and Provider
as appropriate):
class Module
{
private $versionProvider;
public function __construct($provider){
$this->versionProvdier = $provider;
}
public function methodToTest()
{
if ($this->versionProvider->getVersion() === '4.0.0') {
// it could be even $this->versionProvider->newFeaturesAreSupported()
} else {
// some other stuff
}
}
}
and still another could be implementing some proxy class like
class Module
{
public function methodToTest()
{
$myMonostateProxy = new MyMonostateProxy();
$version = $myMonostateProxy->getVersion();
if ($version === '4.0.0') {
// allow for additional options/methods
} else {
// use a subset
}
}
}
so you can mock your monostate separately (probably via reflectioning on privtates or via its public interface, anyway don't forget to tearDown
it). Real implementation of it would just call that uncontrollable Driver::getVersion()
.
I think first two options are cleaner but require some efforts for creation (as you need some injection to perform).
Third has that hidden dependecy and is somewhat tricky in testing and thus not quite clean and needs more efforts to maintaine but hides all that choice stuff inside itself making regular usage easier.
PHP Monkey Patching for 3rd party classes
The Patchwork library is so easy and I make it work with few tries.
http://patchwork2.org/
- Monekey patch any internal and other methods.
- Easy to use.
Can I wrap functions in PHP?
Frame challenge: if you did succeed in this, it would be using a blacklist to achieve security, which is basically impossible to do effectively. For every function you replace with a "safe" version, there will be ten you hadn't thought of that can be used in a malicious way.
Instead, you should either use a whitelist or a sandbox.
In a whitelist approach, you don't let the user enter normal PHP at all, but a special set of functionality that you've carefully picked to allow them to do what they need. That could be an actual subset of PHP that you parse with something like nikic/php-parser, a templating language like Twig, or a completely new language you write a simple parser for.
In a sandbox approach, you allow the user to enter full PHP, but you run it in an isolated environment where they can't affect your real server. Any access to the file system or network would only be accessing virtual resources, and if the process abuses CPU or memory resources, the entire sandbox can be terminated. See for instance how the 3v4l.org site is hosted.
How to overwrite existing PHP functions without APD?
Yes, by using
runkit_function_redefine
— Replace a function definition with a new implementation
It's a PECL extension and can be installed via PEAR. But keep in mind that redeclaring functions does not substitute for proper refactoring. You are just exchanging one evil for another.
Also see Is it possible to replace (monkeypatch) PHP functions?
Related Topics
Check Whether $_Post-Value Is Empty
Undefined Variable Problem with PHP Function
How to Find Unused Functions in a PHP Project
Fatal Error: Class 'Ziparchive' Not Found In
Add Extra Meta for Orders in Woocommerce
Create New Variables from Array Keys in PHP
Call to a Member Function Execute() on Boolean In
How to Render a Datetime Object in a Twig Template
Prevent Browser's Back Button Login After Logout in Laravel 5
Getting Http Code in PHP Using Curl
Get Week Number (In the Year) from a Date PHP
How to Sort an Array of Utf-8 Strings
How to Echo a MySQLi Prepared Statement
How to Generate Random 64-Bit Value as Decimal String in PHP