├── .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 | --------------------------------------------------------------------------------