Strategy Pattern with Anonymous Function Closure - php

I want to implement the Stategy Pattern using Closures in php. The main advantage of using closure is to reduce the amount of boilerplate and code needed by creating additional classes. Usually the pattern looks like this:
interface StateDiscountCalculatorInterface
{
public function calculateDiscount($amount);
}
class NewYorkStateStrategy implement StateDiscountCalculatorInterface
{
public function calculateDiscount($amount)
{
// .... about 20 lines of code
}
}
class CaliforniaStateStrategy implement StateTaxCalculatorInterface
{
public function calculateDiscount($amount)
{
// .... about 20 lines of code that's different from New York State Strategy
}
}
class stateTaxContext
{
private $stategy;
public function setStrategy(StateDiscountCalculatorInterface $strategy)
{
$this->strategy = $strategy;
}
public function getDiscount(array $amount)
{
return $this->strategy->calculateDiscount($amount);
}
}
The version below is with a closure implementing a php functional interface. Is this the right way to do this?
interface StateDiscountCalculatorInterface
{
public function calculateDiscount($amount);
}
class stateTaxContext
{
private $newYorkStateStrategy;
private $californiaStateStrategy;
private $state;
public function __construct()
{
$this->newYorkStateStrategy = function () implements StateDiscountCalculatorInterface {
...NewYorkStateStrategy class is replaced with code here
};
$this->californiaStateStrategy = function () implements StateDiscountCalculatorInterface {
...CaliforniaStateStrategy class is replaced with code here
};
}
public function getDiscount(array $amount)
{
if($this->state==='california')
{
$this->californiaStateStrategy->calculateDiscount($amount);
}
}
}

I am not a design patterns expert, but to my mind one of the best approaches to implement a strategy pattern would be the following - you may keep the interface & strategy classes as they are, but implement context like this:
class StateTaxContext
{
private $state;
public function setState(StateDiscountCalculatorInterface $state)
{
$this->state = $state;
}
public function getDiscount(array $amount)
{
return $this->state->->calculateDiscount($amount);
}
}
And then you may use this pattern everywhere in your code like this:
$context = new StateTaxContext();
// Calculate NY discount?
$context->setState(new NewYorkStateStrategy());
$data = $context->getDiscount($amount);
// Calculate California discount?
$context->setState(new CaliforniaStateStrategy());
$data = $context->getDiscount($amount);

Related

PHP OOP classes and functions

I am not sure how to name this, but here it goes. Lets suppose i have the following
class A {
public function aa() {
$this->bb();
}
public function bb() {
}
}
class B extends a {
}
class C {
__construct(B $service) {
$this->service = $service;
}
public function aa() {
$this->service->aa();
}
}
My call in code will be
$C = new C(new B());
$C->aa();
So this will basically execute A:aa() which is what i want. As you can see, in A::aa() AA::bb() is called.
What I need. When AA::bb() is called i want to execute some code defined in class C, but I am not allowed to change the A class. I can only change the B class or the C class.
My idea was to add a listener in the B class and overwrite the bb() function like this
class B extends a {
public $listener;
bb() {
parent::bb();
$this->listener();
}
}
class C {
__construct(B $service) {
$this->service = $service;
}
public function aa() {
$this->service->listener = function() { }
$this->service->aa();
}
}
But I don't like this idea a lot, doesn't look like a good one. What are my options here?
Again, I CANNOT change the A class and i can only call the C class.
PHP version is 5.3
You have two options. Extend or decorate.
First one would be kinda what you have already written, though, I would not use public visibility for the listener:
class Foo extends A {
private $listener;
public function setListener(callable $func) {
$this->listener = $func;
}
public function bb() {
call_user_func($this->listener);
return parent:bb();
}
}
In the example I passed the listener via setter injection, but you can also use constructor injection and pass the $listened in the overloaded __construct() method. When you extend a class, the "interface restriction" does not aply to the constructor's signature.
The other approach is to use a decorator:
class Foo {
private $target;
public function __construct(A $target) {
$this->target = $target;
}
public function bb($callback) {
$callback();
return $this->target->bb();
}
public function __call($method, $arguments) {
return call_user_func_array(
array( $this->target, $method ),
$arguments
);
}
}
The second approach would let you alter the interface.
Which option you pick depend on the exact functionality you actually need to implement. The decorator is a solution for, when you need drastic change in the objects behavior - for example, it is really good for adding access control.
I understand that you want to execute code in C after code in A completes. You cannot change A.
As written, C::aa calls A::aa, which calls A::bb and the stack unwinds. Why not just do the work in C::aa after the service call finishes?
class C {
public function aa() {
$this->service->aa();
// whatever you want to do
}
}
If, on the other hand, you need to call code after A::aa is called but before A::bb is called then the example you posted would suffice with clarity:
class B extends a {
public $listener;
public function bb() {
call_user_func($this->listener);
parent::bb();
}
}
Note the use of call_user_func, which is necessary for PHP 5.3 to call an anonymous function stored in a member variable.

