Redefining PHP function? - php

If I have a function:
function this($a){
return $a;
}
If I wanted to redefine the function, would it be as simple as rewriting it?
function this($a, $b){ //New this function
return $a * $b;
}

Nope, that throws an error:
Fatal error: Cannot redeclare foo()
The runkit provides options, including runkit_function_rename() and runkit_function_redefine().

If you mean overloading in a Java sense, then the answer is no, this is not possible.
Quoting the PHP manual on functions:
PHP does not support function overloading, nor is it possible to undefine or redefine previously-declared functions.
You could use the runkit extension but usage of runkit in production scenarios is generally considered doubtful practice. If you want to exchange algorithms at runtime, have a look at the Strategy pattern or Anonymous functions instead.
If by redefine you mean add to an existing userland function, refactor, substitute or rewrite, then yes: it is as simple as you've shown. Just add the additional code to the function, but make sure you set a default for backwards compatibility.
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.

You can't redefine or 'undefine' a function in PHP (without resorting to third-party modules). However, you can define a function conditionally.
So, if you know function A can be defined elsewhere, but not always, you can wrap it like this:
if (!function_exists('A')) {
function A() {
// default A implementation
}
}
Then you only need to make sure the implementation you want is encountered first:
function A() {
// another A implementation
}

I've got a library of functions that sometimes I just don't want invoked while I'm testing (typically database updates). If I have, for example, a few different db update functions that are all over the code. instead of commenting out the code, I just create a special class (e.g. class foo {}). Define a global variable (e.g., $DEBUG) and a dummy function (e.g., function dummy {}).
Inside foo define all the (public static) functions you need to mimic as
$fn = isset($DEBUG) ? 'dummy' : 'real function';
return call_user_func_array($fn,func_get_args());
Plus you have the advantages of now doing other things, like logging the calls and parameters.
Then simply replace all your calls to real_function(...) with foo::real_function(...). Usually just a simple search/replace (or leave it there; depending on what's going on in the function and how often it's getting called the overhead may be irrelevant).

I have good news and bad news.
The good news
It is possible (link(s) below).
The nadnews
There are 2 bad news:
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.
And the second bad news: You havbe to sacrifice code readability.
Example:
<?php
function this($a){
return $a;
}
echo this(0);
$f_name = 'this';
$f_args = '$a';
$f_code = 'return $a*$b;';
runkit_function_redefine($f_name, f_args, f_code);
echo this(1,3);
Oh, and one more thing, using this as a name for a function may create confusion, due to the methods of a object of a class being able to use this.something to reffer to the variable something that is in the method and have the same name as the variable something from the object itself. Here is an example
<?php
class theclass{
$a = 'a';
function a($a){
echo $a;
$a = this.$a;
}
}
theclass $object = new theclass();
$object -> a('b'); // will echo: ab

You cannot redeclare functions, without runtime hacking, but in various situations you may, in fact, redefine them.
Namely, if they are stored in a variable. Though, under the hood this is really reassigning the symbol to a new function.
$action['doSomething'] = function($arguments){
return 'false';
};
$action['doSomething'] = function($arguments){
return var_export($arguments,true);
};
echo $action['doSomething']('Hello world');
There is also the case of inheritance.
namespace CoolCorp\AwesomeGame;
class World{
const TILE_SIZE = 8; // size in pixels of an N x N square
const GAME_TICK = 25; // milliseconds between action sequence frames
const UP = 1;
const DOWN = 2;
const LEFT = 3;
const RIGHT = 4;
.
.
}
class Character2D{
const WALK = 1;
const RUN = 2;
public $mode=1;
public $x=0;
public $y=0;
public $next_x=0;
public $next_y=0;
.
.
public function move($direction){
$selected_mode = self::$mode == self::RUN ?
__NAMESPACE__ . '\RunMode'
: __NAMESPACE__ . '\WalkMode';
class_alias($selected_mode, 'game_movement');
switch($direction){
case UP: game_movement::up($this); break;
case DOWN: game_movement::down($this); break;
case LEFT: game_movement::left($this); break;
case RIGHT: game_movement::right($this); break;
}
$this->AnimateNextPositionAsync(WORLD::GAME_TICK);
}
public function move_Alternative($direction){
$game_movement = self::$mode == self::RUN ?
__NAMESPACE__ . '\RunMode'
: __NAMESPACE__ . '\WalkMode';
switch($direction){
case UP: $game_movement::up($this); break;
case DOWN: $game_movement::down($this); break;
case LEFT: $game_movement::left($this); break;
case RIGHT: $game_movement::right($this); break;
}
$this->AnimateNextPositionAsync(WORLD::GAME_TICK);
}
.
.
}
class WalkMode{
public static function up($actor){
$actor->next_y -= World::TILE_SIZE;
};
public static function down($actor){
$actor->next_y += World::TILE_SIZE;
};
public static function left($actor){
$actor->next_x -= World::TILE_SIZE;
};
public static function right($actor){
$actor->next_x += World::TILE_SIZE;
};
}
class RunMode extends WalkMode{
public static function up($actor){
$actor->next_y -= World::TILE_SIZE*2;
};
public static function down($actor){
$actor->next_y += World::TILE_SIZE*2;
};
public static function left($actor){
$actor->next_x -= World::TILE_SIZE*2;
};
public static function right($actor){
$actor->next_x += World::TILE_SIZE*2;
};
}
A bit contrived but illustrative of how you may redefine a function in a child class and use to achieve a goal. The second example assumes you are not using an ancient PHP version.

