Class design patterns - best practices - php

men and women!
My problem is I don't really know what is the best way to design so I defined 2 classes 1'st one is:
class color
{
private $id = NULL;
private $name = '';
private $rgb = NULL;
private $cmy = NULL;
private $wavelength = NULL;
private $frequency = NULL;
public function __construct($name, $rgb, $cmy, $wavelenght, $frequency)
{
setName($name);
setRGB($rgb);
setCMY($cmy);
setWavelength($wavelength);
setFrequency($frequency);
}
public function __destruct()
{
}
public function setName($name)
{
$this->name=$name;
}
public function setRGB($rgb)
{
$this->rgb=$rgb;
}
public function setCMY($cmy)
{
$this->cmy=$cmy;
}
public function setWavelength($wavelength)
{
$this->wavelength=$wavelength;
}
public function setFrequency($frequency)
{
$this->frequency=$frequency;
}
public function getId()
{
return $this->id;
}
public function getName()
{
return $this->name;
}
public function getRGB()
{
return $this->rgb;
}
public function getCMY()
{
return $this->cmy;
}
public function getWavelength()
{
return $this->wavelength;
}
public function getFrequency()
{
return $this->frequency;
}
public function toJSON()
{
return "{'id':'".$this->id."', 'name':'".$this->name."', 'rgb':'".$this->rgb."', 'cmy':'".$this->cmy."', 'wavelength':'".$this->wavelength."', 'frequency':'".$this->frequency."'}";
}
public function toCSV()
{
return $this->id . ", " . $this->name . ", " . $this->rgb . ", " . $this->cmy . ", " . $this->wavelength . ", " . $this->frequency;
}
public function toHTML()
{
return "<p>ID: " . $this->id . "</p><p>Name: " . $this->name . "</p><p>RGB: " . $this->rgb . "</p><p>CMY: " . $this->cmy . "</p><p>Wavelength: " . $this->wavelength . "</p><p>Frequency: " . $this->frequency . "</p>";
}
and 2'nd class looks like
class CRUD_color
{
public function create_color($parameters)
{
$color=new color();
$color->setName($parameter['name']);
$color->setRGB($parameter['rgb']);
$color->setCMY($parameter['cmy']);
$color->setWavelength($parameter['wavelength']);
$color->setFrequency($parameter['frequency']);
$entitymanager->persist($color);
$entitymanager->flush();
}
public function request_color($parameters)
{
$color=$entitymanager->find($parameter['id']);
echo $color->toJSON($parameter['name']);
}
public function update_color($parameters)
{
$color=$entitymanager->find($parameter['id']);
$color->setName($parameter['name']);
$color->setRGB($parameter['rgb']);
$color->setCMY($parameter['cmy']);
$color->setWavelength($parameter['wavelength']);
$color->setFrequency($parameter['frequency']);
$entitymanager->persist($color);
$entitymanager->flush();
}
public function delete_color($parameters)
{
$color=$entitymanager->delete($parameter['id']);
}
}
now my question is if maybe it is better to have only one class color and include the functions from the second class in the 1st one? or let them apart?
why is one better than the other or vice versa? the design pattern is important to me so why choose one over the other..
Is there a problem if lets say we have the function create_color in witch we instantianate the class itself like new color() ????

now my question is if maybe it is better to have only one class color
and include the functions from the second class in the 1st one?
No.
or let them apart?
Yes.
why is one better than the other or vice versa?
If you decide to have different types of CRUDs or other objects that manipulate with colors (Builder for example) you need class Color to be a separate one. The same if you would like your CRUD to manipulate not only with Color objects. It is better to make decoupling as much as possible.
the design pattern is important to me so why choose one over the
other..
There are many patterns that can be helpful for you: Builder, Repository, Decorator, Bridge, Factory... It depends on your needs what is better to implement. You must be familiar with all of them and never implement it without understanding of why it is best choice for this particular task.
Is there a problem if lets say we have the function create_color in
witch we instantianate the class itself like new color() ????
Yes, if you need to add some creational step (for example generate ID in different way) you have to add this step to all your classes like Color, Font etc. In case of separate builder class - you add this step to create() method and it will generate ID in new way for all abstract objects.
Hope this will show you a way to learn more about patterns. Good luck!
BTW, take a look at this great free book: http://gameprogrammingpatterns.com/

Related

how to design a has a relationship in oop (using php)

I am really new in OOP, and not a good English talker, so if my question is dumb, I am sorry.
I thought I understand the oop but when I start codding with it, it works but does not feel right.
the following code is my first try, I will ask my question after them. (I cut the database codes, but as I said the program works.)
// class.Post.inc
class Post {
private $_db;
private $_postId;
private $_title;
private $_creatorId;
public function __construct() {
$this->_db = Database::getInstance ()->getConnection ();
}
public function getApost($postId = 0) {
if($postId){
/* get the post data from database(including user_id) and put them in the instance variables */
$this->_postId = $row ['post_id'];
$this->_title = $row ['title'];
$this->_creatorId = $row ['user_id'];
}
}
public function getCreator() {
$creator = new User ();
return $creator->getUserObject ( $this->_creatorId );
}
public function getPostId() {
return $this->_postId;
}
public function getTitle() {
return $this->_title;
}
}
//class.User.inc
class User {
private $_db;
private $_userId;
private $_name;
public function __construct() {
$this->_db = Database::getInstance ()->getConnection ();
}
public function getUserObject($userId = null) {
if ($userId) {
/* read data from database and put them in the instance variables */
$this->_userId = $row ['user_id'];
$this->_name = $row ['name'];
return $this;
}
return false;
}
public function getUserId() {
return $this->_userId;
}
public function getName() {
return $this->_name;
}
}
//index.php
spl_autoload_register ( function ($className) {
require_once 'classes/class.' . $className . '.inc';
} );
$post = new Post ();
$post->getApost(1);
$creator = $post -> getCreator();
echo $post->getPostId () . '<br>';
echo $post->getTitle () . '<br>';
echo $creator->getName () . '<br>';
my questions:
post has a creator, do I design this relationship right?
what if I want to use join to select post and its creator together?
if I want to show a list of posts, should I define a new method in the post class or in the index page or define a new class for it? how?
There is much that can be said about your code. I could write what you did wrong few hours, but you didn't asked for that, so I answer your questions firsts.
Yes, it's ok to get creator from post from the perspective of entity relations.
I don't see any clean way using your implementation. It's possible, but it would require major refactoring.
If you want to use Active Record pattern, you could of course implement new method in Post class. But I much more recommend using Data Mapper pattern which is cleaner from OOP perspective because of SRP.
One piece of advice at the end:
I often see new developers to reinvent a wheel, which is exactly what you are doing. There are great and feature complete libraries which saves you lot of time writing your own. For example Doctrine ORM. Or much simplier Nextras ORM. Learning curve may seem high, but I guarantee, it's worth it.

Liskov substitution principle and proper way to use inherited classes

I have some handler ("controller") classes and they can process items in some way:
interface IHandler
{
public function execute(Item $item);
}
class FirstHandler implements IHandler
{
public function execute(Item $item) { echo $item->getTitle(); }
}
class SecondHandler implements IHandler
{
public function execute(Item $item) { echo $item->getId() . $item->getTitle(); }
}
class Item
{
public function getId() { return rand(); }
public function getTitle() { return 'title at ' . time(); }
}
But then I need to add some new functionality in child Item class:
class NewItem extends Item
{
public function getAuthor() { return 'author ' . rand(); }
}
and use it in SecondHandler
class SecondHandler implements IHandler
{
public function execute(Item $item) { printf('%d %s, author %s', $item->getId(), $item->getTitle(), $item->getAuthor()); }
}
But Item class actually has not getAuthor method. And, if I try to change signature of accept method in SecondHandler class, I will catch E_STRICT error about declaration compatibility. And, of course, it's sort of LSP violation.
How can I fix this problem? Do I need two interfaces, for example, INewHandler and IHandler, with different signatures of execute method? But it's some sort of code duplicates.
Also, I cannot use __constructor(Item $item) and __construct(NewItem $item) in handlers (and execute method without arguments), which will be seen like a better solution: they must be immutable and only single instance of every strategy allowed in application lifecycle.
As you discovered by yourself, the type hinting implementation of PHP has a lot limitations that make scenarios, like the one described by you, harder than they should be. In other typed languages like Java and Swift your implementation is absolutely licit.
After some thinking on your question I came to the solution presented by FĂ©lix but I consider it too much over engineered compared to the problem.
My answer to your question is not a solution but an advice that I give to you after years of development with PHP:
Give up with type hinting in PHP and develop like it should be... in a dynamic way.
PHP is more similar to Ruby/Python/JavaScript than Java/C++, and trying to copy 1 to 1 from static typed languages translates in forced and convolute implementations.
The solution to your implementation problem is easy, so don't over complicate it and keep it easy as it should be (KISS principle).
Declare the methods' arguments without the type and implement a check where you really need (for example throwing an exception).
interface IStrategy
{
public function execute($item);
}
class FirstStrategy implements IStrategy
{
public function execute($item) {
echo $item->getTitle();
}
}
class SecondStrategy implements IStrategy
{
public function execute($item) {
// execute(NewItem $item) is identical to this check.
if (! $item instanceof NewItem) {
throw new Exception('$item must be an instance of NewItem');
}
echo $item->getAuthor();
}
}
class Item
{
public function getId() { return rand(); }
public function getTitle() { return 'title at ' . time(); }
}
class NewItem extends Item
{
public function getAuthor() { return 'author ' . rand(); }
}
Again, don't think in Java but follow as much as possible the duck typing way.
When possible, try to don't strictly force the type of the parameters but adapt the behavior of the code based on the available interfaces (Duck Typing).
class SecondStrategy implements IStrategy
{
public function execute($item) {
$message = $item->getTitle();
// PHP 5 interface availability check.
if (is_callable([$item, 'getAuthor'])) {
$message .= ' ' . $item->getAuthor();
}
// With PHP 7 is even better.
// try {
// $message .= ' ' . $item->getAuthor();
// } catch (Error $e) {}
echo $message;
}
}
I hope to have helped you. ^_^
Both #daniele-orlando and #ihor-burlachenko made valid points.
Consider following approach for method overloading, which is kind of a compromise and should scale well:
interface IHandler
{
/**
* #param $item Item|NewItem
*/
public function execute($item);
// protected function executeItem(Item $item);
// protected function executeNewItem(NewItem $item);
}
trait IHandlerTrait
{
public function execute($item)
{
switch(true) {
case $item instanceof Item:
return $this->executeItem($item);
case $item instanceof NewItem:
return $this->executeNewItem($item);
default:
throw new \InvalidArgumentException("Unsupported parameter type " . get_class($item));
}
}
protected function executeItem(Item $item)
{
throw new \LogicException(__CLASS__ . " cannot handle execute() for type Item");
}
protected function executeNewItem(NewItem $item)
{
throw new \LogicException(__CLASS__ . " cannot handle execute() for type NewItem");
}
}
class FirstHandler implements IHandler
{
use IIHandlerTrait;
protected function executeItem(Item $item) { echo $item->getTitle(); }
}
class SecondHandler implements IHandler
{
use IIHandlerTrait;
// only if SecondHandler still need to support `Item` for backward compatibility
protected function executeItem(Item $item) { echo $item->getId() . $item-> getTitle(); }
protected function executeNewItem(NewItem $item) { printf('%d %s, author %s', $item->getId(), $item->getTitle(), $item->getAuthor()); }
}
Are you sure you want to use Strategy pattern here?
It looks, like the strategy's action here depends on the type of the element it processes. And Visitor pattern might apply here as well in this case.
As it stands, you appear to want to execute an extensible data record (Item and NewItem). Consider instead executing some pluggable behaviour (implemented via an interface).
It's hard from your writing to guess what that behavior would be, because (New)Item is just a glorified data structure in the example you provide.
If you want to work/manipulate with object in another object, you could/should use interfaces.
interface IStrategy
{
public function execute(ItemInterface $item);
}
interface ItemInterface
{
public function getTitle();
.....
}
If you want to extend public functionality of the (New)Item class you can make new interface for newItem
interface NewItemInterface extends ItemInterface
{
...
}
class SecondStrategy implements IStrategy
{
public function execute(NewItemInterface $item)
{ .... }
}
Or you can use some instance checks as others have mentioned.
If your inheritance and suggestion that SecondHandler should handle both Item and NewItem were correct in the first place, then you should be able to hide this functionality behind the common interface. From your examples, it might be called toString() which might be a part the Item interface.
Otherwise, there might be something wrong with your design initially. And you have to change your inheritance or the way you handle items. Or something else we don't know about.
Also, I don't know why you need DTO but it seems there is some misunderstanding of Doctrine. Doctrine is an ORM and it solves your persistence problem. It adds limitations on how you communicate with your storage introducing repositories, but it doesn't define your domain logic.
As per the Interface segregation please find some solution.
```
# based on interface segrigation.
interface BasicInfo
{
public function getId();
public function getTitle();
}
interface AuthorInfo
{
public function getAuthor();
}
interface IHandler
{
public function execute(Item $item);
}
class FirstHandler implements IHandler
{
public function execute(Item $item) { echo $item->getTitle(); }
}
class SecondHandler implements IHandler
{
public function execute(Item $item) { echo $item->getId() . $item->getTitle(); }
}
class Item implements BasicInfo
{
public function getId() { return rand(); }
public function getTitle() { return 'title at ' . time(); }
}
class Item2 extends Item implements AuthorInfo
{
public function getAuthor() { return 'author ' . rand(); }
}
But I think you should not kept the dependency of the Item class. you should write some duplicated code to keep the class pluggable/independent. So the Open/close principle should also there.

PHP best practice for action based on an object type

I have a PHP/Laravel best practice question.
Here is the scenario:
I have an object with a "type" property in it. The type property will be set to an integer of some kind.
Depending on the "type" integer in the object, different actions will have to happen.
What is the best way to process this object? I am trying desperately to think of a way that avoids using a whole bunch of if/else statements as that feels very like a very wrong and ugly way to approach this.
i.e. I don't want this:
if($obj->type == 1) {
//process actions for type 1
}
else if($obj->type == 2){
//process actions for type 2
}
Would appreciate any advice.
Thanks!
Thanks to #Ryan Vincent I found this resource (https://sourcemaking.com/design_patterns/strategy/php) and changed the Strategy design pattern a bit. For avoiding hard-coded type values check how the dynamic class loading is done in StrategyContext::__construct method. New class instance is initiated by the $type variable name. Class names should be strings in PHP so this way forces types to be strings not only numbers.
Different than the original example in the article, I attached StrategyContext to the book object and wrap the get methods with the strategy to have better use of book object.
Unfortunately if the business logic will be in your code somehow you need to hardcode it. With this method you don't hardcode for each type but you need to create a strategy class for each type. In the example we have StrategyCaps , StrategyStars and StrategyExclaim strategies. So our types are limited to Caps, Stars and Exclaim.
I didn't try this piece of code in production environment but you can have a starting point via the example.
Also for dynamic loading, you can benefit from this question too.instantiate a class from a variable in PHP?
Hope it helps,
<?php
interface StrategyInterface {
public function showTitle($title);
public function showAuthor($author);
}
class StrategyContext implements StrategyInterface {
private $strategy = NULL;
public function __construct($type) {
//Dynamic class loading per type
$classname="Strategy{$type}";
if(class_exists($classname)) {
$this->strategy = new $classname();
} else {
throw new Exception("Strategy not found", 1);
}
}
public function showTitle($title) {
return $this->strategy->showTitle($title);
}
public function showAuthor($author) {
return $this->strategy->showAuthor($author);
}
}
class StrategyCaps implements StrategyInterface {
public function showTitle($title) {
return strtoupper ($title);
}
public function showAuthor($author) {
return strtoupper ($author);
}
}
class StrategyExclaim implements StrategyInterface {
public function showTitle($title) {
return Str_replace(' ','!',$title);
}
public function showAuthor($author) {
return Str_replace(' ','!',$author);
}
}
class StrategyStars implements StrategyInterface {
public function showTitle($title) {
return Str_replace(' ','*',$title);
}
public function showAuthor($author) {
return Str_replace(' ','*',$author);
}
}
class Book {
private $author;
private $title;
private $strategy;
function __construct($strategy, $title_in, $author_in) {
$this->strategy = new StrategyContext($strategy);
$this->author = $author_in;
$this->title = $title_in;
}
function getAuthor() {
return $this->strategy->showAuthor($this->author);
}
function getTitle() {
return $this->strategy->showTitle($this->title);
}
function getAuthorAndTitle() {
return $this->getTitle() . ' by ' . $this->getAuthor();
}
}
writeln('BEGIN TESTING STRATEGY PATTERN');
writeln('');
$type = 'Caps';
$book = new Book($type, 'PHP for Cats','Zeev Suraski');
writeln($book->getAuthorAndTitle());
$type = 'Exclaim';
$book = new Book($type, 'PHP for Unicorns','Rasmus Lerdorf');
writeln($book->getAuthorAndTitle());
$type = 'Stars';
$book = new Book($type, 'PHP for Ponys','Andi Gutmans');
writeln($book->getAuthorAndTitle());
function writeln($line_in) {
echo $line_in.PHP_EOL;
}
Update:
So if you are using an ORM we can assume that Book is your model class. I don't have any knowledge about Eloquent and how it handles data binding etc. so I'll make it as simple as I can. So I assume you can use a constructor with the binded data from database.
Keep your StrategyContext and the actual strategy classes -where your biz logic will be coded- as a service and use dependency injection while finding out which strategy you will use. This way you can bind all your strategies depending on your type variable, into your Model object.
Updated version of Book class,
class Book {
private $author = "Zeev Suraski";
private $title = "PHP for Cats";
private $strategy;
private $type = 'Caps';
function __construct() {
$this->strategy = new StrategyContext($this->type); //Dependency injection here
}
function getAuthor() {
return $this->strategy->showAuthor($this->author);
}
function getTitle() {
return $this->strategy->showTitle($this->title);
}
function getAuthorAndTitle() {
return $this->getTitle() . ' by ' . $this->getAuthor();
}
function setType($type) {
$this->type = $type;
}
function setStrategy($type=null) {
if($type==null) {
$this->strategy = new StrategyContext($this->type); //Dependency injection here
} else {
$this->strategy = new StrategyContext($type); //Dependency injection here
$this->setType($type);
}
}
}
writeln('BEGIN TESTING STRATEGY PATTERN');
writeln('');
$book = new Book();
writeln($book->getAuthorAndTitle());
$type = 'Exclaim';
$book->setType($type);
$book->setStrategy();
writeln($book->getAuthorAndTitle());
$type = 'Stars';
$book->setStrategy($type);
writeln($book->getAuthorAndTitle());
function writeln($line_in) {
echo $line_in.PHP_EOL;
}
I would use PHP's switch statement for this. For example,
switch($obj->type) {
case 1:
// do something
break;
case 2:
// do something else
break;
default:
// default actions
break;
}
Here break is used to stop execution of the switch statement as a whole. Without the break, code execution could fall through to the next case. This is sometimes desirable behavior though. If you wanted cases 1 and 2 to have the same code run, you could leave case 1 empty and write all your code in case 2. That way when the case 1 condition is met, no code related to case 1 would be run, but without a break statement, code execution would continue into case 2 before reaching the break statement in case 2.

Static context for some often needed Data? Best Practise?

I have written some Web Framework in PHP. I was been advised to do nothing in static Context. But i have some Question about this.
Imagine the following Class:
class Image extends HtmlControl {
public $src;
public $alt;
function getDetailPath()
{
return 'Common/Image';
}
}
It is nothing special. It is a Class to render an Image in Html. My Base Class has current following Implementation:
abstract class HtmlControl {
private $template;
abstract function getDetailPath();
public function __construct(ViewInformation $viewInformation) {
$this->template = 'foo/bar/' . $viewInformation->getEndpoint() . '/' . $this->getDetailPath() . '.php';
}
public function render() {
$output = '';
//Load template end fill $output
return $output;
}
}
Also nothing Special. It basicly will resolve the Endpoint Type (something like Frontend or Backend) to the corresponding template file, and provide the method render to get the output.
The Problem is, i need everytime for each part of a html controll to give the $viewInformation parameter.
$img = new Image($this->_info);
In my opinion something like this would be much nicer:
$img = new Image();
So i would have to save the State, which Endpoint should be used, in a static Context. Something like this (Note the Request::getEndpoint() Part):
abstract class HtmlControl {
private $template;
abstract function getDetailPath();
public function render() {
$template = 'foo/bar/' . Request::getEndpoint() . '/' . $this->getDetailPath() . '.php';
$output = '';
//Load template end fill $output
return $output;
}
}
My Question: Is it in this case okay, to have the endpoint in a static context? If not, could my current implementation improved?

Return reference to static variable from __callStatic?

I'm trying to find a workaround for static variables not being copied over to extending classes (which doesn't play nicely with late static binding), here is what I thought might work, but gives me a "PHP Fatal error: Can't use function return value in write context" :
<?php
class Person
{
protected static $tlsb_names = ['name'];
protected static $tlsb_vars = [];
public static function & __callStatic($method,$args)
{
echo "call static " . $method . " on " . get_called_class() . "\n";
if(in_array($method,static::$tlsb_names))
{
if(!array_key_exists(get_called_class(),static::$tlsb_vars))
{
static::$tlsb_vars[get_called_class()] = [];
}
if(!array_key_exists($method, static::$tlsb_vars[get_called_class()]))
{
echo "set var $method for " . get_called_class() . "\n";
static::$tlsb_vars[get_called_class()] = null;
}
return static::$tlsb_vars[get_called_class()][$method];
}
}
public static function show_name()
{
static::name() . "\n";
}
public static function call_me_al()
{
static::name() = "Al";
}
public static function call_me_joe()
{
static::name() = "Joe";
}
}
class Al extends Person{}
class Joe extends Person{}
Al::call_me_al();
Joe::call_me_joe();
Al::show_name();
Joe::show_name();
The problematic part is with the lines :
public static function call_me_al()
{
static::name() = "Al";
}
Apparently this is a compile-time error since non of my echo's are run.
What am I doing wrong here?
The following line of code is wrong:
public static function & __callStatic($method,$args)
You need to match the definition of that __callStatic functionDocs and that is without return by reference:
public static function __callStatic($name, $arguments)
So what you try to achieve is not possible.
And the other problem you circle around with should be able to solve with late static binding (LSB)Docs.
Also keep in mind that Magic is hard to debug, so get your step-debugger ready and step through the application so you can better understand what is actually happen. The debugger in PHP is called Xdebug, most PHP IDEs and editors support it.

Categories