Best method for handling multiple interface implementations?

Unfortunately I'm stuck here.
Consider the following rudimentary examples:
interface ChargeInterface
{
public function charge($amount);
}
class BraintreeCharge implements ChargeInterface
{
public function charge($amount)
{
// braintree logic here
}
}
class StripeCharge implements ChargeInterface
{
public function charge($amount)
{
// stripe logic here
}
}
So there's an interface for charging a payment method, and there are, in this example, two concrete classes which implement the interface.
I'd like to be able to decide on runtime which implementation should be used. So I thought I'd achieve this with custom factory classes:
class PaymentFactory
{
public static $implementation;
public static function charge()
{
return $implementation::charge();
}
}
class StripeFactory
{
public static function charge()
{
return new StripeCharge();
}
}
class BraintreeFactory
{
public static function charge()
{
return new BraintreeCharge();
}
}
Than I could just use the factories:
PaymentFactory::$implemention = StripeFactory::class;
$payments = PaymentFactory::charge();
$payments->charge(100);
Another idea was to use a singleton based logic:
class PaymentFactory extends Singleton
{
protected $implementation;
// Singleton logic missing in this example
public function useImplementation($class)
{
$this->implementation = $class;
}
public function getImplementation()
{
return $this->implementation;
}
public static function charge()
{
$instance = self::getInstance();
return new $instance->getImplementation();
}
}
Later ...
PaymentFactory::getInstance()->useImplementation(StripeCharge::class);
$payments = PaymentFactory::charge();
$payments->charge(100);
Do you've any suggestions regarding best practices here?
I think I'd favour the first one, since the real implementation consists of more than just one class per package, as outlined in the example.
Also it seems to me, this would be the more cleaner way.

Is it possible to (somehow?) declare the format of a constructor in a PHP interface (or anything about it)?

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!

Use two classes in one: design mistake?

