Giter Site home page Giter Site logo

designpatternsphp / designpatternsphp Goto Github PK

View Code? Open in Web Editor NEW
21.7K 1.2K 4.5K 6.04 MB

Sample code for several design patterns in PHP 8.x

License: MIT License

PHP 85.27% Makefile 6.26% Python 7.97% Dockerfile 0.50%
designpatternsphp php design-patterns design-pattern oop modern-php code-examples phpunit php8

designpatternsphp's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

designpatternsphp's Issues

Iterator bug

The following code doesn't produce the expected output :

<?php
require_once 'Book.php';
require_once 'BookList.php';
require_once 'BookListIterator.php';

use DesignPatterns\Behavioral\Iterator\Book;
use DesignPatterns\Behavioral\Iterator\BookList;
use DesignPatterns\Behavioral\Iterator\BookListIterator;

$list = new BookList();
$list->addBook(new Book('foo', 'bar'));
$list->addBook(new Book('a', '1'));
$list->addBook(new Book('b', '2'));
$list->addBook(new Book('c', '3'));
$list->addBook(new Book('d', '4'));

$list->removeBook(new Book('b', '2'));

$it = new BookListIterator($list);
foreach($it as $i => $b)
    echo $b->getAuthorAndTitle(), PHP_EOL;

The output is :

foo by bar
a by 1

When it should be :

foo by bar
a by 1
c by 3
d by 4

The reason why this happens is that after deleting the "b by 2" book, the internal array of BookList looks like this :

Array
(
    [0] => DesignPatterns\Behavioral\Iterator\Book Object
    (
        [author:DesignPatterns\Behavioral\Iterator\Book:private] => bar
        [title:DesignPatterns\Behavioral\Iterator\Book:private] => foo
    )

    [1] => DesignPatterns\Behavioral\Iterator\Book Object
    (
        [author:DesignPatterns\Behavioral\Iterator\Book:private] => 1
        [title:DesignPatterns\Behavioral\Iterator\Book:private] => a
    )

    [3] => DesignPatterns\Behavioral\Iterator\Book Object
    (
        [author:DesignPatterns\Behavioral\Iterator\Book:private] => 3
        [title:DesignPatterns\Behavioral\Iterator\Book:private] => c
    )

    [4] => DesignPatterns\Behavioral\Iterator\Book Object
    (
        [author:DesignPatterns\Behavioral\Iterator\Book:private] => 4
        [title:DesignPatterns\Behavioral\Iterator\Book:private] => d
    )

)

You'll notice that the index 2 is missing, which makes sense since removeBook calls unset() on that specific book. However, BookListIterator's next() method simply increments the internal index ($currentBook) and BookListIterator::valid() stops when BookList::getBook() returns null, which happens once BookListIterator::currentBook reaches 2, the book we just removed by calling $list->removeBook(new Book('b', '2')). Because of this, the iterator stops prematurely.

SimpleFactory or ConcreteFactory ?

The SimpleFactory pattern is referred both in the documentation and in the code, as both SimpleFactory and ConcreteFactory.

I would make a pull request but I actually don't know what is the correct name.

Singleton should be removed

As Singleton is considered as an Anti-Pattern, I thing that should be removed.
Instead of that, dependency Injection design is best alternative.

Create a coding standard for this documentation

This is a very good repository to explain Design Patterns in PHP but I think it would be better to have a coding standard for it.

Some examples:

Do not add non sens comments in docblocks like:

/**
 * Class MyClass  // this comment should not be here
 */
class MyClass
{
    // ...
}

Docblock for constants in classes should not contain @var. They are constants, not variables.

Is not necessary to add @abstract in docblock for a method declared abstract. It can be seen from method's declaration itself.

/**
 * @abstract // this should not be here.
 * @var int $idSomething
 */
abstract public function doSomething($idSomething);

Do not add empty docblock for classes or methods like in this class https://github.com/domnikl/DesignPatternsPHP/blob/master/Structural/Facade/Facade.php

The list can continue and I believe it could add a lot of improvements to the examples.

Suggestion: add searchable topics to project

Now that GitHub has introduced its topic feature to make projects more searchable; I think it would really help others like me who didn't know about this fantastic project, to add (at least) the following topics:

  • design patterns
  • design-pattern
  • oop
  • modern-php
  • code-examples
  • phpunit

These are just suggestions for you to take on board if you'd like...

Anyways thanks!

design patterns for real projects

hey dudes, some days ago I was reading codes from this repo I have an idea. Would be nice to have some libraries with abstract implementation of Design Patterns so I can use in real project!

What it means?
Something like PSRs and we could create a organization with some repositories to provide the way to implement one specific pattern

Look like, create a abstract structure to someone implement a Chain of Responsibility? You know...

isn't Service Locator known as anti-pattern?

