I would like to add some logic before and after every time I'm using a method (doesn't really matter if is private, protected or public) in a class.
For example:
class Service
{
function test1() {
Log:start(__METHOD__);
someLogicInThere(); ....
Log:end(__METHOD__);
}
function test2() {
Log:start(__METHOD__);
someLogicInThere(); ....
Log:end(__METHOD__);
}
...
}
My idea is to finally have something like this:
/**
* #LogDecorate
*/
class Service
{
function test1() {
someLogicInThere();
}
function test2() {
someLogicInThere();
}
...
}
Use annotations is not important. There is any way to do that?
As your question-title already suggests, you could use the Decorator Pattern for this. I'm not quite sure though if a full-stack Decorator pattern is necessary here. If it's a really simple use-case, something like this could suffice.
What you could do, is extend the class and 'route' all calls to the extended class. Then add some logic before and after, and call the parent method in between. Something like this:
class Service {
function method1() {
doSomeFunkyStuff();
}
function method2() {
doSomeOtherFunkyStuff();
}
}
class DecoratedService extends Service {
function method1() {
Log::start(__METHOD__);
parent::method1();
Log::end(__METHOD__);
}
function method2() {
Log::start(__METHOD__);
parent::method2();
Log::end(__METHOD__);
}
}
$service = new DecoratedService();
$service->method1();
$service->method2();
Now you can either choose to use the original Service or use the DecoratedService. The funcionality is the same, and the DecoratedService will not have to be altered if the Service changes, assuming the method names won't change (which would actually be a bad thing).
But also look to the wiki page (or any other resource) to understand fully what's the intent of the Decorator Pattern. This (above) might not be the ideal solution for your problem.
EDIT a bit more automatic as requested, sir.
As you cannot change the visibility of methods, using the magic __call() doesn't work (as public or protected parent methods will be accessible from the child as well). But, what you can do, is create your own call method!
class DecoratedService extends Service {
function call($method) {
if(!method_exists(parent, $method)) {
return false; // OR:
throw Exception;
// OR handle this case some other way
}
Log::start(array(parent, $method));
call_user_func(array(parent, $method));
Log::end(array(parent, $method));
}
}
$service = new DecoratedService;
$service->call('method1');
I guess, it is a typicall case of Smart Reference Pattern (some mix of Proxy and Decorator Patterns).
class A {
function test1() {
echo 'TEST 1', PHP_EOL;
}
function test2() {
echo 'TEST 1', PHP_EOL;
}
}
class ProxyA {
protected $wrapped;
public function __construct($wrapped) {
$this->wrapped = $wrapped;
}
public function __call($name, $args) {
echo 'Log:start';
$this->wrapped->$name($args);
echo 'Log:end';
}
}
$proxy = new ProxyA(new A());
$proxy->test1();
But it works only for public methods.
Mixing Smart Reference with DecoratedService::call() method from #giorgio and #yceruto answer can cover all method, or just implement __call() twice:
class A {
public function test1() {
echo 'TEST 1', PHP_EOL;
}
private function test2() {
echo 'TEST 2', PHP_EOL;
}
public function __call($name, $args) {
if (method_exists($this, $name)) {
$this->$name($args);
}
}
}
class ProxyA {
protected $wrapped;
public function __construct($wrapped) {
$this->wrapped = $wrapped;
}
public function __call($name, $args) {
if (method_exists($this->wrapped, $name)) {
echo 'Log:start';
$this->wrapped->$name($args);
echo 'Log:end';
}
}
}
$proxy = new ProxyA(new A());
$proxy->test0(); // Nothing to do
$proxy->test1(); // Done
$proxy->test2(); // Done
Use of the magic __call method might make this easy for you:
class Service
{
public function test1() {
echo 'TEST 1', PHP_EOL;
}
protected function test2() {
echo 'TEST 2', PHP_EOL;
}
public function __call($method, $args) {
echo 'Some stuff before', PHP_EOL;
$returnValue = $this->$method($args);
echo 'Some stuff after', PHP_EOL;
return $returnValue;
}
}
$x = new Service();
$x->test2();
$x->test1();
Note that if the method is accessible from outside the class (like test1) then __call() won't be invoked; it only executes if the methods involved are protected or private; and doesn't trigger if they are invoked internally within the object either
Related
The magical __call() and __callStatic can pretty much handle any non existing method on the class, but is there a way to handle a non existing magical method on a class?!
Here's an example on why I need this:
I have a class called DoSomething:
class DoSomething{
public function ok(){
echo 'Something!';
}
}
I want to call this class as a function for a reason! which should call the __invoke function of that class:
$doSomething = new DoSomething();
$doSomething();
Normally by doing that, the class should look for the __invoke function, however in my case I don't to have that function declared on my class (DoSomething), instead I want to be able to call another function (such as the ok()) if the __invoke doesn't exist.
I was expecting something like this to work, but of course it didn't :)
public function __call($class, $arguments)
{
$object = IoC::resolve($class);
$object->ok(...$arguments);
}
The main goal is to use the class as a function, without having to declare the __invoke method. Handle the function does not exist error and call another function instead.
I think that would be really cool :D I appreciate suggestions or other solutions to achieve this.
Internal solution
Extract an abstract class
You could extract an abstract class and have your classes extend it:
<?php
abstract class Invokable
{
public function __invoke()
{
return $this->ok();
}
abstract public function ok();
}
class DoSomething extends Invokable
{
public function ok()
{
echo 'Something';
}
}
$doSomething = new DoSomething();
echo $doSomething();
For an example, see:
https://3v4l.org/m0ih8
Extract a trait
You could extract a trait and have your classes use it:
<?php
trait InvokableTrait
{
public function __invoke()
{
return $this->ok();
}
}
class DoSomething
{
use InvokableTrait;
public function ok()
{
echo 'Something';
}
}
$doSomething = new DoSomething();
echo $doSomething();
For an example, see:
https://3v4l.org/ftUfI
External Solution
Create a proxy
You could create a proxy (a decorator) that composes the object that is not invokable:
<?php
class InvokableDecorator
{
private $decorated;
public function __construct($decorated)
{
$this->decorated = $decorated;
}
public function __call($name, $arguments)
{
/**
* delegate to decorated object if the method exists
*/
if (method_exists($this->decorated, $name)) {
return $this->decorated->{$name}($arguments);
}
}
public function __invoke()
{
return $this->decorated->ok();
}
}
class DoSomething
{
public function ok()
{
echo 'Something';
}
}
$doSomething = new InvokableDecorator(new DoSomething());
echo $doSomething();
For an example, see:
https://3v4l.org/C3XEX
Create a handler
You could create a handler that takes care of determining this externally:
<?php
class Handler
{
public function handle($subject)
{
if (is_callable($subject)) {
return $subject();
}
if (method_exists($subject, 'ok')) {
return $subject->ok();
}
throw new \BadMethodCallException(sprintf(
'Unable to handle instance of "%s"',
get_class($subject)
));
}
}
class DoSomething
{
public function ok()
{
echo 'Something';
}
}
$handler = new Handler();
echo $handler->handle(new DoSomething());
For an example, see:
https://3v4l.org/E0NVs
In PHP, how do I find out if a class method was called via a method inherited from a trait?
Say I have a class myClass that uses the Psr\Log\LoggerTrait (see: PSR-3). I need to be able to find out if the method myClass::log() was called via a method from the Psr\Log\LoggerTrait, for example LoggerTrait::debug(), or if it was called directly from outside myClass.
All the methods are non-static.
This is related to a debugging package. I'm not trying to alter behavior based on the caller, I just need to be able to pass that information forward. And to be more precise, I need just the entry point, ie. just the last call outside of my package.
I'm looking at debug_backtrace() but it doesn't seem to offer any direct solutions. Is there some rational way of doing this?
Here's some code:
<?php
class myClass
{
use Psr\Log\LoggerTrait;
public function log($level, $message, array $context = array())
{
if (called_via_trait) {
...
} else {
...
}
}
}
$myObject = new myClass;
$myObject->log('debug', 'This is a direct call');
$myObject->debug('This is a call via a trait method');
You could use get_called_class to determine the class that called it.
trait Test {
public function doTest() {
echo get_called_class() . "\n";
}
}
class Some {
use Test;
public function myFunc() {
$this->doTest();
}
}
$some = new Some();
$some->myFunc(); // Outputs "Some" since Some uses Test
So in your case, inside your class, you could do something like
function test() {
if(get_called_class() == 'myClass') {
// You're in the myClass class
} else {
// You're not in the myClass class
}
}
Yes, you have to use debug_backtrace(); Please follow my example:
namespace Psr\Log;
class LoggerTrait{
public static function debug(){
return myClass::log();
}
}
class myClass{
public static function log(){
$trace = debug_backtrace();
if(isset($trace[1])){
echo'<br />Called by <b>'.$trace[1]['class'].'</b>. ';
} else {
echo'<br />Called by <b>'.$trace[0]['class'].'</b>. ';
}
if(isset($trace[1]['class']) && $trace[1]['class']!=get_class()){
echo'Called outside';
} else {
echo'Called inside';
}
//return get_class();
}
}
trait ExampleTrait {
public function doSay() {
echo LoggerTrait::debug();
echo myClass::log();
}
}
echo LoggerTrait::debug();
echo myClass::log();
echo ExampleTrait::doSay();
I would like some feedback on my coding approach (i.e., whether it is appropriate or whether what I have done can be done in a perhaps better way):
I would like to create an interface to document that a constructor should have a specific format. Of course, if the interface only contains a constructor (and I was even surprised that PHP lets you put a constructor in an interface), the interface will have no effect (except for possibly documentation). Besides, PHP does not enforce the parameters of any callable to match, neither in number nor in type, and this is true of functions, methods, and constructors alike.
If you see how I have named my classes, you will realize what I am trying to do (: document that the constructor parameter must be a messager instance, too bad I could not do more to enforce this). Please let me know if my approach is OK and whether I can improve it.
class Messenger {
private $message;
function __construct($message = "Hello!") {
$this->message = $message;
}
public function getMessage() {
return $this->message;
}
}
With the above simple class in mind, I want to create an interface such as the following, but since we're dealing with a PHP constructor this should be useless?
interface MessengerAware {
function __construct($messenger);
}
class MessengerKnower implements MessengerAware {
private $messenger;
function __construct($messenger) {
$this->messenger = $messenger;
}
public function displayMessengerMessage() {
echo $this->messenger->getMessage();
}
}
I then want to enforce my interface in a class called Runner such as the following:
class Runner {
private $messengerAware;
function __construct($messengerAware) {
if (!is_a($messengerAware, 'MessengerAware')) {
die("I'm expecting an instance implementing the MessengerAware interface.");
}
$this->messengerAware = $messengerAware;
}
public function run() {
echo "I'm running.\n";
$this->messengerAware->displayMessengerMessage();
}
}
and finally run this code:
$messengerAware = new MessengerKnower(new Messenger());
$runner = new Runner($messengerAware);
$runner->run();
OUTPUT:
I'm running.
Hello!
Perhaps it's not possible, but the problem could be worked around using one (or more) factory methods:
Leave this unchanged:
class Messenger {
private $message;
function __construct($message = "Hello!") {
$this->message = $message;
}
public function getMessage() {
return $this->message;
}
}
This modification...
interface MessengerAware {
public static function create($messenger);
public function displayMessengerMessage();
}
and this one...
class MessengerKnower implements MessengerAware {
private $messenger;
public static function create($messenger) {
$messengerKnower = new MessengerKnower();
$messengerKnower->messenger = $messenger;
return $messengerKnower;
}
public function displayMessengerMessage() {
echo $this->messenger->getMessage();
}
}
Leave this unchanged...
class Runner {
private $messengerAware;
function __construct($messengerAware) {
if (!is_a($messengerAware, 'MessengerAware')) {
die("I'm expecting an instance implementing the MessengerAware interface.");
}
$this->messengerAware = $messengerAware;
}
public function run() {
echo "I'm running.\n";
$this->messengerAware->displayMessengerMessage();
}
}
Finally adjust this code:
$messengerAware = MessengerKnower::create(new Messenger());
$runner = new Runner($messengerAware);
$runner->run();
OUTPUT:
I'm running.
Hello!
Is there a way to call an inherited method, without specifying it's function name?
Something like:
class Child extends Parent {
function some_function(){
// magically inherit without naming the parent function
// it will call parent::some_function()
parent::inherit();
// other code
}
function another_function(){
// it will call parent::another_function()
$result = parent::inherit();
// other code
return $result;
}
}
I could think of a hack to do this using debug_backtrace(), get the last function where inherit() was called and access it's parent with the same function name. I was wondering if there's a nicer way instead of using debug functions which are clearly not meant for this.
You can use the magic __FUNCTION__ constant.
class A
{
function some_function()
{
echo 'called ' . __METHOD__;
}
}
class B extends A
{
function some_function()
{
call_user_func(array('parent', __FUNCTION__));
}
}
$b = new B;
$b->some_function(); // prints "called A::some_function"
Instead of
call_user_func(array('parent', __FUNCTION__));
you can also do
parent::{__FUNCTION__}();
Dirty, but:
class Adult {
function mummy(){
return 'Walk like an Egyptian';
}
function daddy(){
return 'Luke, I am your father';
}
}
class Child extends Adult {
function mummy(){
echo 'Mummy says: ';
$me = explode('::',__METHOD__)[1];
echo parent::$me();
}
function daddy(){
echo 'Daddy says: ';
$me = explode('::',__METHOD__)[1];
echo parent::$me();
}
}
$o = new Child();
$o->mummy();
$o->daddy();
EDIT
Actually giving you a parent method called inherit();
class Adult {
private function mummy(){
return 'Walk like an Egyptian';
}
private function daddy(){
return 'Luke, I am your father';
}
protected function inherit($method) {
$beneficiary = explode('::', $method)[1];
return $this->$beneficiary();
}
}
class Child extends Adult {
public function mummy() {
echo 'Mummy says: ',
parent::inherit(__METHOD__),
PHP_EOL;
}
public function daddy() {
echo 'Daddy says: ',
parent::inherit(__METHOD__),
PHP_EOL;
}
}
$o = new Child();
$o->mummy();
$o->daddy();
Dynamically calling functions:
static::$functionName();
In your case:
$func = __FUNCTION__;
parent::$func();
Note: the function name must be a string, if it's the actual function (not really relevant in this context) then it first needs to be converted to its string name first.
Other stuff that your question will probably lead you towards in the long run.
Check out late static binding it's what you're looking for.
Example taken from the linked page.
class A {
public static function who() {
echo __CLASS__;
}
public static function test() {
static::who(); // Here comes Late Static Bindings
}
}
class B extends A {
public static function who() {
echo __CLASS__;
}
}
B::test();
I'm using WordPress as a CMS, and I want to extend one of its classes without having to inherit from another class; i.e. I simply want to "add" more methods to that class:
class A {
function do_a() {
echo 'a';
}
}
then:
function insert_this_function_into_class_A() {
echo 'b';
}
(some way of inserting the latter into A class)
and:
A::insert_this_function_into_class_A(); # b
Is this even possible in tenacious PHP?
If you only need to access the Public API of the class, you can use a Decorator:
class SomeClassDecorator
{
protected $_instance;
public function myMethod() {
return strtoupper( $this->_instance->someMethod() );
}
public function __construct(SomeClass $instance) {
$this->_instance = $instance;
}
public function __call($method, $args) {
return call_user_func_array(array($this->_instance, $method), $args);
}
public function __get($key) {
return $this->_instance->$key;
}
public function __set($key, $val) {
return $this->_instance->$key = $val;
}
// can implement additional (magic) methods here ...
}
Then wrap the instance of SomeClass:
$decorator = new SomeClassDecorator(new SomeClass);
$decorator->foo = 'bar'; // sets $foo in SomeClass instance
echo $decorator->foo; // returns 'bar'
echo $decorator->someMethod(); // forwards call to SomeClass instance
echo $decorator->myMethod(); // calls my custom methods in Decorator
If you need to have access to the protected API, you have to use inheritance. If you need to access the private API, you have to modify the class files. While the inheritance approach is fine, modifiying the class files might get you into trouble when updating (you will lose any patches made). But both is more feasible than using runkit.
An updated way for 2014 that copes with scope.
public function __call($method, $arguments) {
return call_user_func_array(Closure::bind($this->$method, $this, get_called_class()), $arguments);
}
Eg:
class stdObject {
public function __call($method, $arguments) {
return call_user_func_array(Closure::bind($this->$method, $this, get_called_class()), $arguments);
}
}
$obj = new stdObject();
$obj->test = function() {
echo "<pre>" . print_r($this, true) . "</pre>";
};
$obj->test();
You can use the runkit extension for this, but you should really consider regular inheritance instead.
See runkit_method_add.
No you can't dynamically change a class during runtime in PHP.
You can accomplish this by either extending the class using regular inheritance:
class Fancy extends NotSoFancy
{
public function whatMakesItFancy() //can also be private/protected of course
{
//
}
}
Or you could edit the Wordpress source files.
I'd prefer the inheritance way. It's a lot easier to handle in the long run.