PHP - Override Existing Function

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();

How to override built-in PHP function(s)?

I think it could be done like so:

//First rename existing function
rename_function('strlen', 'new_strlen');
//Override function with another
override_function('strlen', '$string', 'return override_strlen($string);');

//Create the other function
function override_strlen($string){
return new_strlen($string);
}

found it here

Notice that every host must have http://php.net/manual/en/book.apd.php installed on the server.

Edit

Another way is to use namespaces

<?php
namespace mysql2pdo;
use PDO;
function mysql_connect() {
return new PDO();
}
echo mysql_connect(); // Causes error because we don't have the parameters
?>

Test it here

PHP - override existing function

Only if you use something like APD that extends the zend engine to allow for that:

Intro

Override Method Docs

Note: Runkit seems like a better option than APD since it's more specific to this purpose and would allow you to keep the original method intact at a different address.

PHP override function of a single instance

In order to fully understand what you are trying to achieve here, your desired PHP version should be known first, PHP 7 is more ideal for OOP approaches than any previous version.

If the binding of your anonymous function is the problem, you can bind the scope of a function as of PHP >= 5.4 to an instance, e.g.

$a->testFunc = Closure::bind(function() {
// here the object scope was gone...
$this->var = "overridden";
}, $a);

As of PHP >= 7 you can call bindTo immediately on the created Closure

$a->testFunc = (function() {
// here the object scope was gone...
$this->var = "overridden";
})->bindTo($a);

Though your approach of what you are trying to achieve is beyond my imagination. Maybe you should try to clarify your goal and I'll workout all possible solutions.

Override default php function

You can use namespaces to override existing function names:

namespace blarg;
function basename() {
return 'whatever';
}
$base = basename();

I.e., any call to basename() within the blarg namespace will use your new version of the function.

PHP overriding method of an object

This is not possible, and luckily so, as it would pose a huge security risk.

Reflection API does allow accessing of methods, but not changing its implemention.

See also

* Is it possible to modify methods of an object instance using reflection

* http://www.stubbles.org/archives/65-Extending-objects-with-new-methods-at-runtime.html


Update

While you cannot replace the implementiation of a function, you can change the value of a otherwise hidden field using reflection:

<?php

class A {

private $item = 5;

public function getItem() {
return $this->item;
}

}

$obj = new A();

$reflect = new ReflectionClass($obj);
$property = $reflect->getProperty('item');
$property->setAccessible(TRUE);
$property->setValue($obj, 10);

echo $obj->getItem(); // 10

Redefining PHP function?

Nope, that throws an error:

Fatal error: Cannot redeclare foo()

The runkit provides options, including runkit_function_rename() and runkit_function_redefine().

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.

Override a function inside a class assigned to a variable

You can't override the method by assigning another function to it in the way that you suggested in the example in your question. It is possible to assign a closure to a property with the same name of an existing method, but that does not override the method. It's still just a property that has a function as a value.

You could theoretically extend the mysqli_result class, but I don't know how you'd get mysqli::query() to return it.

The only way I can think of to override it is by wrapping the result object in a class that provides the additional functionality.

$result = $mysqli->query($sql);

$result = new class($result) {
private $result;

public function __construct($result) {
$this->result = $result;
}

public function fetch_assoc() {
$row = $this->result->fetch_assoc();
// Do extra stuff to $row
return $row;
}

public function __call($name, $arguments) {
return $this->result->$name(...$arguments);
}
};


Related Topics



Leave a reply



Submit