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 th开发者_如何转开发is 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.
精彩评论