Interface injection and common classes Interface injection and common classes wordpress wordpress

Interface injection and common classes


Looking over your code you are definitely off to a good start. You are already using one good rule of thumb when programming in OOP - program to an interface, not an implementation. By the term interface I'm not referring only to actual interfaces, but abstract classes as well.

So at the heart of your question you want to have two classes, ClassA and ClassB that both use common methods from RequestReferrerHandler. You already have the ground work laid out to do that with your interface RequestReferrerHandlerInterface. So we'll say that you have an interface that looks like this:

interface RequestReferrerHandlerInterface{    public function hasAuthorReferrerValue();    public function hasDateReferrerValue();    public function hasSearchReferrerValue();    public function hasTaxReferrerValue();}

So long as this interface is implemented by the RequestReferrerHandler you can type hint the interface as the constructor requirements for ClassA and ClassB. But this isn't anything new because you were already doing this.

There are two things in particular that stand out at me as potential sore thumbs. First, since you want the responsibilities of your classes to be small, you should take the responsibility of providing data to the RequestReferrerHandler away from itself and give it to your Controller. In other words, do not inject $_GET into your class. Make sure your Controller has all the information it needs to properly create the RequestReferrerHandler Let's take a look at your RequestReferrerHandler class, flushed with all of the methods it will need.

class RequestReferrerHandler implements RequestReferrerHandlerInterface{    private $author;    private $date;    private $search;    private $tax;    public function __construct($author = null, $date = null, $search = null, $tax = null)    {        $this->setAuthorReferrer($author);        $this->setDateReferrer($date);        $this->setSearchReferrer($search);        $this->setTaxReferrer($tax);    }    public function hasAuthorReferrerValue()    {        return $this->author !== null ? true : false;    }    public function hasDateReferrerValue()    {        return $this->date !== null ? true : false;    }    public function hasSearchReferrerValue()    {        return $this->search !== null ? true : false;    }    public function hasTaxReferrerValue()    {        return $this->tax !== null ? true : false;    }    public function getAuthorReferrer()    {        return $this->author;    }    public function getDateReferrer()    {        return $this->date;    }    public function getSearchReferrer()    {        return $this->search;    }    public function getTaxReferrer()    {        return $this->tax;    }    public function setAuthorReferrer($author)    {        $this->author = $author;    }    public function setDateReferrer($date)    {        $this->date = $date;    }    public function setSearchReferrer($search)    {        $this->search = $search;    }    public function setTaxReferrer($tax)    {        $this->tax = $tax;    }}