You can't have both functions declared at the same time, that will give an error.

You can't redeclare it. If your question is just about overloading that example, how about:
function this($a, $b=1)
{
return $a * $b;
}

Setting an appropriate default to any new arguments that you add might help for backwards compatibility, i.e.:
function this($a, $b=1){ //New this function with a sane default.
return $a * $b;
}
I also recommend, for clarity, generally avoiding using this for function/variable names.

Related

Storing a Closure Function in a Class Property in PHP

ok I do have the code below
<?php
class foo{
public $bar = NULL;
public function boo(){
$this->bar();
}
}
$mee = new foo();
//save a closure function on the property
$mee->bar = function(){
echo 'hahaha';
};
//invoke the closure function by using a class method
$mee->boo();
?>
and you can see it running here http://codepad.org/s1jhi7cv
now what i want here is to store the closure function on the class method.
well closures are possible as i read the documentation about it here http://php.net/manual/en/functions.anonymous.php
is this possible? did i went to something wrong? please correct me
Your example code at codepad.org does not work because codepad.org uses PHP 5.2.5, and closure support was only added in 5.3.
However, your code will also not work in a PHP version that supports closures, although you will get a different error: http://codepad.viper-7.com/Ob0bH5
This is a limitation of PHP at present. $obj->member() looks for a method named member and will not look at properties to see if they are callable. It is, frankly, annoying.
The only way I am aware of to make this work without call_user_func()/call_user_func_array() is:
public function boo() {
$func = $this->bar;
$func();
}
You need to exploit some magic functionality of PHP (__call) to make use of that. Extend from Extendable for example:
class Extendable {
static function import($context) {
$self = new static();
while (is_callable($context)) $context = $context($self);
if (is_array($context) || is_object($context) || is_a($context, 'Traversable')) {
foreach($context as $key => $value)
$self->$key = &$value; # preserve keys if
}
return $self;
}
public function __call($name, $args) {
if (isset($this->$name) && is_callable($this->$name)) {
return call_user_func_array($this->$name, $args);
}
throw new BadFunctionCallException(sprintf('Undefined function %s.', $name));
}
}
And you can do the job. It's not that nice. Background and examples are in one of my blog posts:
PHP: Extending stdClass with Closures (plus Visitor)
You can naturally implement that magic functionality your own, too.
Use call_user_func() function:
<?php
class foo{
public $bar = NULL;
public function boo(){
call_user_func($this->bar);
}
}
$mee = new foo();
//save a closure function on the property
$mee->bar = function(){
echo 'hahaha';
};
//invoke the closure function by using a class method
$mee->boo();
This will display "ahahah"
Hope it helps.
You will not be able to do that.
Take for example this code:
class T {
function foo() {
echo 'T::foo';
}
}
$t = new T;
$t->foo = function() {
echo 'Closure::foo';
};
$t->foo();
It works fine on PHP 5.4.6 and/or PHP 5.3.16, however it will result in T::foo getting printed.
This happens because methods, in PHP, are not modifiable class properties, as they are for example in javascript.
However,
$foo = $t->foo;
$foo();
will print Closure::foo as expected.
PHP is not a prototype based language hence you cannot redefine functions
Use __call to catch all non-defined methods and then look up the closure and invoke it. Take a look at my post on this SitePoint thread.
Starting at php 7, you can put round brackets around the instance and method to call the method like so: ($this->bar)();.
This appears to cause a syntax error on earlier versions however.

Static Inheritance prior to PHP 5.3

