Jump to content

Hooks?


Liquid Fire

Recommended Posts

As i am building my framework and using it at work, one of my co-workers asked if there way a way to extend the core functionality without having to modify the core file, or what he called hooking.  now you could ofcourse and classes the extends form existing one but if someone wanted to add something to the, lets say base_model class, they would have to edit the file itself and that would mess up with upgrading the framework.  is there a way to extend the allow people to extends the frameowrk core classes without having them edit the actual file?

Link to comment
Share on other sites

Personally I'm not a big fan of this concept. I believe in exposing what ever input/output capability you want via a quasi webservice API type deal. In my opinion it really helps keep the additional components as isolated pieces. I think its cleaner and minimizes dependencies.

Link to comment
Share on other sites

The only reason I would use web services is if i am offering a application but not the source code.  If given a choose between using services or direct code, I would always choose direct code.

 

Maybe i misunderstood what you meant but that sound like you say i should offer my framework functionality with service, is that wrong assumption?

Link to comment
Share on other sites

Thats the absolute right assumption. By making it available via webservices you are making people play by your rules. If you give them the core and they decide to change it you break your update path, etc. It's really the same type of logic used with input validation.

Link to comment
Share on other sites

Check out the observer pattern.

 

Something like this:

<?php
class SomeClass
{
const STATUS_ZERO = 0;
const STATUS_ONE = 1;
const STATUS_TWO = 2;

private $observers = array();
private $status;

public function __construct()
{
	$this->status = self::STATUS_ZERO;
}

public function getStatus()
{
	return $this->status;
}

public function attach(SomeClass_Observer $observer)
{
	if (!in_array($observer, $this->observers)) {
		$this->observers[] = $observer;
	}

	return $this;
}

public function detach(SomeClass_Observer $observer)
{
	$numObservers = count($observers);
	for ($i = 0; $i <= $numObservers; $i++) {
		if ($this->observers[$i] === $observer) {
			unset($this->observers[$i]);
			break;
		}
	}

	return $this;
}

private function notify()
{
	foreach ($this->observers as $observer) {
		$observer->hook($this);
	}
}

public function doSomething()
{
	echo 'do something in ' . __METHOD__ . '()' . PHP_EOL;
	$this->status = self::STATUS_ONE;
	$this->notify();
	echo 'do something else in ' . __METHOD__ . '()' . PHP_EOL;
	$this->status = self::STATUS_TWO;
	$this->notify();
}
}

interface SomeClass_Observer
{
public function hook(SomeClass $someClass);
}

class SomeClass_Observer_AnObserver implements SomeClass_Observer
{
public function hook(SomeClass $someClass)
{
	switch ($someClass->getStatus()) {
		case SomeClass::STATUS_ONE:
			echo '[status 1] doing something in ' . __METHOD__ . '()' . PHP_EOL;
			break;
		case SomeClass::STATUS_TWO:
			echo '[status 2] doing something else in ' . __METHOD__ . '()' . PHP_EOL;
			break;
	}
}
}

class SomeClass_Observer_AnotherObserver implements SomeClass_Observer
{
public function hook(SomeClass $someClass)
{
	if ($someClass->getStatus() == SomeClass::STATUS_ONE) {
		echo '[status 1] doing something in ' . __METHOD__ . '()' . PHP_EOL;
	}
}
}

$someClass = new SomeClass();
$someClass->attach(new SomeClass_Observer_AnObserver())
          ->attach(new SomeClass_Observer_AnotherObserver());

$someClass->doSomething();
?>

 

Output:

do something in SomeClass::doSomething()
[status 1] doing something in SomeClass_Observer_AnObserver::hook()
[status 1] doing something in SomeClass_Observer_AnotherObserver::hook()
do something else in SomeClass::doSomething()
[status 2] doing something else in SomeClass_Observer_AnObserver::hook()

Link to comment
Share on other sites

Thats the absolute right assumption. By making it available via webservices you are making people play by your rules. If you give them the core and they decide to change it you break your update path, etc. It's really the same type of logic used with input validation.