The second thing that sticks out is the santize() methods. Do you see how they are duplicated in both ClassA and ClassB? The sanitizeAuthor() is different among the two classes, but how about the rest? This is a case where the DRY (Don't Repeat Yourself) principle can help out. Since multiple classes may have to sanitize data in similar ways it make sense to abstract that away from your classes.

Let's take a look at how to do that and then we will come back to your concrete classes. First create a new interface that will specify methods that must be exposed by an object that can sanitize data.

interface SanitizerInterface{    public function sanitizeAuthor();    public function sanitizeDate();    public function sanitizeSearch();    public function sanitizeTaxonomy();}

Now, if every object you had of ClassX implemented these four methods in different ways you could start implementing it in different classes that simply sanitize data. However, for this example we will say that is not the case. Let's make the assumption that sanitizeAuthor() could be different among ClassA and ClassB (which it is in your code) and all the other methods will be implemented exactly the same. This is case where we can use an abstract class that will implement the sanitizer methods.

abstract class AbstractSanitizer implements SanitizerInterface{    protected $handler;    public function __construct() {}    public function setHandler(RequestReferrerHandlerInterface $handler)    {        $this->handler = $handler;    }       /* For this example we are saying that sanitizeDate(), sanitizeTaxonomy() and     * sanitizeSearch() will be the same no matter what.  So let's implement them      * and leave the child classes to implement sanitizeAuthor().      *      * Implement the details of the sanitizer function to fit your needs.     */    public function sanitizeDate()    {        if($this->handler !== null)        {            //Perform whatever tasks to sanitize the date            $sanitized = strtoupper($this->handler->getDateReferrer());            echo "Sanitize date -> switch to uppercase letters.\n";            $this->handler->setDateReferrer($sanitized);        }    }    public function sanitizeSearch()    {        if($this->handler !== null)        {            //Perform whatever tasks to sanitize the search            $sanitized = strtolower($this->handler->getSearchReferrer());            echo "Sanitize search -> switch to lowercase letters.\n";            $this->handler->setSearchReferrer($sanitized);        }    }    public function sanitizeTaxonomy()    {        if($this->handler !== null)        {            //Perform whatever tasks to sanitize the taxonomy            $sanitized = str_replace(" ", "_", $this->handler->getTaxReferrer());            echo "Sanitize Taxonomy -> convert spaces to underscores.\n";            $this->handler->setTaxReferrer($sanitized);        }    }}

Some things to take note of right off the bat. First, you'll notice there is the setHandler() method which accepts an instance of the RequestReferrerHandlerInterface. Why is this there? Convenience for the most part. Since we have taken the sanitizing behavior and encapsulated it into its own class it would be nice it we gave the sanitizer a way to update the concrete RequestReferrerHandler it is using with the updated output from a sanitize method.

Next thing, we are using methods from the RequestReferrerHandler class that are not specified in the RequestReferrerHandlerInterface. This isn't an immediate problem per se, because we know that methods like the getters and setters are in the class. However, type hinting to the interface alone doesn't guarantee that those methods will be available if you ever decided to implement that interface with a different concrete object. Therefore, we need to update the RequestReferrerHandlerInterface with methods that will guarantee their availability.

interface RequestReferrerHandlerInterface{    public function hasAuthorReferrerValue();    public function hasDateReferrerValue();    public function hasSearchReferrerValue();    public function hasTaxReferrerValue();    public function getAuthorReferrer();    public function getDateReferrer();    public function getSearchReferrer();    public function getTaxReferrer();    public function setAuthorReferrer($author);    public function setDateReferrer($date);    public function setSearchReferrer($search);    public function setTaxReferrer($tax);}

Now, back to those sanitizers. We know that ClassA and ClassB will implement their sanitizeAuthor() methods differently. The abstract class AbstractSanitizer was made the way it was because the sanitizeAuthor() method from the the SanitizerInteface isn't implemented in AbstractSanitizer so we have to extend it to provide the functionality. We will need the following two classes to do this:

class SanitizerForClassA extends AbstractSanitizer{    /* This class must provide an implementation for how ClassA will     * handle the sanitizeAuthor() method.     */    public function sanitizeAuthor()    {        if($this->handler !== null)        {            //Perform whatever tasks to sanitize the for ClassA            $sanitized = array("author" => $this->handler->getAuthorReferrer());            echo "Sanitize author -> ClassA makes author an array.\n";            $this->handler->setAuthorReferrer($sanitized);        }       }}class SanitizerForClassB extends AbstractSanitizer{    /* This class must provide an implementation for how ClassB will     * handle the sanitizeAuthor() method.     */    public function sanitizeAuthor()    {        if($this->handler !== null)        {            //Perform whatever tasks to sanitize the for ClassB            $sanitized = new stdClass();            $sanitized->author = $this->handler->getAuthorReferrer();            echo "Sanitize author -> ClassB makes author an object property. \n";            $this->handler->setAuthorReferrer($sanitized);        }       }}

These two concrete classes can be used with ClassA and ClassB to sanitize data within the concrete RequestReferrerHandler methods that will be passed into them.

So moving on, let's look at the spec for ClassA and ClassB. We know that ClassA will need the method queryArguments(), ClassB will need the method queryVars() and both classes will need to allow and instance of a RequestReferrerHandlerInterface and SanitizerInterface in their constructors. We will handle the constructor requirement with one interface, then two other interfaces will extend that to provide all the method requirements needed for ClassA and ClassB.

interface SanitizableHandlerInterface{           public function __construct(RequestReferrerHandlerInterface $handler, SanitizerInterface $sanitizer);}interface QueryVarsInterface extends SanitizableHandlerInterface{    public function queryVars();}interface QueryArgumentsInterface extends SanitizableHandlerInterface{    public function queryArguments();}

Since we are now getting down to it, let's take a look at those classes that will use these.

class ClassA implements QueryArgumentsInterface{    private $handler;    private $sanitizer;    public function __construct(RequestReferrerHandlerInterface $handler, SanitizerInterface $sanitizer)    {        $this->handler = $handler;        $this->sanitizer = $sanitizer;        $this->sanitizer->setHandler($this->handler);    }    public function queryArguments() // Will be used in the controller class ClassC    {        $queryArgs = null;        if($this->handler->hasAuthorReferrerValue())        {            $this->sanitizer->sanitizeAuthor();            $queryArgs = $this->handler->getAuthorReferrer();        }        if($this->handler->hasDateReferrerValue())        {            $this->sanitizer->sanitizeDate();            $queryArgs = $this->handler->getDateReferrer();        }        if($this->handler->hasSearchReferrerValue())        {            $this->sanitizer->sanitizeSearch();            $queryArgs = $this->handler->getSearchReferrer();        }        if($this->handler->hasTaxReferrerValue())        {            $this->sanitizer->sanitizeTaxonomy();            $queryArgs = $this->handler->getTaxReferrer();        }        return $queryArgs; //Will return null if all 4 conditions fail or return the value from the one that returns true    }}class ClassB implements QueryVarsInterface{    private $handler;    private $sanitizer;    public function __construct(RequestReferrerHandlerInterface $handler, SanitizerInterface $sanitizer)    {        $this->handler = $handler;        $this->sanitizer = $sanitizer;        $this->sanitizer->setHandler($this->handler);           }    public function queryVars() // Will be used in the controller class ClassC    {        $queryVars = null;        if($this->handler->hasAuthorReferrerValue())        {            $this->sanitizer->sanitizeAuthor();            $queryVars = $this->handler->getAuthorReferrer();        }        if($this->handler->hasDateReferrerValue())        {            $this->sanitizer->sanitizeDate();            $queryVars = $this->handler->getDateReferrer();        }        if($this->handler->hasSearchReferrerValue())        {            $this->sanitizer->sanitizeSearch();            $queryVars = $this->handler->getSearchReferrer();        }        if($this->handler->hasTaxReferrerValue())        {            $this->sanitizer->sanitizeTaxonomy();            $queryVars = $this->handler->getTaxReferrer();        }        return $queryVars; //Will return null if all 4 conditions fail or return the value from the one that returns true    }}

There you have it, the ground work is built. You'll notice that in the constructors properties are set for the handler and sanitizer class that was given and then the sanitizer is given the reference to the handler. (Remember, the sanitizers have a reference to the handler so that sanitized properties in the handler are automatically updated. The individual classes don't need to worry about that now.)

So now the million dollar question is how to use this. Well, you need a controller that can accept ClassA and ClassB. We will type hint these by their respective interfaces as well.

class Controller{    public function __construct() {}    public function doStuff(QueryArgumentsInterface $argsClass, QueryVarsInterface $varsClass)    {        var_dump($argsClass->queryArguments());        var_dump($varsClass->queryVars());    }}

In your version of queryArguments() and queryVars() you expected sanitized data for a return value. Let's plug some data in and see what we get. (Note: As you already figured out none of the sanitize methods I used are doing what you were doing, they are illustrative only.)

//TEST DRIVE//Create a controller that will use the classes$controller = new Controller();//Now make use of your new shiny handlers and sanitizers$controller->doStuff(    new ClassA(new RequestReferrerHandler("Mark Twain", null, null, null), new SanitizerForClassA()),     new ClassB(new RequestReferrerHandler(null, "January 1st, 1999", null, null), new SanitizerForClassB()));$controller->doStuff(    new ClassA(new RequestReferrerHandler(null, null, "OK Google Now!", null), new SanitizerForClassA()),     new ClassB(new RequestReferrerHandler(null, null, null, "Super Awesome Taxonomy Tables"), new SanitizerForClassB()));$controller->doStuff(    new ClassA(new RequestReferrerHandler(null, "January 1st, 1999", null, null), new SanitizerForClassA()),     new ClassB(new RequestReferrerHandler("Mark Twain", null, null, null), new SanitizerForClassB()));$controller->doStuff(    new ClassA(new RequestReferrerHandler(null, null, null, "Super Awesome Taxonomy Tables"), new SanitizerForClassA()),     new ClassB(new RequestReferrerHandler(null, null, "OK Google Now!", null), new SanitizerForClassB()));

Here's the output:

Sanitize author -> ClassA makes author an array.array (size=1)  'author' => string 'Mark Twain' (length=10)Sanitize date -> switch to uppercase letters.string 'JANUARY 1ST, 1999' (length=17)Sanitize search -> switch to lowercase letters.string 'ok google now!' (length=14)Sanitize Taxonomy -> convert spaces to underscores.string 'Super_Awesome_Taxonomy_Tables' (length=29)Sanitize date -> switch to uppercase letters.string 'JANUARY 1ST, 1999' (length=17)Sanitize author -> ClassB makes author an object property.object(stdClass)[15]  public 'author' => string 'Mark Twain' (length=10)Sanitize Taxonomy -> convert spaces to underscores.string 'Super_Awesome_Taxonomy_Tables' (length=29)Sanitize search -> switch to lowercase letters.string 'ok google now!' (length=14)

So what did all of this cost you? Short answer - complexity. It took 4 interfaces, 1 abstract class and a handful of concrete classes to output a little bit of data to the screen.

What do you gain? Short answer - flexibility. In the future you may wish to add more classes that implement either the QueryVarsInterface or QueryArgumentsInterface. Consider these classes ClassC, ClassD and ClassE. All of these classes will need a sanitizer class to go with them (that is if SanitizerForClassA or SanitizerForClassB do not fit the bill) and it would be tedious to keep having to write sanitizer classes. Well, good thing for you, since you were programming to an interface all along, you won't have that problem. You can easily make a GenericSanitizer with a default implementation of the sanitizeAuthor() method. Use can use this class with Controller::doStuff() in any case where you don't need a specialized sanitizer class. You could just as easily implement different concrete classes of QueryArgumentInterface or QueryVarsInterface to test out experimental features you want to add without tampering with your current classes.

Hopefully this has given you some insight on some OOP principles. Here is a complete copy of all of the code above. Slap this in an empty PHP file and run it to see everything in action. Happy programming!

    <?php/* * INTERFACES */interface RequestReferrerHandlerInterface{    public function hasAuthorReferrerValue();    public function hasDateReferrerValue();    public function hasSearchReferrerValue();    public function hasTaxReferrerValue();    public function getAuthorReferrer();    public function getDateReferrer();    public function getSearchReferrer();    public function getTaxReferrer();    public function setAuthorReferrer($author);    public function setDateReferrer($date);    public function setSearchReferrer($search);    public function setTaxReferrer($tax);}interface SanitizerInterface{    public function sanitizeAuthor();    public function sanitizeDate();    public function sanitizeSearch();    public function sanitizeTaxonomy();}interface SanitizableHandlerInterface{           public function __construct(RequestReferrerHandlerInterface $handler, SanitizerInterface $sanitizer);}interface QueryVarsInterface extends SanitizableHandlerInterface{    public function queryVars();}interface QueryArgumentsInterface extends SanitizableHandlerInterface{    public function queryArguments();}/* * ABSTRACT CLASSES */abstract class AbstractSanitizer implements SanitizerInterface{    protected $handler;    public function __construct() {}    public function setHandler(RequestReferrerHandlerInterface $handler)    {        $this->handler = $handler;    }       /* For this example we are saying that sanitizeDate(), sanitizeTaxonomy() and     * sanitizeSearch() will be the same no matter what.  So let's implement them      * and leave the child classes to implement sanitizeAuthor().      *      * Implement the details of the sanitizer function to fit your needs.     */    public function sanitizeDate()    {        if($this->handler !== null)        {            //Perform whatever tasks to sanitize the date            $sanitized = strtoupper($this->handler->getDateReferrer());            echo "Sanitize date -> switch to uppercase letters.\n";            $this->handler->setDateReferrer($sanitized);        }    }    public function sanitizeSearch()    {        if($this->handler !== null)        {            //Perform whatever tasks to sanitize the search            $sanitized = strtolower($this->handler->getSearchReferrer());            echo "Sanitize search -> switch to lowercase letters.\n";            $this->handler->setSearchReferrer($sanitized);        }    }    public function sanitizeTaxonomy()    {        if($this->handler !== null)        {            //Perform whatever tasks to sanitize the taxonomy            $sanitized = str_replace(" ", "_", $this->handler->getTaxReferrer());            echo "Sanitize Taxonomy -> convert spaces to underscores.\n";            $this->handler->setTaxReferrer($sanitized);        }    }}/* * CONCRETE CLASSES */class RequestReferrerHandler implements RequestReferrerHandlerInterface{    private $author;    private $date;    private $search;    private $tax;    public function __construct($author = null, $date = null, $search = null, $tax = null)    {        $this->setAuthorReferrer($author);        $this->setDateReferrer($date);        $this->setSearchReferrer($search);        $this->setTaxReferrer($tax);    }    public function hasAuthorReferrerValue()    {        return $this->author !== null ? true : false;    }    public function hasDateReferrerValue()    {        return $this->date !== null ? true : false;    }    public function hasSearchReferrerValue()    {        return $this->search !== null ? true : false;    }    public function hasTaxReferrerValue()    {        return $this->tax !== null ? true : false;    }    public function getAuthorReferrer()    {        return $this->author;    }    public function getDateReferrer()    {        return $this->date;    }    public function getSearchReferrer()    {        return $this->search;    }    public function getTaxReferrer()    {        return $this->tax;    }    public function setAuthorReferrer($author)    {        $this->author = $author;    }    public function setDateReferrer($date)    {        $this->date = $date;    }    public function setSearchReferrer($search)    {        $this->search = $search;    }    public function setTaxReferrer($tax)    {        $this->tax = $tax;    }}class SanitizerForClassA extends AbstractSanitizer{    /* This class must provide an implementation for how ClassA will     * handle the sanitizeAuthor() method.     */    public function sanitizeAuthor()    {        if($this->handler !== null)        {            //Perform whatever tasks to sanitize the for ClassA            $sanitized = array("author" => $this->handler->getAuthorReferrer());            echo "Sanitize author -> ClassA makes author an array.\n";            $this->handler->setAuthorReferrer($sanitized);        }       }}class SanitizerForClassB extends AbstractSanitizer{    /* This class must provide an implementation for how ClassB will     * handle the sanitizeAuthor() method.     */    public function sanitizeAuthor()    {        if($this->handler !== null)        {            //Perform whatever tasks to sanitize the for ClassB            $sanitized = new stdClass();            $sanitized->author = $this->handler->getAuthorReferrer();            echo "Sanitize author -> ClassB makes author an object property. \n";            $this->handler->setAuthorReferrer($sanitized);        }       }}class ClassA implements QueryArgumentsInterface{    private $handler;    private $sanitizer;    public function __construct(RequestReferrerHandlerInterface $handler, SanitizerInterface $sanitizer)    {        $this->handler = $handler;        $this->sanitizer = $sanitizer;        $this->sanitizer->setHandler($this->handler);    }    public function queryArguments() // Will be used in the controller class ClassC    {        $queryArgs = null;        if($this->handler->hasAuthorReferrerValue())        {            $this->sanitizer->sanitizeAuthor();            $queryArgs = $this->handler->getAuthorReferrer();        }        if($this->handler->hasDateReferrerValue())        {            $this->sanitizer->sanitizeDate();            $queryArgs = $this->handler->getDateReferrer();        }        if($this->handler->hasSearchReferrerValue())        {            $this->sanitizer->sanitizeSearch();            $queryArgs = $this->handler->getSearchReferrer();        }        if($this->handler->hasTaxReferrerValue())        {            $this->sanitizer->sanitizeTaxonomy();            $queryArgs = $this->handler->getTaxReferrer();        }        return $queryArgs; //Will return null if all 4 conditions fail or return the value from the one that returns true    }}class ClassB implements QueryVarsInterface{    private $handler;    private $sanitizer;    public function __construct(RequestReferrerHandlerInterface $handler, SanitizerInterface $sanitizer)    {        $this->handler = $handler;        $this->sanitizer = $sanitizer;        $this->sanitizer->setHandler($this->handler);           }    public function queryVars() // Will be used in the controller class ClassC    {        $queryVars = null;        if($this->handler->hasAuthorReferrerValue())        {            $this->sanitizer->sanitizeAuthor();            $queryVars = $this->handler->getAuthorReferrer();        }        if($this->handler->hasDateReferrerValue())        {            $this->sanitizer->sanitizeDate();            $queryVars = $this->handler->getDateReferrer();        }        if($this->handler->hasSearchReferrerValue())        {            $this->sanitizer->sanitizeSearch();            $queryVars = $this->handler->getSearchReferrer();        }        if($this->handler->hasTaxReferrerValue())        {            $this->sanitizer->sanitizeTaxonomy();            $queryVars = $this->handler->getTaxReferrer();        }        return $queryVars; //Will return null if all 4 conditions fail or return the value from the one that returns true    }}class Controller{    public function __construct() {}    public function doStuff(QueryArgumentsInterface $argsClass, QueryVarsInterface $varsClass)    {        var_dump($argsClass->queryArguments());        var_dump($varsClass->queryVars());    }}/* * TEST DRIVE *///Create a controller that will use the classes$controller = new Controller();//Now make use of your new shiny handlers and sanitizers$controller->doStuff(    new ClassA(new RequestReferrerHandler("Mark Twain", null, null, null), new SanitizerForClassA()),     new ClassB(new RequestReferrerHandler(null, "January 1st, 1999", null, null), new SanitizerForClassB()));$controller->doStuff(    new ClassA(new RequestReferrerHandler(null, null, "OK Google Now!", null), new SanitizerForClassA()),     new ClassB(new RequestReferrerHandler(null, null, null, "Super Awesome Taxonomy Tables"), new SanitizerForClassB()));$controller->doStuff(    new ClassA(new RequestReferrerHandler(null, "January 1st, 1999", null, null), new SanitizerForClassA()),     new ClassB(new RequestReferrerHandler("Mark Twain", null, null, null), new SanitizerForClassB()));$controller->doStuff(    new ClassA(new RequestReferrerHandler(null, null, null, "Super Awesome Taxonomy Tables"), new SanitizerForClassA()),     new ClassB(new RequestReferrerHandler(null, null, "OK Google Now!", null), new SanitizerForClassB()));


As I can see in your previous questions, you look for a way to rationalize your OOP development. This is why I won't give you a fish but I will help you to fish by yourself. This means that I'm gonna (try to) give the base that you should know to do a strong OOP code.

1. SRP and composition

As I can see in your questions, you try to separate responsability of your classes. This is a good thing in OOP of course. What you do is called Single Responsability Principle (SRP). This principle imply that you prefer composition over inheritance.

// Compositionclass Car implements VehicleInterface{    private $motor;}class Motor implements MotorInterface

In this case, the car and the motor have 2 different responsabilities.

// Inheritanceclass Car extends MotorVehicle{}

In the case of inheritance, you make a high compling between the vehicle and motor notions.

Imagine I want to had a new notion like the movement for example:

// Compositionclass Car implements VehicleInterface{    private $motor;    private $movement;}class Motor implements MotorInterfaceclass Drive implements MovementInterface

No problem with composition.

// Inheritanceclass Car extends MotorVehicle, DriveVehicle{}

Multiple inheritance is bad (and even not possible in PHP) because you break the SRP. Inheritance should only be used for factoring code for classes of the same responsability. As you should have only one responsability by class, you shouldn't use multiple inheritance. Other possibilities are bad because you cannot tell me that a Car is more a MotorVehicle than a DriveVehicle.

In your case, you have some request referrer handlers and some sanitizer.

2. Interfaces and low coupling

As I told you in my previous answer your do right when using interfaces to make a low coupling between your classes. This give you a more maintenable, scalable and testable code. Take the previous example:

class Car implements VehicleInterface{    private $motor;}class PetrolMotor implements MotorInterfaceclass DieselMotor implements MotorInterface

Your car can easily take different kind of motors now!

The idea that should drive your mind here, is that a class should never use another class directly but an interface describing a behaviour.

In your case, class A and class B should implement an interface SanitizerInterface.

3. Dependency Injection

At this point, you want to set your handlers in your sanitizer. The better way is to use dependency injection. This is really simple!

class Car implements VehicleInterface{    private $motor;    public function __construct(MotorInterface $motor)    {        $this->motor = $motor;    }}class PetrolMotor implements MotorInterface{}class DieselMotor implements MotorInterface{}$motor = new PetrolMotor();$car = new Car($motor);

In your case, you have to inject the request referrer handler in your sanitizer.

4. SOA

Service Oriented Architecture (SOA) applied to OOP is a great way to rationalize your code.

// Standard OOP$car = new Car();$buyer = new Person();$store = new Store();// Many solutions to buy a car!$buyer->buy($car, $store);// or$store->sell($car, $buyer);// or// ...

In standard OOP, you are often confronted to duplicated code because of that. Where should I code this method? Where I can now where I (or someone else) already coded this method? This problem was so boring for me before! I was not able to rationalize my development.

// SOA$car = new Car();$buyer = new Person();$store = new Store();$saleHandler = new SaleHandler();$saleHandler->sell($car, $buyer, $store);

In SOA, you have a "service class" (here SaleHandler) (basically implemented as a singleton) which handle the maniplation of "data classes" (here Car, Person and Store). There is no intelligence in your data classes (you often only have getters and setters on properties). This way, you know where is your code for sales!

In your case, it seems that your request referrer handlers and sanitizers are some kind of services, so it's ok.

Conclusion

In conclusion, you use intuitively some really good OOP practices. Now, you can apply them and know why!

However, I would highly advice you to try a framework like Symfony2. It will provide you with a strong base for you PHP development and a really nice dependency injection component allowing you to define all the dependencies of your classes in configuration files to have a real dynamical code. It will also help you to do SOA with its services.

Using a framework is a good thing to power up your developments and for your professional life (a developer knowing a framework is a lot more sought after). As PHP frameworks are mainly opensource, you can also participate and give you a nice visibility for recruiters.


If you want to use the same object of RequestReferrerHandler class to ClassA and ClassB, then your strategy is correct. Just need to use the object of RequestReferrerHandler class to instantiate ClassA and ClassB. Then you can access the particular methods. i.e. ClassA.queryArguments() or ClassB.queryVars()

If you want to create seperate object of RequestReferrerHandler class for ClassA and ClassB, you can extend RequestReferrerHandler class to ClassA and ClassB without defining the constructor. So, when you create object of ClassA, it automatically inherit the constructor method of RequestReferrerHandler class and you can access the property and method by parent: keyword. For example:

class ClassA extends RequestReferrerHandler{public function santizeAuthor(){    $author = parent::hasAuthorReferrerValue();  // access the base class method    if ($author) {        $author = array_values($author);        $author = ['author' => (int)htmlspecialchars($author[0])]; //Will output ['author' => 1]    }    return $author; //Returns null or the array ['author' => 1]}public function santizeDate(){    $date = parent::hasDateReferrerValue();    if ($date) {        // @TODO Still to work out    }    return $date;}//etcpublic function queryArguments() // Will be used in the controller class ClassC{    $queryArgs = null;    if ($this->santizeAuthor()) {        $queryArgs = $this->santizeAuthor();    } elseif ($this->santizeDate) {        $queryArgs = $this->santizeDate();    } // etc    return $queryArgs; //Will return null if all 4 conditions fail or return the value from the one that returns true}}

You can do as same as for ClassB. Now you can create object for ClassA and ClassB assigning the constructor’s argument of their base class in Class C and use the return value of ClassA.queryArguments() or ClassB.queryVars() from their object.