Jump to content

Recommended Posts

Sometimes I thing that I have created a design pattern but that in reality already exists, and has, moreover, a name.  Please share with me if you know that pattern that I am going to describe , and if not your opinion about what name should have.

 

When you have a child class with the same method name as the parent then it overloads it and only the child’s method occur. Of course in first line of that child’s method you can call the parent’s method (e.g. parent::methodName();  ) and than the parent method will happen. I am talking about a pattern that will do that using reflection. Also use any private properties to their class contexts

 

Example:

 

<?php
header('Content-Type: text/html; charset=utf-8'); 


// Classes that will be used to the example
class root
{

}

class proA extends root
{
public $txt = "";
private $pr = " (and something private from proA) ";
public function onEntry()
{
	$this->txt .= "proA:onEntry()".$this->pr." ---> ";
}
}

class a extends proA
{
private $pr = " (and something private from a) ";
public function onEntry()
{
	$this->txt .= "a:onEntry()".$this->pr." ---> ";
}
}

class b extends a
{
public function onEntry()
{
	$this->txt .= "b:onEntry()";
}	

public function getTxt()
{
	return $this->txt;
}
}	


// Starting reflection to class b and create an instance
$reflectionClass = new ReflectionClass("b");
$instance = $reflectionClass->newInstance(); 

// Creating an array with reflection classes of all line classes 
// (except the root class) reverse it in order to go from parent 
// to child and than push to that the original reflection class.
$reflectionClasses = array();  
$parent = $reflectionClass->getParentClass(); 
while($parent && $parent->getName() != "root")
{
$reflectionClasses[] = $parent; 
$parent = $parent->getParentClass(); 
}
$reflectionClasses = array_reverse($reflectionClasses);
$reflectionClasses[] = $reflectionClass;


// Invoking the onEntry() method using the original instance 
// an all the reflection classes ordered from parent to child 
for($i=0; $i<count($reflectionClasses); $i++)
{
if( $reflectionClasses[$i]->hasMethod("onEntry") )
{
	$reflectionClasses[$i]->getMethod("onEntry")->invoke($instance,"");
}
}

// And finally invoke the getTxt() method of b class instance
echo $reflectionClass->getMethod("getTxt")->invoke($instance,"");

// The result is  
// proA:onEntry() (and something private from proA) ---> a:onEntry() (and something private from a) ---> b:onEntry()
?>

Link to comment
https://forums.phpfreaks.com/topic/247571-has-this-design-pattern-a-name/
Share on other sites

what do you use this pattern for?

 

It is part of a MVC PHP  framework I am about to publish (yes … one more PHP framework). From programming, using that framework, point, there are some preset flow methods that the programmer can use in its controllers [ onUse() onEntry() onPost() onGet()  onView() ] .

 

Controllers inherit from framework’s ControllerAbstract but many times it is also good practice to have an application controller abstract class (that all the controllers of the specific application inherit from). Things can be more complex if you have a third level – group of controllers for a specific use (example: admin login Log > AdminControllerAbstract > ApplicationControllerAbstract > ControllerAbstract ( of the framework) )

 

Flow methods of the controllers are interchangeable and optional (I am keeping this as short as possible … for more just ask). So to get why I am using this pattern here is a real example. Posting is done by actions that may have the controller that refers this action to. But there are some actions that you want for all your controllers (e.g. log in) than you just define them in the onPost() of the ApplicationControllerAbstract, so the framework should invoke first the onPost of the parent and the onPost of the child. One more , the onUse() will be invoked (if exist) before any other flow method ( regardless if it is onPost() onEntry() or onGet() )  and has meaning of initialization any property that is needed if it is not initialized , so the framework should first invoke the parent’s onUse() and then the child’s.

 

I have tried to explain why I am using this pattern, as for the framework of course this is just a glimpse since it is not the topic.

 

requinix I am not breaking the concept of inheritance. There is a reason why you can do such a thing. Instance of (b) is also an (a) and  a (proA) and a (root)  invoking a method of parent class in its context don’t brakes the concept of inheritance (maybe bends it…hehe) because after that b still is as were for any other calls.

Thank you for your responses, any more opinions are more than welcomed…

 

why don't you use events?

 

create a class that stores the name of the method/ callback/ closure and use the event type/name they are listening to be the key (so you have an array of arrays)

then to populate that class using methods like addEventListener, removeEventListener and dispatchEvent.

 

uppon the call of dispatchEvent, you will look for the right type of event and iterate the callback list calling them.

 

so when something happens somewhere in your system and the method is being listen for, it will run your listening functions.

 

