Is it possible to rename a class method in PHP 5.2 during run time? Is it possible to do that using Reflection?
Given:
class Test
{
public function myMethod()
{
echo 'in my method';
}
}
I want to be able to rename myMethod() to oldMethod() so that later I do this:
$test = new Test();
$test->oldMethod(); // in my method
$test->myMethod(); // run time error: method does not exist
From comment below question:
because I would like to install call event handlers on classes, without the classes knowing about it, so I would know that the user is calling a method from a class before that method is actually called.
Solution: use a Decorator.
class EventDecorator
{
protected $_instance;
public function __construct($instance)
{
$this->_instance = $instance;
}
public function __get($prop)
{
printf('Getting %s in %s', $prop, get_class($this->_instance));
return $this->_instance->$prop;
}
public function __set($prop, $val)
{
printf('Setting %s with %s in %s',
$prop, $val, get_class($this->_instance));
return $this->_instance->$prop = $val;
}
public function __call($method, $args)
{
printf('Calling %s with %s in %s',
$method, var_export($args, TRUE), get_class($this->_instance));
return call_user_func_array(array($this->_instance, $method), $args);
}
}
Then you can wrap any class into it:
class Foo
{
public $prop;
public function doSomething() {}
}
$foo = new EventDecorator(new Foo);
$foo->prop = 'bar'; // Setting prop with bar in Foo
$foo->prop; // Getting prop in Foo
$foo->doSomething('something');
// Calling doSomething with array (0 => 'something',) in Foo
This can be fleshed out to provide pre and post hooks. You could also make the Decorator use the Subject/Observer Pattern and fire events to whatever other object registered to the decorator. The above approach is more maintainable and understandable than monkeypatching random methods with runkit.
Additional notes:
You might be interested in the Symfonys EventDispatcher component.
If you are after Aspect Oriented programming, read http://sebastian-bergmann.de/archives/573-Current-State-of-AOP-for-PHP.html - it's from 2006 but there is not much changed in that field since then.
If you are after horizontal reuse, you will like PHP's Trait functionality that is supposed to be in one of the next few versions.
Using Runkits runkit_method_rename you can do this.
For all of you who are asking why you would need this, I have an idea that is very similar. My idea is to attempt to rename an entire PHP Class on the fly. It would be used, in my case, for an IRC Chat bot that I would have load and instantiate plugins on the fly, so that I would no need to reboot the bot and uptime would be very long. This would include renaming of pre-loaded classes of the same name as the class I would be attempting to load, so that there would be no conflict and it would run properly.
For example:
I have $bot running on irc.example.com
I have the plugin test.php installed and working, now when this is loaded into memory I can alter the file test.php without any change to $bot
So I update test.php
Now I want to cause it to load into $bot, but $bot already has a test load in it, and it would conflict if I attempted to include test.php again
so instead, we run a rename function to rename class test to class test[sha1 of a counter]
and then we include 'test.php'
$bot->test = new test();
and there we have it, an updated test plugin installed and loaded into memory on $bot with no reboot.
This is all theory, but it's something to think about before instantly flaming someone for their ideas with the "Why would you even need this" attitude.
I mean, let's be honest here. What are the odds that you're a super genius who knows everything there is to know about programming and would know what everyone would or wouldn't need?
Related
I'm in the process of trying to track outdated or unused functions inside an object class. One idea I had was to create a new class that inherits that original class, and then "track" when that parent's functions are called. When detected, I will migrate the parent's function into the child until eventually only the necessary/needed functions exist.
Is there code that does this automatically within PHP? Here is in example.
class OldUser {
function getFullName() {
return "{$this->firstName} {$this->lastName}";
}
}
class User extends OldUser {
}
-----
$user = new User;
echo $user->getFulLName();
Then in a log somewhere I note:
"{timestamp} function getFullName() called"
Obviously I could add these logs manually, but if there is an existing way for PHP to do it I'd love to default to that methodology.
Alternatively, if there is a better way to do this I am open to suggestions.
Thanks!
If your code is too magic for static code analysis tools, you should probably write some integration/functional tests for your app and take a look at code coverage - non-covered methods may be a dead code (or you need more tests). After this you will not only have cleaner code, but also useful test, so two birds with one stone. :)
One possible way to achieve this without having to manually add the calls is to use a class that doesn't inherit the class you want to track/log:
Something around these lines should do it:
class User{
private $old_user;
// use the same signature of your class constuctor here
public function __construct($arg1, $arg2, ...)
{
$this->old_user = new OldUser($arg1, $arg2, ...);
}
public function __call($name, $arguments)
{
log(sprintf("%s: function %S() called", date('Y-m-d H:i:s'), $name));
call_user_func_array([$this->old_user,$name], $arguments);
}
}
All you need to do from there is implement all of the public methods of OldUser and have those calls trigger the logging and then call the parent function. eg:
class User extends OldUser {
protected function log($method, $backtrace) {
// ...
}
public function getFullName() {
$this->log(__METHOD__, debug_backtrace());
return parent::getFullName();
}
}
debug_backtrace() will allow you to track down where in the code that the function was called.
I'm writing a plugin for WooCommerce, Today something came across my mind suddenly, I was thinking if there is a way to expend PHP Classes like the way we do that in JavaScript without touching anything in the PHP class( Since WooCommerce will get updated and our changed will be gone ).
I found solutions like using __call method but like i said, the class shouldn't be edited. I want to be able to use something like this WC()->My_custom_method() without touching Woocommerce class.Is it even possible?
For example in JavaScript all we need to do is :
Foo.prototype.bar = function (){
// ...
}
Foo.bar();
PHP does not have prototypical inheritance and classes have no prototype like in JavaScript. You can simulate what you are asking with some hackery, but that will ultimately result in hard to maintain code. So don't go there.
There is a GitHub project at https://github.com/bdelespierre/prototype.php with a Proof of Concept implementation. You might find it interesting to study.
Needless to say, if your aim is just to add some functionality to a class, you can still use PHP's inheritance, e.g. extend the WooCommerce class and add your modifications in the subclass. Then use an instance of that new class instead, e.g.
class MyClass extends SomeWooCommerceClass {
public function bar() {
// your own implementation of bar
}
}
$myObj = new MyClass();
$myObj->bar();
If your aim is to change the behavior of an existing object instance, consider wrapping the instance into a Decorator, e.g.
class WooCommerceDecorator {
private $instance;
public function __construct(SomeWooCommerceClass $instance) {
$this->instance = $instance;
}
public function foo() {
$original = $this->instance->foo();
$original+= 42;
return $original;
}
// … more methods
Then use it by passing the object to the decorator:
$woo = new SomeWooCommerceClass();
$decoratedWoo = new WooCommerceDecorator($woo);
echo $decoratedWoo->foo();
Also see the PHP manual on Inheritance
Your best call would be to use extended class.
class MyClass extends Foo {
public function methodInFoo() {
echo "I Am extended";
parent::methodInFoo();
}
public function additionalFunction() {
echo "I am new method that is not presented in Foo";
}
}
That way you even can have Composer to auto-update core classes and while you are using this extended class, you will have your own functions along with all functionality in core class.
I don't recommend this but you could do something like
class Test {
private $myMethods = array();
public addMethod($name, $func) {
$myMethods[$name] = $func;
}
public callMethod() {
$myMethods[$name]();
}
}
....
$test->addMethod("doSomething", function(){ echo 123;});
$test->callMethod("doSomething");
I didn't test the code it's just an idea
I have a problem here, which I have been thinking about for the past few days.
In a php application to do something with a object you need to:
define it
run a function with it
like so:
(with autoloading, and a registry object)
$registry->obj = new mathClass($var1,$var2); //creates object where $var1 holds the a database object, and $var2 holds the value 1 for example
$registry->obj->calculate('value'); //fetches product rows and returns their total value.
This way at any time in the script i can simply run the calculate function (or some other function) that I defined beforehand.
Imagine a web application that has hundreds of classes that might or might not be required for this specific page load, but can only be defined at the start of the application.
The desired solution is that I simply run
$obj->calculate('price');
without creating the object, for example like this
mathclass::calculate('price');
this then autoloads the mathclass as required without having the principal overhead, the problem here is that I can no longer give the mathclass any variables at the start
($var1,$var2).
What I want is to be able to pseudo-create the object without any autoloading of the class happening, as to not add the overhead, but that the object creates itself with the variables but only when I actually need to do something with it.
I mean does php really expect me to define each and every class at the start so that I can later use them?
is this Lazy-loading? Eager loading?
I might be explaining this badly so please point me in the right direction.
Edit 2015: Simple pseudocode example solution:
class Service {
private $cb, $instance;
public function __construct($cb){
$this->cb = $cb;
}
public function __invoke() {
if(!$this->instance){
$this->instance = call_user_func($this->cb);
}
return $this->instance;
}
}
// setup autoloading
set_include_path(__DIR__.'/vendor'. PATH_SEPARATOR .get_include_path()); // optional
spl_autoload_register(function($c){
include preg_replace('#\\\|_(?!.+\\\)#','/',$c).'.php';
});
// simple dependency injection
$service['db'] = new Service(function(){
return new Database('sqlite::filename.sqlite');
});
$service['config'] = function() use(&$service){
return new Config($service['db']());
};
$service['math'] = function() use(&$service){
return new Math($service['config']());
};
// usage
$service['math']()->calculate('price');
Use a Dependency Injection Framework. It lets you configure your classes from config files and when you need a class you simply call it through the service builder.
You can use a lazy loading factory, i.e.
class Registry
{
private $registeredClasses;
private $loadedClasses;
private $objects;
public function RegisterClass($className, array $parameters)
{
// ... store class ...
}
private function Load($className)
{
// Load the class via some sort of autoloader
}
private function CreateInstance($className)
{
$parameters = $this->GetParametersFor($className);
$this->CreateNewInstanceWithParameters($className, $parameters);
}
public function GetObject($className)
{
if (!$this->IsAvailable($className))
{
$this->Load($className);
$this->CreateInstance($className);
}
return $this->GetInstanceOf($className);
}
}
Later in your code you use it like this:
$registry = new Registry();
$registry->RegisterClass("math", array("var1" => $var1, "var2" => $var2));
...
$registry->GetObject("math")->calculate($x1, $x2);
...
Ofc you need to add the parts i was too lazy to add, i.e. the autoloading.
if you use the autoload functionality it will only load the math class when you instantiate it, 1 option is to instantiate it when you need it, another option is to use some kind of wrapper class that will include and call the class.
What you can use is Static classes in PHP. Although this is something you might consider not doing for high-traffic websites.
Declare a class like so:
class Something
{
private static $var = "something";
public static function PrintVar()
{
echo self::$var;
}
}
Now you can include this class and execute the code anywhere you like without initializing the object.
Like so:
Something::PrintVar();
prints
something
Good luck!
Part of the reason why class objects require defining using new() is because they consume memory. Normally PHP will perform memory cleanup at the end of script if you havent done so, but usually in a constructor/destructor object-oriented environment you would want to unset() that class object to free up memory. Earlier versions of PHP (before php4) had issues with memory leaks due to these reasons.
If you want to avoid the whole initialization process you may just want to try a simple include library, such as this:
<?
if (!function_exists("calculate"))
{
function calculate($var1={default},$var2={default})
{
...routine...
}
}
?>
And then you do not have to deal with the whole pain of defining a full class for a simple routine.
i just got some more questions while learning PHP, does php implement any built in plugin system?
so the plugin would be able to change the behavior of the core component.
for example something like this works:
include 'core.class.php';
include 'plugin1.class.php';
include 'plugin2.class.php';
new plugin2;
where
core.class.php contains
class core {
public function coremethod1(){
echo 'coremethod1';
}
public function coremethod2(){
echo 'coremethod2';
}
}
plugin1.class.php contains
class plugin1 extends core {
public function coremethod1(){
echo 'plugin1method1';
}
}
plugin2.class.php contains
class plugin2 extends plugin1 {
public function coremethod2(){
echo 'plugin2method2';
}
}
This would be ideal, if not for the problem that now the plugins are dependable on each other, and removing one of the plugins:
include 'core.class.php';
//include 'plugin1.class.php';
include 'plugin2.class.php';
new plugin2;
breaks the whole thing...
are there any proper methods to doing this?
if there are not, them i might consider moving to a different langauge that supports this...
thanks for any help.
edit:
obviously it is my understanding that is lacking, so here is a
attempt at a clarification.
core.class.php contains anything...
plugin1.class.php contains anything...
plugin2.class.php contains anything...
include 'core.class.php';
include 'plugin1.class.php';
include 'plugin2.class.php';
$core = new core;
$core->coremethod1();//outputs plugin2method1
whereas:
include 'core.class.php';
include 'plugin2.class.php';
$core = new core;
$core->coremethod1();//outputs plugin1method1
I'm interested in any implementation, even one not involving classes
for example
include 'core.php';
//does core stuff
include 'core.php';
include 'plugin1';
//does extended core stuff
include 'core.php';
include 'plugin2';
//does extended core stuff
include 'core.php';
include 'plugin2';
include 'plugin1';
//does very extended core stuff
including a file needs to change the application behavior. for it to have any meaning.
I do not know what this is called either, so point me at the proper naming if there is any.
You are misusing the term "plugin". A plugin is generally a package of code that extends or alters the base functionality of a system - to make actual PHP plugins (which in the PHP world are called extensions) you'd be writing C or C++.
What you're describing here is merely including classes or class trees into the current execution for usage. And there is a way to bring them into the current execution context 'automatically', and that's via the autoload system.
If, after you've read the documentation on autoloading, you are still unsure of how to move forward, comment here and I will help you along.
EDIT
Ok, I see what you're after. You can't do exactly what you're after. When you execute new core; an instance of the class core will be returned - you can't modify that at all.
However, if you are willing to modify how you create instances of core, then I think I have something that could work for you, and it might look something like this.
class core {
public function coremethod1(){
echo 'coremethod1';
}
public function coremethod2(){
echo 'coremethod2';
}
/**
* #return core
*/
final public static function create()
{
// listed in order of preference
$plugins = array( 'plugin2', 'plugin1' );
foreach ( $plugins as $plugin )
{
if ( class_exists( $plugin ) )
{
return new $plugin();
}
}
return new self;
}
}
class plugin1 extends core {
public function coremethod1(){
echo 'plugin1method1';
}
}
class plugin2 extends plugin1 {
public function coremethod2(){
echo 'plugin2method2';
}
}
$core = core::create();
// test what we have
echo get_class( $core ), '<br>'
, $core->coremethod1(), '<br>'
, $core->coremethod2()
;
If your only concern is that not including plugin1 will create an error, then you can resort to autoloading to have plugin2 load plugin1 automatically:
From the comments in the PHP Manual on spl_autoload
// Your custom class dir
define('CLASS_DIR', 'class/')
// Add your class dir to include path
set_include_path(get_include_path().PATH_SEPARATOR.CLASS_DIR);
// You can use this trick to make autoloader look
// for commonly used "My.class.php" type filenames
spl_autoload_extensions('.class.php');
// Use default autoload implementation
spl_autoload_register();
If, however, you are looking for a traits/mixin-like feature, then the answer is no. PHP does not support this as of now. At least not without patching the core or resorting to these two APIs you do not want to use in production code.
The proper way to change how an object behaves at runtime would be to use Decorators:
$class = new BasicCache( new BasicValidators ( new Basic ) );
or Strategy patterns:
$class = new Basic;
$class->setStrategy(function() { return 'foo'} );
echo $class->callStrategy(); // foo
$class->setStrategy(function() { return 'bar'} );
echo $class->callStrategy(); // bar
See http://sourcemaking.com/design_patterns for the most common patterns.
EDIT Here is an example of how to create plugins with decorators. Assume, we have a game of some sort where some non-player characters walk around in a virtual space and greet the main character from time to time. That's all they do right now. We want some variation on how they greet though, which is why we need our plugins/decorators in this scenario.
First we create an interface that defines some methods any object able to greet should have. We don't care about what it does when these methods are invoked on a specific object. We just want to make sure that the methods are available and that they are called with a clearly defined input:
interface GreetInterface
{
public function greet($name);
public function setGreeting($greeting);
}
An interface is basically a contract any implementing object must fulfill. In our case, the contract says, if you are an object that can greet, you have to have two methods. Implement them any way you like, but have these methods.
Let's build our non-player character classes now, implementing this interface
class Dude implements GreetInterface
{
protected $greeting = 'hello';
public function greet($name)
{
return sprintf('%s %s', $this->greeting, $name);
}
public function setGreeting($greeting)
{
$this->greeting = $greeting;
return $this;
}
}
That's pretty straigtforward I guess. The Dude class just defines the two methods from the interface. When greet() is called, it will fetch the string stored in greeting and prepend to the param passed to the greet method. The setGreeting method allows us to change the greeting at runtime. Note: you could add a getter as well (I was just lazy)
Now on to the plugins. We will create an abstract GreetPlugin class to contain some shared boilerplate code, simply because we don't want to duplicate code in our actual plugins. The abstract plugin class will implement the GreetInterface, so we can make sure all subclasses implement the interface too.
Since Dude already implements the interface as well, we could have the plugins extend Dude, but that would be conceptually wrong, because extending creates an is-a relationship, but a plugin is not a Dude.
abstract class GreetPluginAbstract implements GreetInterface
{
protected $inner;
public function __construct(GreetInterface $inner)
{
$this->inner = $inner;
}
public function setGreeting($greeting)
{
$this->inner->setGreeting($greeting);
return $this;
}
public function greet($name)
{
return $this->inner->greet($name);
}
}
The plugin class accepts one argument when initialized: any class implementing the GreetInterface. The TypeHint makes sure, the class fulfills the contract. That's required, because, as you can see in the code, our plugins will need to call the methods in the interface on the class passed through the constructor. If we had extended from Dude, we would now be able to wrap dudes into dudes, which is a bit odd. Another reason for not doing it.
Now on to the first plugin. We want some of our dudes to speak with a fancy french accent, which means they use âccénts all over the place, but cannot pronounce a proper h. Disclaimer: yes, I know that's a cliche. Please bear with my examples
class FrenchPlugin extends GreetPluginAbstract
{
public function greet($name) {
return str_replace(array('h', 'e'), array('', 'é'),
$this->inner->greet($name));
}
}
Since the Plugin extends the abstract plugin, we can now focus on the actual code that modifies how a regular dude would do his greeting. When greet() is called, we call greet() on the wrapped element and then remove all h characters and turn all es into és. Everything else is unmodified abstract behavior.
In another plugin, we want to change the wording of the greeting, so we have some dudes say Heya, instead of just Hello. Just to add some variation.
class EasyGoingPlugin extends GreetPluginAbstract
{
protected $inner;
public function __construct(GreetInterface $inner) {
$this->inner = $inner->setGreeting('heya');
parent::__construct($inner);
}
}
This way we only override the constructor, because the greet method should just return whatever it will be. So we call the setGreeting method on the object passed to this plugin. Because the object has to implement the GreetInterface, we can be sure this works.
Note that I am assigning the return value of setGreeting as the inner object. This is possible because I return $this, whenever setMethod is called. This cannot be enforced through the interface, so you cannot rely on this form the interface. I just added it to show another technique: method chaining.
With two plugins done, we feel we have enough variation. Now we only need a convenient way to create Dudes. For that we create a small class like this:
class DudeBuilder
{
public static function build()
{
$dude = new Dude();
$decorators = func_get_args();
foreach($decorators as $decorator) {
$decorator .= "Plugin";
// require_once $decorator;
$dude = new $decorator($dude);
}
return $dude;
}
}
Note: I always mix up Builder and AbstractFactory, so if the above is a Factory, well, then it's a factory. Check out the design patterns links I gave earlier on ;)
All this Builder does, is create a regular dude and then wrap/decorate it into/with whatever plugins we tell it to use and than return it. Because the builder encapsulates no own state, we make the build method static.
For this example I assume you used the autoloading code I gave right on top. If not, you can include the plugin files in the foreach loop. Lazy loading them only when they are needed will give you a few microseconds faster load times over including them all on top. Hopefully, this also explains what I meant in the various comments when I argued the behavior should not be controlled by a file inclusion. The file inclusion is just a necessity. You cannot use a class that is not know to PHP. But that the class is actually used, is controlled by our code alone, by passing in the plugin names to the build method.
Let's do this now
$regularDude = DudeBuilder::build();
$frenchDude = DudeBuilder::build('French');
$easygoingDude = DudeBuilder::build('EasyGoing');
$frenchEasyGoingDude = DudeBuilder::build('French', 'EasyGoing');
This is effectively the same as doing:
$regularDude = new Dude;
$frenchDude = new FrenchPlugin(new Dude);
$easygoingDude = new EasyGoingPlugin(new Dude);
$frenchEasyGoingDude = new FrenchPlugin(new EasyGoingPlugin(new Dude));
With just two plugins, we can now create three types of Dudes. Let's have them greet you:
echo $regularDude->greet('Yuri'), PHP_EOL,
$frenchDude->greet('Yuri'), PHP_EOL,
$easygoingDude->greet('Yuri'), PHP_EOL,
$frenchEasyGoingDude->greet('Yuri'), PHP_EOL;
// gives
hello Yuri
éllo Yuri
heya Yuri
éya Yuri
We can now create additional plugins to decorate our basic classes with. If for some reason, you decide your game should have talking horses or cars as well, you could also create a class Car or Horse and have it implement the greet interface too and add a Builder for them. You can then reuse the plugins to create French EasyGoing Cars or Horses.
PHP core can be extended with PECL extensions (which are C++, I believe).
Core functions can be overridden (if you have the APD PECL extension installed) with override_function
User functions can be executed with call_user_func.
Maybe if you could explain what you are planning, we'd be able to offer a better answer?
Your code is breaking because plugin2 extends plugin1, and you're not including the plugin1 class. Why not make class plugin2 extend core? That seems to be what you're going for.
Is there a way I can set up callbacks on (or automataically log) method parameters, entries, and exits without making explicit calls within each method? I basically want to log this information to my logger class (which is static) without having to do it manually for each method.
Right now I have to call Logger::logEntry() and Logger::logExit() in every method to accomplish this. I would love to not have to do this:
class TestClass {
public function tester($arg) {
Logger::logEntry();
Logger::info('Parameter $arg => ' . $arg);
// Do some stuff...
Logger::logExit();
}
}
use a wrapper class. this method has the following benefits:
no need to change your underlying class structure / method signatures
change logging? just update this class
update object calls vs inserting code into every class you want to log
.
class LogWatch {
function __construct($class) {
$this->obj = $class;
}
function __call($method, $args) {
if (in_array($method, get_class_methods($this->obj) ) ) {
Logger::logEntry();
Logger::info('Parameter '.implode(', ', $args) );
call_user_func_array(array($this->obj, $method), $args);
Logger::logExit();
} else {
throw new BadMethodCallException();
}
}
}
$test = new LogWatch(new TestClass() );
$test->tester();
// you can use instances of `LogWatch()` just like your watched class
// including passing appropriate params:
$test->tester($param1, $param2);
If you want to do function logging for the sake of debugging you may want to look into the Xdebug extension. There's no good way to intercept function calls at at runtime, and any automated interception will add great runtime overhead.
Using XDebug you could instead turn it on as-needed, as well as get lots of other stuff
( XDebug is thus used with PHPUnit to do unit testing and coverage analysis. )
Xdebug
PHPUnit
The Problem with __call
__call may look to be a fun solution to the problem, but there are 3 problems with this, namely
Significant Execution Overhead. your doing __call --> call_user_func_array , which will literally add not one, but two function calls to every execution.
Backtraces become indecipherable: The actual function you were trying to call gets lost in a sea of __call and call_user_func_array making backtracing exceedingly hard, especially if your backtraces come with their arguent lists included.
Stupid Hidden Functions: You're going back to PHP4 style "hiding" of functions by prefixing them with _ to stop the user directly calling it or seeing it, because if the function name happens to be named what they wan't, the __call wont trigger, so you have already got a whole class full of really horrible function names, which developers will be tempted to call directly anyway in various places. ( And if you want to get rid of __call later, you will have to rename all these functions as to not break the code! )
Thus, if you are utilising php code to implement this will result in epically horrible code, that any future user of your codebase will NOT want to work with. You are far better getting something ( like Xdebug ) that can be added transparently when you need it, and save greatly polluting your code.
you could use the magic function __call. It gets called when no functions match that name. Rename your methods to be prefixed with something, (eg: underscore), and optionally set them to private/protected.
class TestClass {
public function __call($function, $args) {
Logger::logEntry();
Logger::info('Parameters: ' . implode(", ", $args);
$localFunc = "_" . $function;
$return = $this->$localFunc($args);
Logger::logExit();
return $return;
}
private function _tester() {
// do stuff...
return "tester called";
}
}
$t = new TestClass();
echo $t->tester();
// "tester called"