class A
{
static $v = "A";
static function echoExtendedStaticVariable() {
echo self::$v;
}
}
class B extends A
{
static $v = "B";
// override A's variable with "B"
}
Why does:
echo B::$v
print "A"?
And how do I get it to print "B"?
Is there a way to do this before PHP 5.3?
B->echoExtendedStaticVariable() == 'A' because self:: is evaluated at compile-time, not run-time. It's as if you wrote A:: instead of self::.
What you want is a feature called "late static binding"--it's "late" because it can determine the class at runtime instead of at compile-time.
You can emulate this (sort-of) in PHP 5.2 using ReflectionClass:
class A
{
static $v = "A";
function echoExtendedStaticVariable() {
$rc = new ReflectionClass($this);
echo $rc->getStaticPropertyValue('v');
}
}
class B extends A
{
static $v = "B";
}
$b = new B();
$b->echoExtendedStaticVariable(); // B
Note that you can only do this if you have access to an instance, so you can't make echoExtendedStaticVariable a static method and expect this to work.
There is no way to do this easily in PHP 5.2 (i.e.: without explicitly overriding each method).
When you call B::echoExtendedStaticVariable, it forwards to A::echoExtendedStaticVariable, the scope changes to the one of A and all bindings about B are gone. No backtrace, no reflection, no magic constants, nothing: it all points to A.
In my opinion, static members should be avoided unless really necessary, and it is rarely the case. It renders your code difficult to extend, since dependency injection is limited and substitution is almost impossible (except in anti- patterns like Singleton).

php Set a anonymous function in an instance

I am just starting out with PHP, and I am wondering if there is a way to add an anonymous function to a class instance.
For instance, lets say...
class A{
public B;
}
$c = new A();
//This is where I am getting a little confused...
//The following wont work
$c->B = function(){echo('HelloWorld');};
$c->B();
What I am hoping to do is reuse the same spit of code in a great number of different applications, and make it so that I can just 'swap-out' and replace functions in specific instances.
I am using php5.3 (so anonymous functions should work, just not in the way that I am using them).
Thanks so very much for your time!!
-GK
You can use the __call magic function for this job. Not a beauty, but it works..
like this:
class A {
public $B;
public function __call($closure, $args)
{
call_user_func_array($this->$closure, $args);
}
}
$c = new A();
$c->B = function () { echo('HelloWorld'); };
$c->B();
FWIW:
PHP 5.3's treatment of anonymous functions is entertaining. This won't work:
$c->B = function() { echo func_get_arg(0); };
$c->B("This fails :(");
This WILL work:
$c->B = function() { echo func_get_arg(0); };
$hilarious = $c->B;
$hilarious("This works!");
To work around this, you need to use a __call hack like the one provided by Oden.
This behavior may change in the future. The array dereferencing RFC was recently committed to PHP's trunk, and the patch has set off a discussion on function call chaining, the syntax of which may allow what you're trying to do without the __call hack. Unfortunately it's proven difficult in the past to get function call chaining working.
# real ugly, but PoC...
class a {
function __call($f, $x) {
call_user_func_array($this->$f, $x);
}
}
$a = new a;
$a->b = function() { echo "Hello world"; };
$a->b();
Sounds like you are describing a Strategy Pattern or Decorator Pattern - there are other ways to achieve this in way which is more easily communicated with other developers who read your code.
You can do something along these lines (which will also work with callbacks that are not closures):
<?php
class A {
private $fun;
function setFun($fun) {
if (!is_callable($fun))
throw new InvalidArgumentException();
$this->fun = $fun;
}
public function fun() {
call_user_func_array($this->fun, func_get_args());
}
}
$c = new A();
$c->setFun(function($a) { echo('HelloWorld ' . $a);});
$c->fun("here");
which gives HelloWorld here.
That said, you should also consider inheritance or the decorator pattern.
This is not an issue anymore by PHP 7;
// no error
$result = ($this->anonFunc)();
$result = ($this->anonFunc)($arg1, $arg2, ...);
See more about AST.
Rather than hooking a __call magic method into your class, you can instead execute the callable directly using call_user_func.
class A {
public $b;
}
$c = new A();
$c->b = function(){echo('HelloWorld');};
call_user_func($c->b); // HelloWorld
Obviously it would be nice for PHP to provide some syntax to execute this directly.

What is function overloading and overriding in php?