I wrote these two classes that simple encrypt and decrypt strings:
Encode.php
class Encode {
protected funcion do_encode($string) { .. }
}
Decode.php
class Decode {
protected funcion do_decode($string) { .. }
}
What I would like to do is:
Encrypt.php
class Encrypt extends Encode, Decode {
protected $stuff_for_parents;
function __construct($configs) {
$this->stuff_for_parents = $configs['SomeConf'];
}
public function encode($string) { $this->do_encode($string); }
public function decode($string) { $this->do_decode($string); }
}
But we cannot include more than one class, so: fail.
Now my questions are:
Is it a design problem? Cause this scenario doesn't look weird to me, does it?
Is there another way to have one object that uses both the functions in the different classes? Sort of $encrypt->encode($str); $encrypt->decode($str);
If you want Encode and Decode to be separate classes, you can create instances of them within Encrypt. For example:
<?
class Encrypt {
private $encoder;
private $decoder;
public function __construct() {
$this->encoder = new Encode();
$this->decoder = new Decode();
}
public function encode($string) {
return $this->encoder->encode($string);
}
public function decode($string) {
return $this->decoder->decode($string);
}
}
?>
In that example Encode and Decode must be concrete classes. But you might want to consider using interfaces instead. Interfaces are useful if you think you might need to use different types of Encode and Decode objects, in different situations. For example, maybe you have a TripleDESEncode class and a BlowfishEncode class. They can both implement a common interface, like this:
<?
interface IEncode {
public function encode($string);
}
class TripleDESEncode implements IEncode {
public function encode($string) {...}
}
class BlowfishEncode implements IEncode {
public function encode($string) {...}
}
?>
In that case, you may want to create the particular instances you want to use first, and then pass them into the constructor of Encrypt. This is called dependency injection:
<?
class Encrypt {
public function __construct(IEncode $encoder, IDecode $decoder) {
$this->encoder = $encoder;
$this->decoder = $decoder;
}
...
}
$myEncrypt = new Encrypt(new BlowfishEncode(), new BlowfishDecode());
echo $myEncrypt->encode('test');
?>
There is nothing wrong with encapsulating your algorithms in separate classes (in fact it is good practice if you would like the flexibility to change these, especially at runtime), however, what you probably want is composition rather than inheritance:
class Encrypt {
private $encoder;
private $decoder;
protected $stuff_for_parents;
function __construct($configs, $encoder, $decoder) {
$this->stuff_for_parents = $configs['SomeConf'];
$this->encoder = $encoder;
$this->decoder = $decoder;
}
public function encode($string) { $this->encoder->do_encode($string); }
public function decode($string) { $this->decoder->do_decode($string); }
}
I think you should just creat two methods/functions in Encryption class. It is very logical.
It does make sense but it can be done in the way allowed by programming languages. Encoding decoding are different functions that encryption class should perform so these should be methods.
I would write is somthing like:
class Encrypt
{
protected $stuff_for_parents;
function __construct($configs) {
$this->stuff_for_parents = $configs['SomeConf'];
}
protected funcion encode($string)
{
}
protected funcion decode($string)
{
}
}

Faking method attributes in PHP?

