Proper way to implement "layered" class logic - php

I must admit that I don't know if I have a problem in my design pattern, over-thinking or maybe even just class naming, so any suggestions are welcome. This must be an easy problem but it is rather hard for me to even explain it in words(language barrier), so I will try to do it in code.
For example I'm trying to iterate over a network data stream byte by byte(the task is completely irrelevant to question, just to better explain pseudo-code, please don't say that I use wrong tool to do that). Base class will look something like this:
class BaseNetworkIterator implements Iterator {
protected $stream;
protected $currentByte;
public function __construct() {
$this->stream = open_network_stream();
}
/** .... * */
public function next() {
$this->currentByte = $this->stream->getByte();
}
public function current() {
return $this->currentByte;
}
}
Now imagine that logic in this class is complicated by itself(not one line per method and there are many more helper methods) but I need to do even more. For example I need to reverse bits order in every byte. I don't want to include this logic in base class as it is already big, so I extend it:
class ReverseByte extends BaseNetworkIterator {
/** .... * */
public function next() {
parent::next();
$this->currentByte = $this->reverseStreamByte($this->currentByte);
}
protected function reverseStreamByte($byte) {
/** .... * */
}
}
And more, I want to completely skip all newlines in this stream(reversed):
class SkipNewLine extends ReverseByte {
/** .... * */
public function next() {
do {
parent::next();
} while ($this->currentByte === "\n");
}
}
And if we get two consecutive bytes(after all this operations - they may be separated by newlines etc.) equal to "NO", then we must reverse one following byte once more(don't think about it: just something that uses all previous logic and a protected method that was defined in one of the previous classes):
class HandleDoubleReverseKeyword extends SkipNewLine {
const DOUBLE_REVERSE_KEYWORD = 'NO';
/** .... * */
public function next() {
parent::next();
if ($this->getTwoCharsCache() === self::DOUBLE_REVERSE_KEYWORD) {
$this->currentByte = $this->reverseStreamByte($this->currentByte);
$this->clearTwoCharsCache();
} else {
$this->saveMaxTwoCharsCache($this->currentByte);
}
}
private function saveMaxTwoCharsCache($newChar) {
/** .... * */
}
private function getTwoCharsCache() {
/** .... * */
}
private function clearTwoCharsCache() {
/** .... * */
}
}
And now although logic is split between classes rather nicely for my taste(each consecutive class does something completely different and isolated and it is easy to see what is done in each layer) it is a mess to work with. If we add new "filter" in the middle we must change what later class is extended from... Naming starts to get insane as "HandleDoubleReverseKeyword" doesn't explain what this class really does even remotely (even if we are in "NetworkIterator" namespace). I don't really understand what a "final" class should look like.
I was thinking of using traits as naming goes much easier there but they cause more problems then solve(execution order, code completion etc.).
I was also thinking of using Yii-like "behaviour/event" pattern (Something like: base next() method consecutively calls an array of class/methods and some external source can add more class/methods to that array instead of extending base class) but there is a huge problem with properties/methods visibility(it is a problem, basically I have to make ALL properties and methods public) and more importantly it is not clear how to properly access methods of other additional classes.
Ok, this still may be not very clear so any feedback is appreciated. I know there is no question mark in this "question", but I hope my intentions are clear and the only thing that comes to mind is: how to do this type of design properly?

My 2 cents:
The stream should be separated from the iterator class and its sub classes. Iterator defines how to access the data, each iterator instance should only hold the reference to the data, not the actual data.
The logic in class HandleDoubleReverseKeyword is about how to process the data, not how to access the data; and the action is decided base on what the data is, so the class should not inherited from the iterator class; here I think we can use the state pattern.
So the code to deal with the stream could be like this:
$stream = open_network_stream();
$iterator it = new Iterator(&stream);
$data = it->next();
while(data){
switch(data->value){
case 'A': AcitionA->action();break;
case 'B': AcitionB->action();break;
}
$data = it->next();
}

I think you are approaching this from the wrong perspective.
The current hierarchy you have in place highly limits the re-usability of each component, since they are all implemented to work only on the result of a byte stream iterator. If for example you needed to implement a file iterator, and then skip over each new line, you cannot possibly reuse your existing SkipNewLine, because it works only on the result of a reverse byte iterator.
Another fallacy is that you have no way to control the order in which each of this steps occurred without rewriting the entire class structure. Even something as simply as moving the SkipNewLine class before the ReverseByte (or after the HandleDoubleReverseKeyword) is a refactoring nightmare.
I suggest you implement each step in the iteration as a separate class, that solely acts on a generic stream, and makes no assumptions as to the state of the source stream. You can inject an instance of each of these components into your BaseNetworkIterator, and use them independently of each other.
This will further provide you with the ability to act on each of the individual states with knowledge of the global state of the iteration.

Related

Documenting abstract factory method return types in PHP with docblocks

This has been asked again and again, but the replies are a bit old and I'm somewhat desperately hoping something changed since "can't be done" replies.
Context:
class AbstractBuildObject {}
class Hammer extends AbstractBuildObject{}
class Nail extends AbstractBuildObject{}
class AbstractFactory{
/**
* return $type
*/
public function build1(string $type): AbstractBuiltObject {
return new $type();
}
/**
* return any(AbstractBuiltObject)
*/
public function build2(string $someArg): AbstractBuiltObject {
$type = $this->decideTypeBasedOnArgsAndState($someArg);
return new $type();
}
}
I tried to represent what I need with the annotations above the builders.
return $type (or ideally return $type of AbstractBuiltObject should hint that the return type is specified in the input parameter.
In the second case, any(AbstractBuiltObject) signifies that any derived concretion of the abstract class might be returned.
So I need some kind of annotation to achieve the effects I described. These annotations obviously don't work, I just used them for illustrating the concept.
I know one might be tempted to use pipe type joins like return Hammer|Nail, but in my case, the factory class should hold be modified every time a new concrete implementation is added to the project, it's also not specific enough in the build1 case, where I know precisely what the return type should be.
So, in short, I need this to work at least in PhpStorm:
(new AbstractFactory())->build1(Hammer::class)-> // I should have Hammer autocomplete here
(new AbstractFactory())->build2('foo')-> // I should have autocomplete of any concretion of the abstract here
Philosophical conversations about breaking the D in SOLID aside, if you want something like this to autocomplete the methods that are available only on Hammer:
(new AbstractFactory())->build1(Hammer::class)->
Then you have already committed to writing this block of code specifically for the Hammer class. And if you're going to do that, then you might as well do this:
$hammer = (new AbstractFactory())->build1(Hammer::class);
And if you do that, then you might as well do this:
/**
* #var Hammer
*/
$hammer = (new AbstractFactory())->build1(Hammer::class);
And then your autocomplete on $hammer-> should work.
The solution we adopted is this:
<?php
class AbstractBuiltClass {
/**
* #return static
*/
public static function type(self $instance)
// change return type to :static when #PHP72 support is dropped and remove explicit typecheck
:self
{
if(!($instance instanceof static)){
throw new Exception();
}
return $instance;
}
}
class Hammer extends AbstractBuiltClass{
function hammerMethod(){}
}
Hammer::type($factory->get(Hammer::class))->hammerMethod();
Contenders for a viable solution:
Psalm template annotations: https://psalm.dev/docs/annotating_code/templated_annotations/ very promising but not widely supported yet
Variable docblock (see Alex Howansky's answer)

Modifying a PHP class file or stub programmatically

Given a PSR-2 compliant PHP class file (or stub)
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Car extends Model
{
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
//
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
//
];
}
Is there some tool to easily parse and modify it?
In the best of worlds with a fluent API, maybe something like:
PhpClass::make(".../Car.php")
->setNamespace("Some/New/Namespace")
->use("Some\Dependency")
->addMethod($newFunctionBody)
Im aware this might be a naive example, but how close to such a tool is there out there? By tool I mean something I can pull in as a dependency preferably via composer.
Right now I have a somewhat working solution using placeholders and regex but it starts to grow out of control with many edge cases. Therefore im thinking I might need to actually interpret the PHP.
Componere
Componere is a PHP 7 extension, available on pecl and documented in the PHP manual ...
The code below registers the definition in the class entry table:
<?php
/* just making the example standalone */
class Model {}
class Car extends Model {
public function something() {}
}
trait SaysVroomVroomWhenPoked {
public function poke() {
return "Vroom Vroom";
}
}
$def = new \Componere\Definition(Some\Place\Car::class, Car::class);
$def->addTrait(SaysVroomVroomWhenPoked::class);
$def->addMethod("newMethod", new \Componere\Method(function(){
return 42;
}));
$def->register();
$car = new \Some\Place\Car();
printf("%s and %d\n", $car->poke(), $car->newMethod());
?>
Registering the class in the entry table may be desirable in some cases, it's effects are application wide for the life of the request.
The code below patches a particular instance of an object with the required features:
<?php
/* just making the example standalone */
class Model {}
class Car extends Model {
public function something() {}
}
trait SaysVroomVroomWhenPoked {
public function poke() {
return "Vroom Vroom";
}
}
function accept(Car $car) {
$patch = new \Componere\Patch($car);
$patch->addTrait(SaysVroomVroomWhenPoked::class);
$patch->addMethod("newMethod", new \Componere\Method(function(){
return 42;
}));
$patch->apply();
printf("%s and %d\n", $car->poke(), $car->newMethod());
}
$car = new Car();
accept($car);
var_dump(method_exists($car, "newMethod")); # false
?>
Note that doing this everywhere is much less efficient than changing the definition, but it's side effects disappear when the accept function returns.
http://php.net/componere
Note: it has a fluid interface, but for the purposes of clarity I did not use it here ...
Edit:
I just noticed your comment expressing an interest in pre-processing code, or possibly using anonymous classes, and not runtime manipulation. Using anonymous classes is an excellent idea, but I don't think you need an example of that ...
Full disclosure: I wrote Componere, and I wrote the implementation of anonymous classes for PHP ...
Anything I say to dissuade you from pre-processing is probably going to be pretty empty now ...
I built a Laravel package for this use case: https://github.com/ajthinking/php-file-manipulator
There may actually be a way to do this. The concept you're looking for is called 'monkey patching'. I really wouldn't recommend opening that can of worms if at all possible, it's inherently hacky. But I think there are some PHP packages that offer it. You might also want to look into Php7's concept of 'anonymous classes'. Perhaps coupled with using Reflection to parse the class you're trying to effectively alter, you could build an anonymous class to replicate it, use Reflection on it to get the raw code therein, write it to a temp file, and somehow swap it out for the original in the auto-loader's namespace=>filepath list at runtime.
I can't promise any of that will work though, and can promise it'd be a headache. But if you're looking to tinker, there's some food for thought. If you do get it working, please post it here, I wouldn't mind seeing it. Good luck.

optional dependencies within a class

I'm looking for some direction regarding the following, I'm new to OOP and getting there but think either my lack of understanding is causing me to get stuck in a rabbit hole or I'm just over thinking things too much and being anal.
basically i have a main class called "CurlRequest" which sole purpose is to perform curl requests, providing a url and params it returns me some html. This class works and functions as intended and I'm happy with that.
I use this class for a few projects but for one I then wanted to track the performance of my requests made. attempted, failed, passed etc, so i created a static class for this which manages all my counters. I place counter references like the following at different areas in my CurlRequest class.
PerformanceTracker::Increment('CurlRequest.Attempted');
PerformanceTracker::Increment('CurlRequest.Passed');
PerformanceTracker::Increment('CurlRequest.Failed');
I have around 10 or so of these with my class tracking all kinds of things during the curl request and i also use my PerformanceTracker class in other classes i made.
However like mentioned i only wanted to do this for one of my projects, so find my self in the situation of having my original CurlRequest class and an altered one with performance counters in it.
My question is, is their a way i can use the same class for any project and choose to use the PerformanceTracker class or not. The obvious way i thought of was to pass an $option argument into the class and then have if statements around all the counters, but can't help think its messy.
if ($this->options['perfCounter'] == true ) {
PerformanceTracker::Increment($this->owner . '.CurlRequest.Failed');
}
this also adds a lot of extra code to the class.
I suggest placing the if statement in a separate method
private function handlePerformanceTracker($q)
{
if ($this->options['perfCounter'] == true ) {
PerformanceTracker::Increment($q);
}
}
And call this method instead of your calls to
PerformanceTracker::Increment(...);
Also if you find that you want to track performance differently between your projects it might be useful to change your constructor to accept a callable argument, this way you externalize the actual implementation from the CurlRequest class itself.
public function __construct(..., callable performanceHandler)
Then when you instantiate your class:
$curlRequest = new CurlRequest(..., function($outcome) {
//your implementation
});
You can use inheritance and create a subclass that performs the logging before delegating to the parents methods:
class PerformanceTracker
{
static function Increment($s)
{
echo $s;
}
}
class CurlRequest
{
function get($url){
//preform curl request, save html to variable etc
//dummy vars used here so working example code
$html = 'html here';
$curlError = false;
if($curlError){
$this->error($curlError);
}
return $this->success($html);
}
protected function success($html)
{
return $html;
}
protected function error($curlError)
{
throw new Exception($curlError);
}
}
class LoggingCurlRequest extends CurlRequest
{
function get($url)
{
PerformanceTracker::Increment('CurlRequest.Attempted');
return parent::get($url);
}
function success($html)
{
PerformanceTracker::Increment('CurlRequest.Passed');
return parent::success($html);
}
function error($curlError)
{
PerformanceTracker::Increment('CurlRequest.Failed');
parent::error($curlError);
}
}
$lcr = new LoggingCurlRequest();
$lcr->get('unused in example');
As i have used dummy classes with minimal code to demo the technique the benefit might not be obvious, but in you real code, the methods in the CurlRequest class will be more complex, but the methods in the logging class will remain as two liners, with the log function and the call to the parent method.
Using this technique you can modify the parent class without effecting the derived classes (provided the method signatures dont change), can create other derived classes (how about a CachingCurlRequest) etc.
For the full benefits of OOP you should look into dependency injection and interfaces
From an OOP perspective you could use the 'Null' object pattern. This just means that the dependency used by the CurlRequest class is abstract (possibly an interface?). You would then have Two concrete implementations of PerformanceTracker: the one you have today and one that does nothing (it does not have any behavior). In this way for the one project when you instantiate the CurlRequest class it would use the concrete implementation that has behavior and for all the other projects it would use the concrete implementation with no behavior. All of the code in CurlRequest would look the same but it would have different behavior depending on which concrete implementation it was using

Create class instance from within static method

As the title says, I'm wanting to create an instance of a class from within a static method of the same class. I've figured out so far is that I can by doing something like this:
class Foo{
public $val;
public static function bar($val){
$inst = new Foo;
$inst->val = $val;
return $inst;
}
}
Which therefore lets me do this.
$obj = Foo::bar("some variable");
Which is great.
So now the questions. Is there an easier way of doing this that I'm not aware of, or any shortcuts to achieving the same result? Are there any advantages or disadvantages of creating an instance in this fashion?
Thanks.
They way you're doing it is fine. There are a few other things that can make your life easier that you can do as well.
Don't hardcode the class name. If you're on 5.3+, use the keyword static. That way, if you extend the class, the new function can instantiate that one as well:
public static function bar($var) {
$obj = new static();
$obj->var = $var;
return $obj;
}
Then you can use it in any extending class without needing to override anything.
Figure out if $var should be passed in through a constructor rather than set after construction. If the object depends upon it, you should require it.
public function __construct($var) {
$this->var = $var;
}
That way you can't instantiate the object without setting the variable.
Enforce the instantiation of the class through the static method. If you're doing anything in there that you need to do, then make the constructor either protected or private. That way, someone can't bypass the static method.
protected function __construct() {}
private function __construct() {}
Edit: Based on your comment above, it sounds to me like you're trying to implement the Singleton Design Pattern. There's tons of information out there about why it's not a great idea and the bad things it may do. It has uses as well.
But there are a few other patterns that may be of use to you depending on what you're doing exactly.
You can use the Factory Method if you're trying to create different objects using the same steps.
If all of the objects start off the same and then are customized, you could use the Prototype Pattern.
You could use an Object Pool if it's particularly expensive to create your object.
But one thing to consider, is that in PHP objects are pretty light weight. Don't try to avoid creating a new object just for that overhead. Avoid doing heavy things like database queries or filesystem accesses multiple times. But don't worry about calling new Foo() unless foo's constructor is particularly heavy...
This looks like a simple factory method pattern.
You have a nice advantage: suppose that in the future you want to start using a different implementation (but that does the same thing). Using a factory you can change all the objects that are created in many places of a complex system simply by changing the creator method. Note that this would work easier if you used an external class (as is in the first link below).
Keeping it as you have now, you can also subclass this class and override the method to create a more complex object. I don't think this is what you want to achieve in here.
Anyway, this is good to enable Test Driven Development, abstraction and lots of other good things.
links:
Php patterns
Factory method pattern on wikipedia
If you're just creating an object, this isn't very usefull. You could just call a constructor. But if you're doing something more complicated (like you're starting with some sort of singleton pattern but haven't included all the details in this example), then:
This sounds about right. If you want to prevent objects created in the default way like this:
$obj = new Foo("Some Variable");
You can add a private constructor:
class Foo{
public $val;
private __construct(){}
public static function bar($val){
$inst = new Foo;
$inst->val = $val;
return $inst;
}
}
Now you enforce people to use your static class. The need to set the val in the function might be gone, so you could even add the value-parameter to your private constructor but do the other things (that you presumably want to do, like check for some sort of singleton pattern) in your 'bar' function
Super late but found this useful.
A good example of this in the wild is this static method from Audi's UI library returning an Array of instantiated TextField classes from within TextField's static method upgradeElements.
/**
* Class constructor for Textfield AUI component.
* Implements AUI component design pattern defined at:
* https://github.com/...
*
* #param {HTMLElement} element The element that will be upgraded.
*/
export default class Textfield extends Component {
/**
* Upgrades all Textfield AUI components.
* #returns {Array} Returns an array of all newly upgraded components.
*/
static upgradeElements() {
let components = [];
Array.from(document.querySelectorAll(SELECTOR_COMPONENT)).forEach(element => {
if (!Component.isElementUpgraded(element)) {
components.push(new Textfield(element));
}
});
return components;
};
constructor(element) {
super(element);
}
...
See the rest in the repo
https://github.com/audi/audi-ui/blob/master/src/textfield/textfield.js#L25

unit test a method that creates an object

I'm trying to get my head round Unit Testing and there's one more piece of the jigsaw I need to find.
What I'm trying to do is write tests for the following code. In this case, I've got a really simple Front Controller (written in PHP).
class frontController
{
public function routeRequest($oRequest)
{
$sClassname = $oRequest->getController();
$sMethod = $oRequest->getAction();
$oController = new $sClassname();
$oResponse = $oController->{$sMethod}($oRequest);
return $oResponse;
}
}
The problem I have is because the code creates new objects. I can easily mock the request object so that I can tightly control what it will actually do within my test case. I'm not sure the best way to actually replace the controller with a test double.
This article from IBM suggests having a factory method for creating my controller and then overriding this with a specific class used for testing:
class frontController
{
public function routeRequest($oRequest)
{
$sMethod = $oRequest->getAction();
$oController = $this->createController($oRequest);
$oResponse = $oController->{$sMethod}($oRequest);
return $oResponse;
}
protected function createController($oRequest)
{
$sClassname = $oRequest->getController();
return new $sClassname();
}
}
and then for testing perhaps something like this:
class testFrontController extends frontController
{
public function setMockController($oMockController)
{
$this->oMc = $oMockController;
}
protected function createController($oRequest)
{
return $this->oMockController;
}
}
(note this isn't quite what the article says, but I'm thinking it would be most useful to me if it did this)
Another solution could be to have another class that creates the controller. This would then be a dependent class of the frontController. This way I can replace the factory/creation class during testing with a test double. Something like this:
class frontController
{
public function routeRequest($oRequest, $oControllerFactory)
{
$sMethod = $oRequest->getAction();
$oController = $oControllerFactory->create($oRequest);
$oResponse = $oController->{$sMethod}($oRequest);
return $oResponse;
}
}
class controllerFactory
{
public function create($oRequest)
{
$sClassname = $oRequest->getController();
return new $sClassname();
}
}
I guess the dependency injection could be taken care of in the front controller constructor or via a setter instead of a parameter to the actual "route" method.
I think I prefer option 2.
Is either of these two methods the right way of going about testing this kind of thing?
(perhaps "good way" would be better word here!)
Any thoughts or suggestions on option 1 vs option 2 appreciated or indeed any alternatives. Remember - the key thing is about how to test an object that itself creates other objects as part of its execution.
Thanks!
You might find this article handy.
It discusses how object creation should be separated from the actual running of the application.
I generally find factories to be a good thing to use for this scenario. In addition to the swappability aspect, it means that additional parameters, data, or dependencies required by the object being created can be stored by the factory, and so the object which actually requests the new object doesn't have to know anything about them...
You do not want to use the real controller but a mock, right ?
It seems to me the simplest way to achieve this would be to subclass the request so that it returns the name of a MockController.
I assume you have thought through your assertions so as to define the goal of what exactly you are testing. Keep in mind that unit tests are going to be testing the returns from your methods, which, in this case, is $oResponse (whatever this may be). As a result, your test assertions will be based on this return value. Since I don't know what that return value is from your code snippets, I can only demonstrate an example that you can complete.
I would recommend PHPUnit for your testing as it seems to be the most complete package for PHP imho (many are fans of SimpleTest, as well ... to each their own).
It would look something like this (Please note that I have left out includes for brevity. Read the PHPUnit documentation for more information):
class AimTest extends PHPUnit_Framework_TestCase{
private $_controller = null;
private $_request = null;
public function setUp(){
$this->_controller = new frontController();
//what does this object's type?
$this->_request = new requestObject();
}
public function testObjectCreation(){
/*
* note, that this is only one of several assertions that could
* be made depending on the return value
*/
$return = $this->_controller->routeRequest($this->_request);
//tailor to what you expect your output to be
$this->assertTrue($return == "my expected output");
}
Hope I didn't miss the mark completely on your stated purpose. Moral of the story is that you can only test what your methods return. If you want to test object instantiation from a method, use the instanceof PHP function against a method that returns that object after instantiation.

Categories