isn't Service Locator formerly known as anti-pattern ?
Service Locator is an Anti-Pattern since it hides class' dependencies causing issues when you change dependencies, since they are not directly exposed out of the class.

What do you think @domnikl ? :)

Memento

What do you think about this proposal?

I reworked the implementation of the pattern so now it has practical usage within php (because on many sites this pattern have amorphous representation, divorced from reality).

update

UML Diagram of Adapter is not updated

Unsupported parameter for module: autoremove

Error when deploying vagrand.

==> default: Mounting NFS shared folders...
==> default: Running provisioner: ansible...
    default: Running ansible-playbook...

PLAY ***************************************************************************

TASK [setup] *******************************************************************
ok: [192.168.11.2]

TASK [server : Update apt] *****************************************************
ok: [192.168.11.2]

TASK [server : Install System Packages] ****************************************
changed: [192.168.11.2] => (item=[u'curl', u'wget', u'python-software-properties'])

TASK [server : Install Extra Packages] *****************************************
changed: [192.168.11.2] => (item=[u'vim', u'htop', u'iotop', u'bwm-ng', u'git'])

TASK [server : Configure the timezone] *****************************************
changed: [192.168.11.2]

TASK [server : More Configure the timezone] ************************************
changed: [192.168.11.2]

TASK [server : Set default system language pack] *******************************
changed: [192.168.11.2]

TASK [vagrant_local : Set the hostname in /etc/hostname] ***********************
changed: [192.168.11.2]

TASK [vagrant_local : Set the hostname] ****************************************
changed: [192.168.11.2]

TASK [vagrant_local : Update /etc/hosts] ***************************************
changed: [192.168.11.2]

TASK [php : Update apt] ********************************************************
fatal: [192.168.11.2]: FAILED! => {"changed": false, "failed": true, "msg": 
"unsupported parameter for module: autoremove"}

PLAY RECAP *********************************************************************
192.168.11.2               : ok=10   changed=8    unreachable=0    failed=1   

Ansible failed to complete successfully. Any error output should be
visible above. Please fix these errors and try again.

Explanation

I really appreciate this, and downloaded it so that I can learn it.

Could you improve this only slightly by giving an example explanation where I might use each pattern, in simplistic terms?

For instance, let's say I want to make a plugin architecture for a web app -- which design pattern would you use? Or let's say I want to confirm a login -- which design pattern? You don't have to give those exact examples, however.

Composite pattern, why use abstract FormElement?

Hi domnikl,

Awesome examples! Learning a lot, thanks.
I have a question, why does your composite pattern uses an abstract class in stead of an interface or trait?

Trait example:

trait RenderableTrait
{
   /**
     * renders the elements' code.
     *
     * @param int $indent
     *
     * @return mixed
     */
    abstract public function render($indent = 0);
}

Interface example

interface RenderableInterface
{
   /**
     * renders the elements' code.
     *
     * @param int $indent
     *
     * @return mixed
     */
    public function render($indent = 0);
}

Than you can decouple the From class from the FormElement and add the RenderableTrait or RederableInterface to the Form and FormElement class.

Forgive my possible ignorance, I'm still learning and trying to understand the why of programming decisions.

Adding examples

Even if most patterns are self-explaining we should provide usage examples. Any thoughts?

Class 'PHPUnit_Framework_TestCase' not found

php AbstractFactoryTest.php
PHP Fatal error: Class 'PHPUnit_Framework_TestCase' not found in /Users/shengbinxu/web/DesignPatternsPHP/Creational/AbstractFactory/Tests/AbstractFactoryTest.php on line 13

Fatal error: Class 'PHPUnit_Framework_TestCase' not found in /Users/shengbinxu/web/DesignPatternsPHP/Creational/AbstractFactory/Tests/AbstractFactoryTest.php on line 13

VehicleInterface don't found anywhere in the builder pattern

In the builder pattern in Vehicle.php I found line:
"VehicleInterface is a contract for a vehicle" - but don't see any Vehicle Interface anywhere. So the code is missing? what is wrong with this code? Thanks.
I feel a bit confused about it.

Repository knows about database columns

I have a thought about Repository pattern. It knows too much about the columns name, if I want to create a Storage for a database where created is a keyword, so the name of this column in this DB is created_at. It will break my Repository implementation. Or even so, if in DB 1 my date is in format YYYY-MM-DD and DB 2 my date is as MM-DD-YYYY, my Repository should not know how to transform the returned string from storage to a DateTime, because the String could vary. What you think?

Update
Illustration

Delegate Pattern

Please, implement a delegate pattern.
It's very simple and cool :)

Presenter Pattern

How do you feel about adding the Presenter Pattern to this repo? Its similar to the Decorator pattern, but has some key differences. Decorators add new functionality to class instances, whereas Presenters are closer to the view and work directly with the view layer and may contain the language of the view (html/css/etc..). It also contains the ui business logic for the View.