(I have a sample here, but then it's part of my framework, pm me if you want a copy)

requinix I am not breaking the concept of inheritance. There is a reason why you can do such a thing. Instance of (b) is also an (a) and  a (proA) and a (root)  invoking a method of parent class in its context don’t brakes the concept of inheritance (maybe bends it…hehe) because after that b still is as were for any other calls.

Thank you for your responses, any more opinions are more than welcomed…

Calling the parent method is fine, but if my child class B's Foo method doesn't want to call its parent class A's Foo then it doesn't have to. Maybe I missed an important point but enforcing that B::Foo -> A::Foo chain is not right.

 

Spark has the exact right answer for this: events.

can I post code? last time I posted code it got removed...  :shrug:

 

Event abstract

abstract class Event{
	private $target;
	private $lockTarget = false;

	public function setTargetOnce($obj){
		if($lockTarget) return;
		$this->target = $obj;
		$this->lockTarget = true;
	}
	abstract public function getName();
	public function getTarget(){
		return $this->target;
	}
}

 

Handler abstract (your dispatcher inherit from this)

abstract class EventHandler{
	private $listeners = array();

	public function addEventListener($eventName,$listener,$method=""){
		if(!isset($this->listeners[$eventName])) $this->listeners[$eventName] = array();

		$this->listeners[$eventName][] = array($listener,$method);
	}
	public function removeEventListener($eventName,$listener){
		for($i = 0; $i < count($this->listeners[$eventName]); $i++){
			$subject = $this->listeners[$eventName][$i];
			if($subject[0] !== $listener) continue;
			array_splice($this->listeners[$eventName],$i,1);
		}
	}
	protected function dispatchEvent($event){
		$event->setTargetOnce($this);

		foreach($this->listeners[$event->getName()] as $listener){
			$called = $listener[0];
			if($listener[1] != "") $called = array($listener[0],$listener[1]);
			call_user_func($called,$event);
		}
	}
}

 

now to test it you will need these:

BasicEvent

class BasicEvent extends Event{
	private $name = "basic";
	private $type;

	public function BasicEvent($type){
		$this->type = $type;
	}
	public function getName(){
		return $this->name;
	}
	public function getType(){
		return $this->type;
	}
}

 

and this is something that will use that event:

The dispatcher

class BasicDispatcher extends EventHandler{
	private $holder = false;

	public function __set($key,$value){
		$this->dispatchEvent(new BasicEvent("set"));

		$this->holder->{$key} = $value;
	}
	public function __get($key){
		$this->dispatchEvent(new BasicEvent("get"));

		return $this->holder->{$key};
	}
}

 

now for the main code:

PS the Dynamic class and others are part of my project, you can use any class here

$ouvinte = new Dynamic();
$ouvinte->onBasic = function($self,$evento){
	JavaScript::alert($evento->getName()." ".$evento->getType()." sendo tratado pelo ouvinte.");
};

$disparador = new BasicDispatcher();
$disparador->addEventListener("basic", $ouvinte, "onBasic");
$disparador->addEventListener("basic", "tratarLocal");

$disparador->basicIo = "verificando integridade da mensagem pós-evento.";
$mensagem = $disparador->basicIo;
JavaScript::alert($mensagem);

//local function
function tratarLocal($evento){
	JavaScript::alert($evento->getName()." ".$evento->getType()." sendo tratado localmente.");
}

 

once you set or get the basicIo property the event is dispatched and both listening methods are called

Thank you Spark_BR for your time , I am familiar with the observer pattern, but my framework stands in a lot deferent approach. I am sure though that your example will help others. Maybe what I didn’t made clear is that this method overloading break and flip will happen only to the preset flow functions of the framework (e.g. onPost is used when there is a post , onGet when it is get (or trailing path variables of the controller name in URL), onUse when the controller is used first of all others no matter what and onEntry when it neither post or get (or aren’t onPost / onGet methods respectively in the final Controller) .

 

The first problem that drove me to the pattern I first described, is that there could be some general application actions (like log on for example) that are handled by the abstract application controller from where all the controllers inherit. That means that in order to make it work each controller should has a onPost with parent::onPost() in first line even if that specific controller don’t have any reason to use onPost().

 

Using the pattern I described if there is post all the onPost methods will invoked from parent to child, and furthermore if the last child – actual Controller don’t have onPost all the onEntry methods will invoked.

 

That pattern helped me a lot in many other design issues. For example if abstract application controller has a onUse that initiate some general public application properties (and the framework don’t automatically find them and set them through visit scope cashing or application scope cashing) than all the final Controllers should have onUse with the first line parent::onUse() . With the pattern I described the framework will invoke before anything else all the onUse methods that exists from parent to child to the current controller.

 

then you need something more hardcore like Aspects and proxies

so you can attach pseudo-events to any method without changing the class, from an external source

 

problem is, it's difficult and uses undocumented workarounds to be implemented (I'm working on something so I can handle transversal interests in my system like logging, but nothing ready yet)

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.