In PHP, what do you mean by function overloading and function overriding. and what is the difference between both of them? couldn't figure out what is the difference between them.
Overloading is defining functions that have similar signatures, yet have different parameters. Overriding is only pertinent to derived classes, where the parent class has defined a method and the derived class wishes to override that method.
In PHP, you can only overload methods using the magic method __call.
An example of overriding:
<?php
class Foo {
function myFoo() {
return "Foo";
}
}
class Bar extends Foo {
function myFoo() {
return "Bar";
}
}
$foo = new Foo;
$bar = new Bar;
echo($foo->myFoo()); //"Foo"
echo($bar->myFoo()); //"Bar"
?>
Function overloading is not supported by PHP. It occurs when you define the same function name twice (or more) using different set of parameters. For example:
class Addition {
function compute($first, $second) {
return $first+$second;
}
function compute($first, $second, $third) {
return $first+$second+$third;
}
}
In the example above, the function compute is overloaded with two different parameter signatures. *This is not yet supported in PHP. An alternative is to use optional arguments:
class Addition {
function compute($first, $second, $third = 0) {
return $first+$second+$third;
}
}
Function overriding occurs when you extend a class and rewrite a function which existed in the parent class:
class Substraction extends Addition {
function compute($first, $second, $third = 0) {
return $first-$second-$third;
}
}
For example, compute overrides the behavior set forth in Addition.
Strictly speaking, there's no difference, since you cannot do either :)
Function overriding could have been done with a PHP extension like APD, but it's deprecated and afaik last version was unusable.
Function overloading in PHP cannot be done due to dynamic typing, ie, in PHP you don't "define" variables to be a particular type. Example:
$a=1;
$a='1';
$a=true;
$a=doSomething();
Each variable is of a different type, yet you can know the type before execution (see the 4th one).
As a comparison, other languages use:
int a=1;
String s="1";
bool a=true;
something a=doSomething();
In the last example, you must forcefully set the variable's type (as an example, I used data type "something").
Another "issue" why function overloading is not possible in PHP:
PHP has a function called func_get_args(), which returns an array of current arguments, now consider the following code:
function hello($a){
print_r(func_get_args());
}
function hello($a,$a){
print_r(func_get_args());
}
hello('a');
hello('a','b');
Considering both functions accept any amount of arguments, which one should the compiler choose?
Finally, I'd like to point out why the above replies are partially wrong;
function overloading/overriding is NOT equal to method overloading/overriding.
Where a method is like a function but specific to a class, in which case, PHP does allow overriding in classes, but again no overloading, due to language semantics.
To conclude, languages like Javascript allow overriding (but again, no overloading), however they may also show the difference between overriding a user function and a method:
/// Function Overriding ///
function a(){
alert('a');
}
a=function(){
alert('b');
}
a(); // shows popup with 'b'
/// Method Overriding ///
var a={
"a":function(){
alert('a');
}
}
a.a=function(){
alert('b');
}
a.a(); // shows popup with 'b'
Overloading Example
class overload {
public $name;
public function __construct($agr) {
$this->name = $agr;
}
public function __call($methodname, $agrument) {
if($methodname == 'sum2') {
if(count($agrument) == 2) {
$this->sum($agrument[0], $agrument[1]);
}
if(count($agrument) == 3) {
echo $this->sum1($agrument[0], $agrument[1], $agrument[2]);
}
}
}
public function sum($a, $b) {
return $a + $b;
}
public function sum1($a,$b,$c) {
return $a + $b + $c;
}
}
$object = new overload('Sum');
echo $object->sum2(1,2,3);
Although overloading paradigm is not fully supported by PHP the same (or very similar) effect can be achieved with default parameter(s) (as somebody mentioned before).
If you define your function like this:
function f($p=0)
{
if($p)
{
//implement functionality #1 here
}
else
{
//implement functionality #2 here
}
}
When you call this function like:
f();
you'll get one functionality (#1), but if you call it with parameter like:
f(1);
you'll get another functionality (#2). That's the effect of overloading - different functionality depending on function's input parameter(s).
I know, somebody will ask now what functionality one will get if he/she calls this function as f(0).
Method overloading occurs when two or more methods with same method name but different number of parameters in single class.
PHP does not support method overloading.
Method overriding means two methods with same method name and same number of parameters in two different classes means parent class and child class.
I would like to point out over here that Overloading in PHP has a completely different meaning as compared to other programming languages. A lot of people have said that overloading isnt supported in PHP and by the conventional definition of overloading, yes that functionality isnt explicitly available.
However, the correct definition of overloading in PHP is completely different.
In PHP overloading refers to dynamically creating properties and methods using magic methods like __set() and __get(). These overloading methods are invoked when interacting with methods or properties that are not accessible or not declared.
Here is a link from the PHP manual : http://www.php.net/manual/en/language.oop5.overloading.php
Overloading: In Real world, overloading means assigning some extra stuff to someone. As as in real world Overloading in PHP means calling extra functions. In other way You can say it have slimier function with different parameter.In PHP you can use overloading with magic functions e.g. __get, __set, __call etc.
Example of Overloading:
class Shape {
const Pi = 3.142 ; // constant value
function __call($functionname, $argument){
if($functionname == 'area')
switch(count($argument)){
case 0 : return 0 ;
case 1 : return self::Pi * $argument[0] ; // 3.14 * 5
case 2 : return $argument[0] * $argument[1]; // 5 * 10
}
}
}
$circle = new Shape();`enter code here`
echo "Area of circle:".$circle->area()."</br>"; // display the area of circle Output 0
echo "Area of circle:".$circle->area(5)."</br>"; // display the area of circle
$rect = new Shape();
echo "Area of rectangle:".$rect->area(5,10); // display area of rectangle
Overriding : In object oriented programming overriding is to replace parent method in child class.In overriding you can re-declare parent class method in child class. So, basically the purpose of overriding is to change the behavior of your parent class method.
Example of overriding :
class parent_class
{
public function text() //text() is a parent class method
{
echo "Hello!! everyone I am parent class text method"."</br>";
}
public function test()
{
echo "Hello!! I am second method of parent class"."</br>";
}
}
class child extends parent_class
{
public function text() // Text() parent class method which is override by child
class
{
echo "Hello!! Everyone i am child class";
}
}
$obj= new parent_class();
$obj->text(); // display the parent class method echo
$obj= new parent_class();
$obj->test();
$obj= new child();
$obj->text(); // display the child class method echo
There are some differences between Function overloading & overriding though both contains the same function name.In overloading ,between the same name functions contain different type of argument or return type;Such as:
"function add (int a,int b)" & "function add(float a,float b);
Here the add() function is overloaded.
In the case of overriding both the argument and function name are same.It generally found in inheritance or in traits.We have to follow some tactics to introduce, what function will execute now.
So In overriding the programmer follows some tactics to execute the desired function where in the overloading the program can automatically identify the desired function...Thanks!
Overloading: Declaring a function multiple times with a different set of parameters like this:
<?php
function foo($a) {
return $a;
}
function foo($a, $b) {
return $a + $b;
}
echo foo(5); // Prints "5"
echo foo(5, 2); // Prints "7"
?>
Overriding: Replacing the parent class's method(s) with a new method by redeclaring it like this:
<?php
class foo {
function new($args) {
// Do something.
}
}
class bar extends foo {
function new($args) {
// Do something different.
}
}
?>
PHP 5.x.x does not support overloading this is why PHP is not fully OOP.