Example code:

class PresentableClass{
  use PresentableTrait;
  protected $presenter = 'ClassPresenter';
}

//Sample class presenter used for this test only
class ClassPresenter extends Presenter{
  public function userName(){
    if($this->email) return $this->email;   
    return "{$this->firstName} $this->lastName";
  }
}

//An example of a presenter trait
<?php namespace App\Presenters;
trait PresentableTrait {
    protected $presenterInstance;

    public function present()
    {
        // Check if the property has been declared on the model and
        // the class exists
        if (!$this->presenter or !class_exists($this->presenter)) {
            throw new Exception('Please set the Presenter path to your Presenter FQN');
        }

        // The good old Singleton pattern
        if (!$this->presenterInstance) {
            $this->presenterInstance = new $this->presenter($this);
        }
        return $this->presenterInstance;
    }
}

<?php
namespace App\Presenters;
abstract class Presenter
{
    protected $entity; // Store the original model instance
    function __construct($entity){
        $this->beforeConstruct();
        $this->entity = $entity;
        $this->afterConstruct();
    }

  // Call the function if exists, or return the property on the original model
    public function __get($property)
    {
        if (method_exists($this, $property)) {
            return $this->{$property}();
        }
        return $this->entity->{$property};
    }
    //optional
    public function beforeConstruct(){}
    public function afterConstruct(){}
}

Some references:
https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter
http://stackoverflow.com/questions/2056/what-are-mvp-and-mvc-and-what-is-the-difference
https://github.com/laracasts/Presenter

Thoughts as this might be closer to the singleton pattern (might be an anti-pattern)?

Version in other languages?

Hey! Whats'up?!

Is there some version of this repo in other language? I've forked this repo yesterday to translate to portuguese.


To contribute in translation, check Translation Rule/Hint below

[important] Before your start, re-fork this project or synchronize your repo with upstream!(because i just do some change)

Translation Rule/Hint

  1. All po files were generated by all README.rst, Only them (explication of patterns) will be translated, Code and comments should be in English and not change. code is always the core of this repo.
  2. Word for Word translation is not needed, you can add your own explication to make translation much easy to understand.
  3. if you didn't found the language you want to translate, take a look at here, and @shangguokan who will add initial files.
  4. You can use po editor or text editor to translate.
  5. It remain some markup in po files, please be careful not to break reST notation.

example: Russian translation is completed

#: ../../Creational/AbstractFactory/README.rst:22
msgid "You can also find these code on `GitHub`_"
msgstr "在 `GitHub`_ 上查看代码"   (`xxx`_ one underscore here)

#: ../../Creational/AbstractFactory/README.rst:24
msgid "AbstractFactory.php"
msgstr ""                         (do not need translate xxx.php, keep it empty)

PR

if you finished, make one pull request or by "Russian translation part one two..."(maxi five)
i will create project on read the doc and translation will be hosted at http://designpatternsphp.readthedocs.org/{language_slug}/latest/

Language

language(click to preview) translator
ca – Catalan @torrentalle
en – English @domnikl
es – Spanish @torrentalle @desarrolla2
pt_BR – Brazilian Portuguese @leleonam @bgsouza @davispeixoto
ru – Russian @KIVagant
zh_CN – Simplified Chinese @su-xiaolin @yplam

Title

It's possible to change english wikipedia link of title to the localized version.
three formats are possible:

//take care of the num of underscore

#: ../../Behavioral/ChainOfResponsibilities/README.rst:2
msgid "`Chain Of Responsibilities`__"

//1. only keep russian title, russian link on russian title
msgstr "`Цепочка обязанностей <https://ru.wikipedia.org/wiki/Цепочка_обязанностей>`_" 

or
//2. keep two version titles, russian link on russian title, english link on english title
msgstr "`Цепочка обязанностей <https://ru.wikipedia.org/wiki/Цепочка_обязанностей>`_ (`Chain Of Responsibilities`__)"

or
//3. keep two version titles, russian link on russian title, no english link
msgstr "`Цепочка обязанностей <https://ru.wikipedia.org/wiki/Цепочка_обязанностей>`_ (Chain Of Responsibilities)"

or
//4. if no russian wikipedia page,so english link on russian title
msgstr "`Цепочка обязанностей`__" 

// I think 1 and 3 are best way

FAQ

  1. How can i add some link or bold on the translation string?
    you can use reST markup.
    msgstr "External **hyperlinks**, like Python http://www.python.org/_."
  2. How can i test my translation?
    first, you don't need test your translations. if you want,
    the repo use Sphinx + reStructuredText
    a.install sphinx on your computer http://sphinx-doc.org/
    b.learn how translation works http://sphinx-doc.org/latest/intl.html
    c.Install sphinx-intl by pip install sphinx-intl or easy_install sphinx-intl.
    d.execute $ sphinx-intl build
    e.execute $ make -e SPHINXOPTS="-D language='pt_BR'" html
    f.you can find html in folder _build