Is it possible to use the equivalent for .NET method attributes in PHP, or in some way simulate these?
Context
We have an in-house URL routing class that we like a lot. The way it works today is that we first have to register all the routes with a central route manager, like so:
$oRouteManager->RegisterRoute('admin/test/', array('CAdmin', 'SomeMethod'));
$oRouteManager->RegisterRoute('admin/foo/', array('CAdmin', 'SomeOtherMethod'));
$oRouteManager->RegisterRoute('test/', array('CTest', 'SomeMethod'));
Whenever a route is encountered, the callback method (in the cases above they are static class methods) is called. However, this separates the route from the method, at least in code.
I am looking for some method to put the route closer to the method, as you could have done in C#:
<Route Path="admin/test/">
public static void SomeMethod() { /* implementation */ }
My options as I see them now, are either to create some sort of phpDoc extension that allows me to something like this:
/**
* #route admin/test/
*/
public static function SomeMethod() { /* implementation */ }
But that would require writing/reusing a parser for phpDoc, and will most likely be rather slow.
The other option would be to separate each route into it's own class, and have methods like the following:
class CAdminTest extends CRoute
{
public static function Invoke() { /* implementation */ }
public static function GetRoute() { return "admin/test/"; }
}
However, this would still require registering every single class, and there would be a great number of classes like this (not to mention the amount of extra code).
So what are my options here? What would be the best way to keep the route close to the method it invokes?
This is how I ended up solving this. The article provided by Kevin was a huge help. By using ReflectionClass and ReflectionMethod::getDocComment, I can walk through the phpDoc comments very easily. A small regular expression finds any #route, and is registered to the method.
Reflection is not that quick (in our case, about 2,5 times as slow as having hard-coded calls to RegiserRoute in a separate function), and since we have a lot of routes, we had to cache the finished list of routes in Memcached, so reflection is unnecessary on every page load. In total we ended up going from taking 7ms to register the routes to 1,7ms on average when cached (reflection on every page load used 18ms on average.
The code to do this, which can be overridden in a subclass if you need manual registration, is as follows:
public static function RegisterRoutes()
{
$sClass = get_called_class(); // unavailable in PHP < 5.3.0
$rflClass = new ReflectionClass($sClass);
foreach ($rflClass->getMethods() as $rflMethod)
{
$sComment = $rflMethod->getDocComment();
if (preg_match_all('%^\s*\*\s*#route\s+(?P<route>/?(?:[a-z0-9]+/?)+)\s*$%im', $sComment, $result, PREG_PATTERN_ORDER))
{
foreach ($result[1] as $sRoute)
{
$sMethod = $rflMethod->GetName();
$oRouteManager->RegisterRoute($sRoute, array($sClass, $sMethod));
}
}
}
}
Thanks to everyone for pointing me in the right direction, there were lots of good suggestions here! We went with this approach simply because it allows us to keep the route close to the code it invokes:
class CSomeRoutable extends CRoutable
{
/**
* #route /foo/bar
* #route /for/baz
*/
public static function SomeRoute($SomeUnsafeParameter)
{
// this is accessible through two different routes
echo (int)$SomeUnsafeParameter;
}
}
Using PHP 5.3, you could use closures or "Anonymous functions" to tie the code to the route.
For example:
<?php
class Router
{
protected $routes;
public function __construct(){
$this->routes = array();
}
public function RegisterRoute($route, $callback) {
$this->routes[$route] = $callback;
}
public function CallRoute($route)
{
if(array_key_exists($route, $this->routes)) {
$this->routes[$route]();
}
}
}
$router = new Router();
$router->RegisterRoute('admin/test/', function() {
echo "Somebody called the Admin Test thingie!";
});
$router->CallRoute('admin/test/');
// Outputs: Somebody called the Admin Test thingie!
?>
Here's a method which may suit your needs. Each class that contains routes must implement an interface and then later loop through all defined classes which implement that interface to collect a list of routes. The interface contains a single method which expects an array of UrlRoute objects to be returned. These are then registered using your existing URL routing class.
Edit: I was just thinking, the UrlRoute class should probably also contain a field for ClassName. Then $oRouteManager->RegisterRoute($urlRoute->route, array($className, $urlRoute->method)) could be simplified to $oRouteManager->RegisterRoute($urlRoute). However, this would require a change to your existing framework...
interface IUrlRoute
{
public static function GetRoutes();
}
class UrlRoute
{
var $route;
var $method;
public function __construct($route, $method)
{
$this->route = $route;
$this->method = $method;
}
}
class Page1 implements IUrlRoute
{
public static function GetRoutes()
{
return array(
new UrlRoute('page1/test/', 'test')
);
}
public function test()
{
}
}
class Page2 implements IUrlRoute
{
public static function GetRoutes()
{
return array(
new UrlRoute('page2/someroute/', 'test3'),
new UrlRoute('page2/anotherpage/', 'anotherpage')
);
}
public function test3()
{
}
public function anotherpage()
{
}
}
$classes = get_declared_classes();
foreach($classes as $className)
{
$c = new ReflectionClass($className);
if( $c->implementsInterface('IUrlRoute') )
{
$fnRoute = $c->getMethod('GetRoutes');
$listRoutes = $fnRoute->invoke(null);
foreach($listRoutes as $urlRoute)
{
$oRouteManager->RegisterRoute($urlRoute->route, array($className, $urlRoute->method));
}
}
}
I'd use a combination of interfaces and a singleton class to register routes on the fly.
I would use a convention of naming the router classes like FirstRouter, SecondRouter and so on. This would enable this to work:
foreach (get_declared_classes() as $class) {
if (preg_match('/Router$/',$class)) {
new $class;
}
}
That would register all declared classes with my router manager.
This is the code to call the route method
$rm = routemgr::getInstance()->route('test/test');
A router method would look like this
static public function testRoute() {
if (self::$register) {
return 'test/test'; // path
}
echo "testRoute\n";
}
The interfaces
interface getroutes {
public function getRoutes();
}
interface router extends getroutes {
public function route($path);
public function match($path);
}
interface routes {
public function getPath();
public function getMethod();
}
And this is my definition av a route
class route implements routes {
public function getPath() {
return $this->path;
}
public function setPath($path) {
$this->path = $path;
}
public function getMethod() {
return $this->method;
}
public function setMethod($class,$method) {
$this->method = array($class,$method);
return $this;
}
public function __construct($path,$method) {
$this->path = $path;
$this->method = $method;
}
}
The Router manager
class routemgr implements router {
private $routes;
static private $instance;
private function __construct() {
}
static public function getInstance() {
if (!(self::$instance instanceof routemgr)) {
self::$instance = new routemgr();
}
return self::$instance;
}
public function addRoute($object) {
$this->routes[] = $object;
}
public function route($path) {
foreach ($this->routes as $router) {
if ($router->match($path)) {
$router->route($path);
}
}
}
public function match($path) {
foreach ($this->routes as $router) {
if ($router->match($path)) {
return true;
}
}
}
public function getRoutes() {
foreach ($this->routes as $router) {
foreach ($router->getRoutes() as $route) {
$total[] = $route;
}
}
return $total;
}
}
And the self register super class
class selfregister implements router {
private $routes;
static protected $register = true;
public function getRoutes() {
return $this->routes;
}
public function __construct() {
self::$register = true;
foreach (get_class_methods(get_class($this)) as $name) {
if (preg_match('/Route$/',$name)) {
$path = call_user_method($name, $this);
if ($path) {
$this->routes[] = new route($path,array(get_class($this),$name));
}
}
}
self::$register = false;
routemgr::getInstance()->addRoute($this);
}
public function route($path) {
foreach ($this->routes as $route) {
if ($route->getPath() == $path) {
call_user_func($route->getMethod());
}
}
}
public function match($path) {
foreach ($this->routes as $route) {
if ($route->getPath() == $path) {
return true;
}
}
}
}
And finally the self registering router class
class aRouter extends selfregister {
static public function testRoute() {
if (self::$register) {
return 'test/test';
}
echo "testRoute\n";
}
static public function test2Route() {
if (self::$register) {
return 'test2/test';
}
echo "test2Route\n";
}
}
the closest you can put your path to the function definition (IMHO) is right before the class definition. so you would have
$oRouteManager->RegisterRoute('test/', array('CTest', 'SomeMethod'));
class CTest {
public static function SomeMethod() {}
}
and
$oRouteManager->RegisterRoute('admin/test/', array('CAdmin', 'SomeMethod'));
$oRouteManager->RegisterRoute('admin/foo/', array('CAdmin', 'SomeOtherMethod'));
class CAdmin {
public static function SomeMethod() {}
public static function SomeOtherMethod() {}
}
There is a proposal for this, it was declined. See the rfc here:
Attributes RFC at php.net
My solution to this desire is something like this:
abstract class MyAttributableBase{
protected static $_methodAttributes=[];
public static function getMethodAtributes(string $method):?array{
if( isset(self::$_methodAttributes[$method])){
return self::$_methodAttributes[$method];
}
return null;
}
protected static function setMethodAttributes(string $method, array $attrs):void{
self::$_methodAttributes[$method] = $attrs;
}
}
class MyController extends MyAttributableBase{
protected static function getMethodAtributes(string $method):?array{
switch( $method ){
case 'myAction':
return ['attrOne'=>'value1'];
default:
return parent::getMethodAttributes($method);
}
}
}
Usage:
$c = new MyController();
print $c::getMethodAttributes('myAction')['attrOne'];
You can of course use it from within a base class method to do "routing" stuff in this case, or from a routing class that operates on "MyAttributableBase" objects, or anywhere else you would want to inspect this attached metadata for any purpose. I prefer this "in-code" solution to using phpDoc. Note I didn't attempt to test this exact code but it is mentally copied from a working solution. If it doesn't compile for some small reason it should be easy to fix and use. I have not figured out a way to cleanly put the attributes near the method definition. Using this implementation in the base you COULD set the attributes within the method (myAction in this case) as the first code to execute, but it would not be a static attribute, it would get reset at each invocation. You could add code to additionally ensure it is only set once but that's just extra code to execute and maybe is not better. Overriding the get method allows you to set the info once and refer to it once, even though it's not that close to the method definition. Keeping the static array in the base does allow some flexibility if there are cases for adding or changing metadata at runtime. I could be possible to use something like phpDoc and a static constructor to parse that when the first class is created to populate the static metadata array. I haven't found a solution that is awesome but the one I'm using is adequate.

Categories