├── .gitignore
├── Adapter
└── Adapter.php
├── Decorator
└── Decorator.php
├── DependencyInjection
└── DependencyInjection.php
├── Facade
└── Facade.php
├── Factory
├── AbstractFactory.php
├── FactoryMethod.php
└── SimpleFactory.php
├── Iterator
└── Iterator.php
├── Observer
└── Observer.php
├── Proxy
└── Proxy.php
├── README.md
├── Singleton
└── Singleton.php
└── Strategy
└── Strategy.php
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/Adapter/Adapter.php:
--------------------------------------------------------------------------------
1 | connection = new mysqli($host, $username, $password, $dbname);
19 | }
20 |
21 | public function query($sql)
22 | {
23 | $this->result = $this->connection->query($sql);
24 |
25 | return $this;
26 | }
27 |
28 | public function result()
29 | {
30 | if (gettype($this->result) === 'boolean') {
31 | return $this->result;
32 | } elseif ($this->result->num_rows > 0) {
33 | $result = [];
34 |
35 | while ($row = $this->result->fetch_assoc()) {
36 | $result[] = $row;
37 | }
38 |
39 | return $result;
40 | } else {
41 | return [];
42 | }
43 | }
44 | }
45 |
46 | class PDOAdapter implements AdapterInterface
47 | {
48 | protected $connection;
49 |
50 | protected $result;
51 |
52 | public function __construct($host, $username, $password, $dbname)
53 | {
54 | $this->connection = new PDO("mysql:host=$host;dbname=$dbname", $username, $password);
55 | }
56 |
57 | public function query($sql)
58 | {
59 | $query = $this->connection->prepare($sql);
60 | $exec = $query->execute();
61 |
62 | if ($query->columnCount() == 0) {
63 | $this->result = $exec;
64 | } else {
65 | $this->result = $query;
66 | }
67 |
68 | return $this;
69 | }
70 |
71 | public function result()
72 | {
73 | if (gettype($this->result) === 'boolean') {
74 | return $this->result;
75 | } else {
76 | $data = [];
77 |
78 | while ($row = $this->result->fetch(PDO::FETCH_ASSOC)) {
79 | $data[] = $row;
80 | }
81 |
82 | return $data;
83 | }
84 | }
85 | }
86 |
87 | class Database
88 | {
89 | protected $adapter;
90 |
91 | public function __construct(AdapterInterface $adapter)
92 | {
93 | $this->adapter = $adapter;
94 | }
95 |
96 | public function query($sql)
97 | {
98 | return $this->adapter->query($sql);
99 | }
100 |
101 | public function result()
102 | {
103 | return $this->adapter->result();
104 | }
105 | }
106 |
107 | $mysql = new MySQLAdapter('localhost', 'root', '1234', 'demo');
108 | $db = new Database($mysql);
109 |
110 | $query = $db->query("SELECT * FROM users");
111 | $result = $query->result();
112 | var_dump($result);
113 |
--------------------------------------------------------------------------------
/Decorator/Decorator.php:
--------------------------------------------------------------------------------
1 | email = $email;
23 | }
24 |
25 | abstract public function body();
26 | }
27 |
28 | class NewYearEmailDecorator extends EmailDecorator
29 | {
30 | public function body()
31 | {
32 | return $this->email->body() . ' Additional text from deocorator.';
33 | }
34 | }
35 |
36 | // Simple Email
37 | $email = new Email();
38 | var_dump($email->body());
39 |
40 | // Decorated Email
41 | $emailNewYearDecorator = new NewYearEmailDecorator($email);
42 | var_dump($emailNewYearDecorator->body());
43 |
--------------------------------------------------------------------------------
/DependencyInjection/DependencyInjection.php:
--------------------------------------------------------------------------------
1 | adapter = $adapter;
10 | }
11 | }
12 |
13 | class MysqlAdapter
14 | {
15 |
16 | }
17 |
18 | class Database2
19 | {
20 | protected $adapter;
21 |
22 | public function setterMethod(MySqlAdapter $adapter)
23 | {
24 | $this->adapter = $adapter;
25 | }
26 | }
27 |
28 | class Database3
29 | {
30 | protected $adapter;
31 |
32 | public function __construct(AdapterInterface $adapter)
33 | {
34 | $this->adapter = $adapter;
35 | }
36 | }
37 |
38 | interface AdapterInterface
39 | {
40 |
41 | }
42 |
43 | class MysqlAdapter2 implements AdapterInterface
44 | {
45 |
46 | }
47 |
48 | /** Usage **/
49 | // Contructor Injection
50 | $mysqlAdapter = new MysqlAdapter;
51 | $database = new Database($mysqlAdapter);
52 |
53 | // Setter Method Injection
54 | $mysqlAdapter = new MysqlAdapter;
55 | $database = new Database();
56 | $database->setterMethod($mysqlAdapter);
57 |
58 | // Interface Injection
59 | $mysqlAdapter = new MysqlAdapter2;
60 | $database = new Database($mysqlAdapter);
61 |
--------------------------------------------------------------------------------
/Facade/Facade.php:
--------------------------------------------------------------------------------
1 | cart = new Cart;
55 | $this->order = new Order;
56 | $this->payment = new Payment;
57 | $this->shipping = new Shipping;
58 | }
59 |
60 | public function addToCart($products)
61 | {
62 | $this->cart->addProducts($products);
63 | }
64 |
65 | public function checkout()
66 | {
67 | $products = $this->cart->getProducts();
68 |
69 | $this->totalAmount = $this->order->process($products);
70 | }
71 |
72 | public function makePayment()
73 | {
74 | $charge = $this->shipping->calculateCharge();
75 | $this->payment->charge($charge);
76 |
77 | $isCompleted = $this->payment->makePayment();
78 |
79 | if ($isCompleted) {
80 | $this->shipping->shipProducts();
81 | }
82 | }
83 | }
84 |
85 | $customer = new CustomerFacade;
86 |
87 | $products = [
88 | [
89 | 'name' => 'Polo T-Shirt',
90 | 'price' => 40,
91 | ],
92 | [
93 | 'name' => 'Smart Watch',
94 | 'price' => 400,
95 | ],
96 | ];
97 |
98 | $customer->addToCart($products);
99 | $customer->checkout();
100 | $customer->makePayment();
101 |
--------------------------------------------------------------------------------
/Factory/AbstractFactory.php:
--------------------------------------------------------------------------------
1 | makeCar();
131 | echo $car->design() . '
';
132 | echo $car->assemble() . '
';
133 | echo $car->paint() . '
';
134 |
135 | echo '
';
136 |
137 | $bike = $bangladeshiFactoryInstance->makeBike();
138 | echo $bike->design() . '
';
139 | echo $bike->assemble() . '
';
140 | echo $bike->paint() . '
';
141 |
142 | echo '
';
143 |
144 | $usaFactoryInstance = new USAFactory;
145 | $car = $usaFactoryInstance->makeCar();
146 | echo $car->design() . '
';
147 | echo $car->assemble() . '
';
148 | echo $car->paint() . '
';
149 |
150 | echo '
';
151 |
152 | $bike = $usaFactoryInstance->makeBike();
153 | echo $bike->design() . '
';
154 | echo $bike->assemble() . '
';
155 | echo $bike->paint() . '
';
156 |
--------------------------------------------------------------------------------
/Factory/FactoryMethod.php:
--------------------------------------------------------------------------------
1 | make('mercedes');
143 | echo $mercedes->design() . '
';
144 | echo $mercedes->assemble() . '
';
145 | echo $mercedes->paint() . '
';
146 |
147 | echo '
';
148 |
149 | $toyota = $carFactoryInstance->make('toyota');
150 | echo $toyota->design() . '
';
151 | echo $toyota->assemble() . '
';
152 | echo $toyota->paint() . '
';
153 |
154 | echo '
';
155 |
156 | $bikeFactoryInstance = new BikeFactory;
157 |
158 | $yamaha = $bikeFactoryInstance->make('yamaha');
159 | echo $yamaha->design() . '
';
160 | echo $yamaha->assemble() . '
';
161 | echo $yamaha->paint() . '
';
162 |
163 | echo '
';
164 |
165 | $ducati = $bikeFactoryInstance->make('ducati');
166 | echo $ducati->design() . '
';
167 | echo $ducati->assemble() . '
';
168 | echo $ducati->paint() . '
';
169 |
--------------------------------------------------------------------------------
/Factory/SimpleFactory.php:
--------------------------------------------------------------------------------
1 | brands = [
14 | 'mercedes' => 'MercedesCar',
15 | 'toyota' => 'ToyotaCar',
16 | ];
17 | }
18 |
19 | public function make($brand)
20 | {
21 | if (!array_key_exists($brand, $this->brands)) {
22 | return new Exception('Not available this car');
23 | }
24 |
25 | $className = $this->brands[$brand];
26 |
27 | return new $className();
28 | }
29 | }
30 |
31 | interface CarInterface
32 | {
33 | public function design();
34 | public function assemble();
35 | public function paint();
36 | }
37 |
38 | class MercedesCar implements CarInterface
39 | {
40 | public function design()
41 | {
42 | return 'Designing Mercedes Car';
43 | }
44 |
45 | public function assemble()
46 | {
47 | return 'Assembling Mercedes Car';
48 | }
49 |
50 | public function paint()
51 | {
52 | return 'Painting Mercedes Car';
53 | }
54 | }
55 |
56 | class ToyotaCar implements CarInterface
57 | {
58 | public function design()
59 | {
60 | return 'Designing Toyota Car';
61 | }
62 |
63 | public function assemble()
64 | {
65 | return 'Assembling Toyota Car';
66 | }
67 |
68 | public function paint()
69 | {
70 | return 'Painting Toyota Car';
71 | }
72 | }
73 |
74 | $carFactory = new CarFactory;
75 |
76 | $mercedes = $carFactory->make('mercedes');
77 | echo $mercedes->design() . '
';
78 | echo $mercedes->assemble() . '
';
79 | echo $mercedes->paint() . '
';
80 |
81 | echo '
';
82 |
83 | $toyota = $carFactory->make('toyota');
84 | echo $toyota->design() . '
';
85 | echo $toyota->assemble() . '
';
86 | echo $toyota->paint() . '
';
87 |
--------------------------------------------------------------------------------
/Iterator/Iterator.php:
--------------------------------------------------------------------------------
1 | title = $title;
10 | }
11 |
12 | public function getTitle()
13 | {
14 | return $this->title;
15 | }
16 | }
17 |
18 | class BookList implements Iterator, Countable
19 | {
20 | private $books = [];
21 |
22 | private $currentIndex = 0;
23 |
24 | public function current()
25 | {
26 | return $this->books[$this->currentIndex];
27 | }
28 |
29 | public function key()
30 | {
31 | return $this->currentIndex;
32 | }
33 |
34 | public function next()
35 | {
36 | $this->currentIndex++;
37 | }
38 |
39 | public function rewind()
40 | {
41 | $this->currentIndex = 0;
42 | }
43 |
44 | public function valid()
45 | {
46 | return isset($this->books[$this->currentIndex]);
47 | }
48 |
49 | public function count()
50 | {
51 | return count($this->books);
52 | }
53 |
54 | public function addBook(Book $book)
55 | {
56 | $this->books[] = $book;
57 | }
58 |
59 | public function removeBook(Book $bookToRemove)
60 | {
61 | foreach ($this->books as $key => $book) {
62 | if ($book->getTitle() === $bookToRemove->getTitle()) {
63 | unset($this->books[$key]);
64 | }
65 | }
66 |
67 | $this->books = array_values($this->books);
68 | }
69 | }
70 |
71 | $bookList = new BookList();
72 | $bookList->addBook(new Book('Design Pattern'));
73 | $bookList->addBook(new Book('Head First Design Pattern'));
74 | $bookList->addBook(new Book('Clean Code'));
75 | $bookList->addBook(new Book('The Pragmatic Programmer'));
76 |
77 | $bookList->removeBook(new Book('Design Pattern'));
78 |
79 | foreach ($bookList as $book) {
80 | echo $book->getTitle() . PHP_EOL;
81 | }
82 |
--------------------------------------------------------------------------------
/Observer/Observer.php:
--------------------------------------------------------------------------------
1 | observers = new \SplObjectStorage();
10 |
11 | foreach ($this->setObservers() as $observer) {
12 | $this->attach($observer);
13 | }
14 | }
15 |
16 | public function attach(\SplObserver $observer)
17 | {
18 | $this->observers->attach($observer);
19 | }
20 |
21 | public function detach(\SplObserver $observer)
22 | {
23 | $this->observers->detach($observer);
24 | }
25 |
26 | public function notify()
27 | {
28 | foreach ($this->observers as $observer) {
29 | $observer->update($this);
30 | }
31 | }
32 |
33 | protected function setObservers()
34 | {
35 | return [];
36 | }
37 |
38 | public function __set($name, $value)
39 | {
40 | $this->data[$name] = $value;
41 | // notify the observers, that model has been updated
42 | $this->notify();
43 | }
44 | }
45 |
46 | class Post extends Model
47 | {
48 | protected function setObservers()
49 | {
50 | return [
51 | new PostModelObserver,
52 | new Observer2,
53 | ];
54 | }
55 | }
56 |
57 | class PostModelObserver implements \SplObserver
58 | {
59 | public function update(\SplSubject $subject)
60 | {
61 | echo get_class($subject) . ' has been updated' . '
';
62 | }
63 | }
64 |
65 | class Observer2 implements \SplObserver
66 | {
67 | public function update(\SplSubject $subject)
68 | {
69 | echo get_class($subject) . ' has been updated' . '
';
70 | }
71 | }
72 |
73 | $post1 = new Post();
74 | $post2 = new Post();
75 | $post3 = new Post();
76 |
77 | $post1->title = 'Hello World';
78 | $post2->title = 'Another Post Title';
79 | $post3->body = 'Lorem ipsum............';
80 |
--------------------------------------------------------------------------------
/Proxy/Proxy.php:
--------------------------------------------------------------------------------
1 | fileName = $fileName;
17 |
18 | $this->readFile();
19 | }
20 |
21 | private function readFile()
22 | {
23 | $this->fileContent = file_get_contents($this->fileName);
24 | }
25 |
26 | public function content()
27 | {
28 | return $this->fileContent;
29 | }
30 | }
31 |
32 | class ProxyFile implements FileInterface
33 | {
34 | private $fileName;
35 |
36 | private $realFileObject;
37 |
38 | public function __construct($fileName)
39 | {
40 | $this->fileName = $fileName;
41 | }
42 |
43 | public function content()
44 | {
45 | // Lazy load the file using the RealFile class
46 | if (!$this->realFileObject) {
47 | $this->realFileObject = new RealFile($this->fileName);
48 | }
49 |
50 | return $this->realFileObject->content();
51 | }
52 | }
53 |
54 | $realFile = new RealFile('/path/to/file.jpg');
55 | var_dump(memory_get_usage()); // ~5Mb
56 | $realFile->content();
57 | var_dump(memory_get_usage()); // ~5Mb
58 |
59 | $realFile->content();
60 | var_dump(memory_get_usage()); // ~5Mb
61 |
62 | $proxyFile = new ProxyFile('/path/to/file.jpg');
63 | var_dump(memory_get_usage()); // ~350Kb
64 | $proxyFile->content();
65 | var_dump(memory_get_usage()); // ~5Mb
66 |
67 | $proxyFile->content();
68 | var_dump(memory_get_usage()); // ~5Mb
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PHP Design Patterns
2 |
3 | ## Patterns
4 | - [x] Adapter
5 | - [x] DependencyInjection
6 | - [x] Facade
7 | - [x] Factory
8 | - [x] Observer
9 | - [x] Singleton
10 | - [x] Strategy
11 | - [x] Iterator
12 | - [x] Proxy
13 | - [x] Decorator
14 | - [ ] S.O.L.I.D Principle
15 | - [ ] CLEAN Architecture
16 |
--------------------------------------------------------------------------------
/Singleton/Singleton.php:
--------------------------------------------------------------------------------
1 | sayHi();
30 |
--------------------------------------------------------------------------------
/Strategy/Strategy.php:
--------------------------------------------------------------------------------
1 | traveler = $traveler;
39 | }
40 |
41 | public function travel()
42 | {
43 | $this->traveler->travel();
44 | }
45 | }
46 |
47 | $traveler = new Traveler(new BusTravelStrategy());
48 | $traveler->travel();
49 |
50 | $traveler1 = new Traveler(new PlaneTravelStrategy());
51 | $traveler1->travel();
52 |
--------------------------------------------------------------------------------