Specification pattern issues

Hey guys,

What do you think about changing Specification pattern example? At the moment it has the following issues:

  1. Specification interface contains plus, either and notmethods which put on Specification object redundant responsibilities. Instead of checking if some certain condition is satisfied it is also responsible for creating new specifications. This is not a good approach and may create wrong impression on people who are not familiar with the pattern.
  2. AbstractSpecification class knows about its children. While sometimes it adds some convenience, in general, it is a bad design.
  3. Plus and Either specifications have an arity of two while they can operate on any number of specifications (in case we want to show them in the example).
  4. Plus refers to the mathematical operation of addition while specifications return boolean results and I would stick with the standard boolean logic operations. I suspect Plus and Eithernames were used because and and or are reserved words but we can call them AndSpecification, OrSpecification, and NotSpecification. These names look worse if we want our code to look more like a natural language but in this case, in my opinion, they increase readability. Because the name AndSpecification less likely will confuse somebody.

I propose to:

  1. Remove plus, either and not methods from the Specification interface
  2. Remove AbstractSpecification class (it is not needed)
  3. Rename Plus, Either and Not specifications to AndSpecification, OrSpecification and NotSpecification correspondingly
  4. Change the arity of AndSpecification and OrSpecification to any number of parameters

I didn't create a pull request because wanted to discuss this with you guys first. But I can prepare it this weekend if you agree with proposed changes.

MVC

Not enough MVC pattern.

add READMEs in every pattern's folder

The README files should all have a similar structure, so that they're easily readable and users find the important contents right away without much need for searching.

Invalid UML diagram for Creational/Pool?

It seems to me that the UML diagram for Creational/Pool a mistake because the source code is not contain Processor class and run method for Worked does not match.
Possibly previously used different source code for example?

phpunit There was 1 error: Argument 1 passed to AbstractFactoryTest::testComponentCreation() must be an instance of AbstractFactory, none given

hey, guys, please take a look, what happened this error:

wozzup@u1404:~/php/Creational/AbstractFactory$ phpunit Tests/AbstractFactoryTest.php
PHPUnit 3.7.28 by Sebastian Bergmann.

E

Time: 49 ms, Memory: 2.50Mb

There was 1 error:

1) Creational\AbstractFactory\Tests\AbstractFactoryTest::testComponentCreation
Argument 1 passed to Creational\AbstractFactory\Tests\AbstractFactoryTest::testComponentCreation() must be an instance of Creational\AbstractFactory\AbstractFactory, none given

/home/wozzup/php/Creational/AbstractFactory/Tests/AbstractFactoryTest.php:19

FAILURES!
Tests: 1, Assertions: 0, Errors: 1.

do i need to composer autoload "squizlabs/php_codesniffer": "1.5.*" to get phpunit work?

Russian documentation looks outdated

Hello to all.

I can help to translate some new patterns for RU locale: More/EAV and Structural/Flyweight
And, as I can imagine, EN documentation should be changed from Sep 8 2015 when I sent last PR with translation.

So, maybe some *.po files in RU locale is now outdated too. Can you check this?

UP: JFYI, here is broken UML image.

where is MVC and HMVC

hi
where is MVC and HMVC?
they are also good to be in this awesome work.
if you need this tel me i will write them and add to your code later
thanks.

Restructure the repository

What are you think to restructure this repository?

My proposal:

Create a directory structure with types of Design Patterns, like on my branch restructure:

|-- Creational
|   |-- Factory
|   |   |-- Tests
|   |-- ...
|-- Behavioral
|   |-- ...
|-- Structural
|   |-- ...

Composite pattern: Suggestion to add a note about nested forms in test

I have noticed the following in Structural/Composite/Tests/CompositeTest.php.

Even though the following test demonstrates the example for this pattern well, technically you cannot nest html forms, that I know of. https://www.w3.org/TR/html5/forms.html#the-form-element

public function testRender()
    {
        $form = new Composite\Form();
        $form->addElement(new Composite\TextElement('Email:'));
        $form->addElement(new Composite\InputElement());
        $embed = new Composite\Form();
        $embed->addElement(new Composite\TextElement('Password:'));
        $embed->addElement(new Composite\InputElement());
        $form->addElement($embed);
        $this->assertEquals(
            '<form>Email:<input type="text" /><form>Password:<input type="text" /></form></form>',
            $form->render()
        );
    }

Maybe there could be some notes added as part of the doc block for the test, or an inline comment - something along the lines of the following?

This is just an example, in a real world scenario you are not able to nest HTML forms.

I can create a PR, if this would be welcomed...

Anyways - this repository is awesome, thanks!!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.