PHP syntax to call methods on temporary objects

Is there a way to call a method on a temporary declared object without being forced to assign 1st the object to a variable?
See below:
class Test
{
private $i = 7;
public function get() {return $this->i;}
}
$temp = new Test();
echo $temp->get(); //ok
echo new Test()->get(); //invalid syntax
echo {new Test()}->get(); //invalid syntax
echo ${new Test()}->get(); //invalid syntax
I use the following workaround when I want to have this behaviour.
I declare this function (in the global scope) :
function take($that) { return $that; }
Then I use it this way :
echo take(new Test())->get();
What you can do is
class Test
{
private $i = 7;
public function get() {return $this->i;}
public static function getNew() { return new self(); }
}
echo Test::getNew()->get();
Why not just do this:
class Test
{
private static $i = 7;
public static function get() {return self::$i;}
}
$value = Test::get();
Unfortunately, you can't do that. It's just the way PHP is, I'm afraid.
No. This is a limitation in PHP's parser.
i often use this handy little function
function make($klass) {
$_ = func_get_args();
if(count($_) < 2)
return new $klass;
$c = new ReflectionClass($klass);
return $c->newInstanceArgs(array_slice($_, 1));
}
usage
make('SomeCLass')->method();
or
make('SomeClass', arg1, arg2)->foobar();
Impossible and why would you create an object this way at all?
The point of an object is to encapsulate unique state. In the example you gave, $i will always be 7, so there is no point in creating the object, then getting $i from it and then losing the object to the Garbage collector because there is no reference to the object after $i was returned. A static class, like shown elsewhere, makes much more sense for this purpose. Or a closure.
Related topic:
http://www.mail-archive.com/internals#lists.php.net/msg44919.html
http://bugs.php.net/bug.php?id=23022&edit=1
http://www.mail-archive.com/internals#lists.php.net/msg07610.html
This is an old question: I'm just providing an updated answer.
In all supported versions of PHP (since 5.4.0, in 2012) you can do this:
(new Test())->get();
See https://secure.php.net/manual/en/migration54.new-features.php ("Class member access on instantiation").
This has come up very recently on php-internals, and unfortunately some influential people (e. g. sniper) active in development of PHP oppose the feature. Drop an email to php-internals#lists.php.net, let them know you're a grownup programmer.

Categories