maybe it is just mean but that is not the point of web services.  The point of web services is to give other people access to data that they don't have direct access to(like amazon).  The model related classes(2 of them) are the only thing that directly deals with data, everything else is need access to a server.  I mean I don't know any other framework(RoR, Codeignitor, PHPCake) that don't offer the framework source but only off the functions of the framework through service but if there is any,. please let me know.

 

I have have a look at the observer pattern.

Link to comment
Share on other sites

That's because its opensource, everything is available.

 

I've used webservices for all kinds of stuff though. Yes it involves data but sometimes it's doing a calculations, etc not just granting access to some data.

Link to comment
Share on other sites

looking at the observer, it seems it would allow somethings but not exactly what i am looking for, it seems i can only extend functionality of existing functions but not add totally new functionality which is what i am looking for.

 

for example I have a url_helper class and my boss wants a breadcrumb functionality for the site.  Now while a breadcrumb is cool and all, i don't like it should be part of the core code.  What i would like to be able to do it load a class that will allow me to do $url_helper->get_breadcrumb() without having to add inside the core url_helper class the method breadcrumb().  This way if I update the url_helper, they can update it without having to worry about added the function back in after the update.  Is this possible?

Link to comment
Share on other sites

basically yes, that it was i am looking for, i did not think it was directly possible but there might be some solution that simulates it.  the only thing i can think of it

<?php
class url_helper
{
public function __call($function, $parameter)
{
	//this allow plugin calls
	try
	{
		$class = get_class($this) . '_' . $function;
		$plugin = new $class();

		//make all plugin have the object the are adding the plugin to as first parameter
		$parameters = array_merge(array($this), $parameters);

		call_user_func_array(array($plugin, 'invoke'), $parameters);

		unset($plugin);
	}
	catch(Exception $exception)
	{
		//not able to find plugin, should i throw exception or continue as normal?
	}
}

//class code
}

class url_helper_get_breadcrumbs
{
public function __construct()
{
}

public function invoke()
{
	//breadcrumb code
}
}

$url_helper = new url_helper();

//this should call the url_helper_get_breadcrumbs->invoke function
$url_helper->get_breadcrumbs();
?>

 

but not sure if it is the best way to do it.

Link to comment
Share on other sites

the reason is that the page controllers already have an instances of url_helper in them from the base class and the url_hepler is a singleton class so they would have to rewrite the way the instance is stored so it stores the new class and not the base class.  I don't think this is going to be much of an issue, I don't think there should be wanting to add much to the core framework, only extend it with new classes.

Link to comment
Share on other sites

I don't know if you're one of the people I've discussed the usage of singletons with, but this clearly shows how unneeded usage of the singleton pattern can transform from what seemed to be a convenience to an inconvenience. As you have uncovered yourself, the usage of a singleton has coupled your classes too tightly. Had your "base class" accepted an instance of url_helper passed to it by argument and ensured that it was an url_helper instance by using type hinting, then a child class (e.g. something like my_url_helper like I said above) would have been compatible with your framework/base class.

 

For solving your problem, you could classes which would take an instance of url_helper and use url_helper::get_links() or whatever to generate the breadcrumbs or some other kind of extended functionality based on that of url_helper.

Link to comment
Share on other sites

I now understand the theme of your questions, Liquid Fire, and what you're trying to accomplish.

 

I don't know if there's an equivalent in PHP, but I use Spring ( http://www.springframework.org/ ) in my professional life quite a bit. It's pretty amazing, albeit a bit verbose.

 

Let's take the URL Helper mentioned above. As long as you have an interface URLHelper and a concrete implementation MyURLHelper , you should be able to rip MyURLHelperImpl out completely and make LiquidsURLHelperImpl which implements URLHelper without breaking anything.

 

The process of 'swapping' would have to be handled via configuration files (the Spring way,) or some other method (your way)

Link to comment
Share on other sites

  • 2 weeks later...
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.