├── AbstractFactoryWithReflection ├── config.php ├── User.php ├── Article.php ├── MySQLUser.php ├── SQLiteUser.php ├── MySQLArticle.php ├── SQLiteArticle.php ├── index.php └── Factory.php ├── AbstractFactoryWithSimpleFactory ├── config.php ├── User.php ├── Article.php ├── MySQLUser.php ├── SQLiteUser.php ├── MySQLArticle.php ├── SQLiteArticle.php ├── index.php └── Factory.php ├── vendor ├── autoload.php └── composer │ ├── autoload_classmap.php │ ├── autoload_namespaces.php │ ├── autoload_psr4.php │ ├── autoload_static.php │ ├── LICENSE │ ├── autoload_real.php │ └── ClassLoader.php ├── Proxy ├── Subject.php ├── RealSubject.php ├── index.php └── Proxy.php ├── Observer ├── Observer.php ├── Subject.php ├── SMSObserver.php ├── EmailObserver.php ├── index.php └── SubjectAbstract.php ├── Bridge ├── Color.php ├── Red.php ├── Green.php ├── Yellow.php ├── Circle.php ├── Square.php ├── Triangle.php ├── Graph.php └── index.php ├── Command ├── CommandInterface.php ├── Receiver.php ├── Invoker.php ├── index.php └── Command.php ├── Facade ├── Encrypt.php ├── File.php ├── index.php └── Facade.php ├── FactoryMethod ├── Factory.php ├── Add.php ├── AddFactory.php ├── DivFactory.php ├── MulFactory.php ├── SubFactory.php ├── Mul.php ├── Sub.php ├── Div.php ├── Operation.php └── index.php ├── Template ├── Huawei.php ├── Xiaomi.php ├── index.php └── Phone.php ├── SafeComposite ├── File.php ├── Component.php ├── Dir.php └── index.php ├── SimpleFactory ├── Add.php ├── Mul.php ├── Sub.php ├── Div.php ├── Factory.php ├── Operation.php ├── Bad.php └── index.php ├── Decorator ├── Food.php ├── Decorator.php ├── Kaolengmian.php ├── Shouzhuabing.php ├── Egg.php ├── Latiao.php ├── Sausage.php └── index.php ├── Flyweight ├── ConcreteFlyweight.php ├── UnsharedConcreteFlyweight.php ├── Flyweight.php ├── FlyweightFactory.php └── index.php ├── Prototype ├── Car.php ├── ShallowDrive.php ├── DeepDrive.php └── index.php ├── composer.json ├── Iterator ├── IteratorInterface.php ├── ContainerInterface.php ├── index.php ├── NameContainer.php └── NameIterator.php ├── ClassAdapter ├── Target.php ├── Adaptee.php ├── Adapter.php └── index.php ├── AbstractFactory ├── User.php ├── Article.php ├── Factory.php ├── MySQLUser.php ├── SQLiteUser.php ├── MySQLArticle.php ├── SQLiteArticle.php ├── MySQLFactory.php ├── SQLiteFactory.php └── index.php ├── ObjectAdapter ├── Adaptee.php ├── Target.php ├── index.php └── Adapter.php ├── TransparentComposite ├── File.php ├── Component.php ├── Dir.php └── index.php ├── singleton └── index.php ├── readme.md └── index.html /AbstractFactoryWithReflection/config.php: -------------------------------------------------------------------------------- 1 | 'SQLite' 5 | ]; -------------------------------------------------------------------------------- /AbstractFactoryWithSimpleFactory/config.php: -------------------------------------------------------------------------------- 1 | 'SQLite' 5 | ]; -------------------------------------------------------------------------------- /vendor/autoload.php: -------------------------------------------------------------------------------- 1 | array($baseDir . '/'), 10 | ); 11 | -------------------------------------------------------------------------------- /Observer/Observer.php: -------------------------------------------------------------------------------- 1 | '; 15 | $this->notify(); 16 | } 17 | } -------------------------------------------------------------------------------- /Bridge/Red.php: -------------------------------------------------------------------------------- 1 | '; 18 | } 19 | } -------------------------------------------------------------------------------- /Bridge/Yellow.php: -------------------------------------------------------------------------------- 1 | '; 18 | } 19 | } -------------------------------------------------------------------------------- /FactoryMethod/Factory.php: -------------------------------------------------------------------------------- 1 | color->run()} 的圆形"; 19 | } 20 | } -------------------------------------------------------------------------------- /Bridge/Square.php: -------------------------------------------------------------------------------- 1 | color->run()} 的正方形"; 19 | } 20 | } -------------------------------------------------------------------------------- /Bridge/Triangle.php: -------------------------------------------------------------------------------- 1 | color->run()} 的三角形"; 19 | } 20 | } -------------------------------------------------------------------------------- /Template/Huawei.php: -------------------------------------------------------------------------------- 1 | '; 20 | } 21 | } -------------------------------------------------------------------------------- /Template/Xiaomi.php: -------------------------------------------------------------------------------- 1 | '; 20 | } 21 | } -------------------------------------------------------------------------------- /SafeComposite/File.php: -------------------------------------------------------------------------------- 1 | name .'
'; 19 | } 20 | } -------------------------------------------------------------------------------- /FactoryMethod/Add.php: -------------------------------------------------------------------------------- 1 | numberA + $this->numberB; 21 | } 22 | } -------------------------------------------------------------------------------- /FactoryMethod/AddFactory.php: -------------------------------------------------------------------------------- 1 | numberA + $this->numberB; 21 | } 22 | } -------------------------------------------------------------------------------- /FactoryMethod/Mul.php: -------------------------------------------------------------------------------- 1 | numberA * $this->numberB; 21 | } 22 | } -------------------------------------------------------------------------------- /FactoryMethod/Sub.php: -------------------------------------------------------------------------------- 1 | numberA - $this->numberB; 21 | } 22 | } -------------------------------------------------------------------------------- /SimpleFactory/Mul.php: -------------------------------------------------------------------------------- 1 | numberA * $this->numberB; 21 | } 22 | } -------------------------------------------------------------------------------- /SimpleFactory/Sub.php: -------------------------------------------------------------------------------- 1 | numberA - $this->numberB; 21 | } 22 | } -------------------------------------------------------------------------------- /Decorator/Food.php: -------------------------------------------------------------------------------- 1 | name . $content . '
'; 20 | } 21 | } -------------------------------------------------------------------------------- /Prototype/Car.php: -------------------------------------------------------------------------------- 1 | name = $name; 26 | } 27 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "baijunyao/design-patterns", 3 | "description": "design patterns", 4 | "type": "project", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "baijunyao", 9 | "email": "baijunyao@baijunyao.com" 10 | } 11 | ], 12 | "require": {}, 13 | "autoload": { 14 | "psr-4": { 15 | "Baijunyao\\DesignPatterns\\": "" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Iterator/IteratorInterface.php: -------------------------------------------------------------------------------- 1 | money; 26 | } 27 | } -------------------------------------------------------------------------------- /ObjectAdapter/Adaptee.php: -------------------------------------------------------------------------------- 1 | money; 26 | } 27 | } -------------------------------------------------------------------------------- /ObjectAdapter/Target.php: -------------------------------------------------------------------------------- 1 | action(); 22 | } 23 | } 24 | 25 | $client = new Client(); 26 | $client->run(); -------------------------------------------------------------------------------- /Facade/index.php: -------------------------------------------------------------------------------- 1 | encryptContent(); 22 | } 23 | } 24 | 25 | $client = new Client(); 26 | $client->run(); -------------------------------------------------------------------------------- /AbstractFactory/Article.php: -------------------------------------------------------------------------------- 1 | food = $food; 25 | } 26 | } -------------------------------------------------------------------------------- /AbstractFactoryWithSimpleFactory/Article.php: -------------------------------------------------------------------------------- 1 | money = '$5'; 19 | } 20 | 21 | /** 22 | * 通知 23 | */ 24 | public function notify() 25 | { 26 | echo '通知'; 27 | } 28 | } -------------------------------------------------------------------------------- /FactoryMethod/Div.php: -------------------------------------------------------------------------------- 1 | numberB == 0) { 21 | throw new \InvalidArgumentException('除数不能为0'); 22 | } 23 | return $this->numberA / $this->numberB; 24 | } 25 | } -------------------------------------------------------------------------------- /SimpleFactory/Div.php: -------------------------------------------------------------------------------- 1 | numberB == 0) { 21 | throw new \InvalidArgumentException('除数不能为0'); 22 | } 23 | return $this->numberA / $this->numberB; 24 | } 25 | } -------------------------------------------------------------------------------- /AbstractFactory/MySQLUser.php: -------------------------------------------------------------------------------- 1 | action(); 22 | 23 | echo '
'; 24 | 25 | $huawei = new Huawei(); 26 | $huawei->action(); 27 | } 28 | } 29 | 30 | $client = new Client(); 31 | $client->run(); -------------------------------------------------------------------------------- /AbstractFactoryWithReflection/MySQLUser.php: -------------------------------------------------------------------------------- 1 | food->name() . '+蛋'; 21 | } 22 | 23 | /** 24 | * 价格 25 | * 26 | * @return int|mixed 27 | */ 28 | public function price() 29 | { 30 | return $this->food->price() + 1; 31 | } 32 | } -------------------------------------------------------------------------------- /AbstractFactoryWithSimpleFactory/MySQLUser.php: -------------------------------------------------------------------------------- 1 | food->name() . '+辣条'; 21 | } 22 | 23 | /** 24 | * 价格 25 | * 26 | * @return int|mixed 27 | */ 28 | public function price() 29 | { 30 | return $this->food->price() + 3; 31 | } 32 | } -------------------------------------------------------------------------------- /AbstractFactoryWithReflection/MySQLArticle.php: -------------------------------------------------------------------------------- 1 | food->name() . '+肠'; 21 | } 22 | 23 | /** 24 | * 价格 25 | * 26 | * @return int|mixed 27 | */ 28 | public function price() 29 | { 30 | return $this->food->price() + 2; 31 | } 32 | } -------------------------------------------------------------------------------- /Bridge/Graph.php: -------------------------------------------------------------------------------- 1 | color = $color; 27 | } 28 | 29 | /** 30 | * @return mixed 31 | */ 32 | abstract public function draw(); 33 | } -------------------------------------------------------------------------------- /AbstractFactoryWithSimpleFactory/MySQLArticle.php: -------------------------------------------------------------------------------- 1 | command = $command; 23 | } 24 | 25 | /** 26 | * 执行 27 | */ 28 | public function run() 29 | { 30 | $this->command->execute(); 31 | } 32 | } -------------------------------------------------------------------------------- /Flyweight/UnsharedConcreteFlyweight.php: -------------------------------------------------------------------------------- 1 | name . $content . '
'; 20 | } 21 | 22 | /** 23 | * 附加的删除方法 24 | */ 25 | public function delete() 26 | { 27 | $this->name = ''; 28 | } 29 | } -------------------------------------------------------------------------------- /SafeComposite/Component.php: -------------------------------------------------------------------------------- 1 | name = $name; 25 | } 26 | 27 | /** 28 | * @return mixed 29 | */ 30 | abstract public function display(); 31 | } -------------------------------------------------------------------------------- /Flyweight/Flyweight.php: -------------------------------------------------------------------------------- 1 | name = $name; 27 | } 28 | 29 | /** 30 | * @param $content 31 | */ 32 | public function show($content){} 33 | } 34 | 35 | -------------------------------------------------------------------------------- /TransparentComposite/File.php: -------------------------------------------------------------------------------- 1 | name .'
'; 28 | } 29 | } -------------------------------------------------------------------------------- /AbstractFactory/SQLiteArticle.php: -------------------------------------------------------------------------------- 1 | setCommand($command); 27 | $invoker->run(); 28 | } 29 | } 30 | 31 | $client = new Client(); 32 | $client->run(); -------------------------------------------------------------------------------- /Flyweight/FlyweightFactory.php: -------------------------------------------------------------------------------- 1 | flyweights[$name])){ 27 | $this->flyweights[$name]=new ConcreteFlyweight($name); 28 | } 29 | return $this->flyweights[$name]; 30 | } 31 | } -------------------------------------------------------------------------------- /Observer/index.php: -------------------------------------------------------------------------------- 1 | attach($emailObserver); 25 | $subject->attach($SMSObserver); 26 | $subject->publish(); 27 | } 28 | } 29 | 30 | $client = new Client(); 31 | $client->run(); -------------------------------------------------------------------------------- /AbstractFactory/MySQLFactory.php: -------------------------------------------------------------------------------- 1 | car = $car; 30 | } 31 | 32 | public function show() 33 | { 34 | echo '开始驾驶'.$this->car->name; 35 | echo '
'; 36 | } 37 | } -------------------------------------------------------------------------------- /ClassAdapter/index.php: -------------------------------------------------------------------------------- 1 | pay(); 23 | echo '
'; 24 | 25 | // 适配器 26 | $adapter = new Adapter(); 27 | $adapter->pay(); 28 | echo '
'; 29 | 30 | $adapter->notify(); 31 | } 32 | } 33 | 34 | $client = new Client(); 35 | $client->run(); -------------------------------------------------------------------------------- /Proxy/Proxy.php: -------------------------------------------------------------------------------- 1 | realSubject = new RealSubject(); 27 | } 28 | 29 | /* 30 | * 执行操作 31 | */ 32 | public function action() 33 | { 34 | $this->realSubject->action(); 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /AbstractFactoryWithReflection/SQLiteArticle.php: -------------------------------------------------------------------------------- 1 | pay(); 23 | echo '
'; 24 | 25 | // 适配器 26 | $adapter = new Adapter($adaptee); 27 | $adapter->pay(); 28 | echo '
'; 29 | 30 | $adapter->notify(); 31 | } 32 | } 33 | 34 | $client = new Client(); 35 | $client->run(); -------------------------------------------------------------------------------- /AbstractFactoryWithSimpleFactory/SQLiteArticle.php: -------------------------------------------------------------------------------- 1 | observers[] = $observer; 23 | } 24 | 25 | /** 26 | * 通知 27 | */ 28 | public function notify() 29 | { 30 | foreach ($this->observers as $k => $v) { 31 | $v->update(); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Command/Command.php: -------------------------------------------------------------------------------- 1 | receiver = $receiver; 25 | } 26 | 27 | /** 28 | * @return mixed|void 29 | */ 30 | public function execute() 31 | { 32 | $this->receiver->action(); 33 | } 34 | } -------------------------------------------------------------------------------- /Iterator/index.php: -------------------------------------------------------------------------------- 1 | add('张三'); 22 | $nameContainer->add('李四'); 23 | $nameContainer->add('王麻子'); 24 | 25 | $nameIterator = $nameContainer->getIterator(); 26 | 27 | while ($nameIterator->hasNext()) { 28 | echo $nameIterator->next(); 29 | } 30 | } 31 | } 32 | 33 | $client = new Client(); 34 | $client->run(); -------------------------------------------------------------------------------- /Prototype/DeepDrive.php: -------------------------------------------------------------------------------- 1 | car = $car; 30 | } 31 | 32 | public function show() 33 | { 34 | echo '开始驾驶'.$this->car->name; 35 | echo '
'; 36 | } 37 | 38 | public function __clone() 39 | { 40 | $this->car = clone $this->car; 41 | } 42 | } -------------------------------------------------------------------------------- /Iterator/NameContainer.php: -------------------------------------------------------------------------------- 1 | nameArray[] = $name; 27 | } 28 | 29 | /** 30 | * 获取迭代器 31 | * 32 | * @return \Baijunyao\DesignPatterns\Iterator\NameIterator|mixed 33 | */ 34 | public function getIterator() 35 | { 36 | return new NameIterator($this->nameArray); 37 | } 38 | } -------------------------------------------------------------------------------- /TransparentComposite/Component.php: -------------------------------------------------------------------------------- 1 | name = $name; 25 | } 26 | 27 | /** 28 | * 添加子节点 29 | * 30 | * @return mixed 31 | */ 32 | abstract public function add(); 33 | 34 | /** 35 | * 展示名称 36 | * 37 | * @return mixed 38 | */ 39 | abstract public function display(); 40 | } -------------------------------------------------------------------------------- /Template/Phone.php: -------------------------------------------------------------------------------- 1 | powerOn(); 18 | $this->showLogo(); 19 | $this->callUp(); 20 | } 21 | 22 | /** 23 | * 开机 24 | */ 25 | protected function powerOn() 26 | { 27 | echo '开机' . '
'; 28 | } 29 | 30 | /** 31 | * logo 32 | * 33 | * @return mixed 34 | */ 35 | abstract protected function showLogo(); 36 | 37 | /** 38 | * 打电话 39 | */ 40 | protected function callUp() 41 | { 42 | echo '打电话' . '
'; 43 | } 44 | } -------------------------------------------------------------------------------- /Facade/Facade.php: -------------------------------------------------------------------------------- 1 | file = new File(); 28 | $this->encrypt = new Encrypt(); 29 | } 30 | 31 | /** 32 | * 获取文件内容并加密 33 | */ 34 | public function encryptContent() 35 | { 36 | echo $this->file->content(); 37 | echo '
'; 38 | echo $this->encrypt->encrypt(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ObjectAdapter/Adapter.php: -------------------------------------------------------------------------------- 1 | adaptee = $adaptee; 22 | $adaptee->money = '$5'; 23 | } 24 | 25 | /** 26 | * 支付 27 | * 28 | * @return mixed|void 29 | */ 30 | public function pay() 31 | { 32 | $this->adaptee->pay(); 33 | } 34 | 35 | /** 36 | * 通知 37 | * 38 | * @return mixed|void 39 | */ 40 | public function notify() 41 | { 42 | echo '通知'; 43 | } 44 | } -------------------------------------------------------------------------------- /SafeComposite/Dir.php: -------------------------------------------------------------------------------- 1 | children[] = $component; 26 | } 27 | 28 | /** 29 | * @return mixed|string 30 | */ 31 | public function display() 32 | { 33 | $nameStr = $this->name .'
'; 34 | foreach ($this->children as $k => $v) { 35 | 36 | $nameStr .= '--' . $v->display(); 37 | } 38 | return $nameStr; 39 | } 40 | } -------------------------------------------------------------------------------- /AbstractFactoryWithReflection/index.php: -------------------------------------------------------------------------------- 1 | createUser(); 24 | $user->insert(); 25 | echo '
'; 26 | $user->select(); 27 | 28 | echo '
'; 29 | 30 | // 创建 article 31 | $article = $factory->createArticle(); 32 | $article->insert(); 33 | echo '
'; 34 | $article->select(); 35 | } 36 | } 37 | 38 | $client = new Client(); 39 | $client->run(); -------------------------------------------------------------------------------- /TransparentComposite/Dir.php: -------------------------------------------------------------------------------- 1 | children[] = $component; 26 | } 27 | 28 | /** 29 | * @return mixed|string 30 | */ 31 | public function display() 32 | { 33 | $nameStr = $this->name .'
'; 34 | foreach ($this->children as $k => $v) { 35 | 36 | $nameStr .= '--' . $v->display(); 37 | } 38 | return $nameStr; 39 | } 40 | } -------------------------------------------------------------------------------- /AbstractFactoryWithSimpleFactory/index.php: -------------------------------------------------------------------------------- 1 | createUser(); 24 | $user->insert(); 25 | echo '
'; 26 | $user->select(); 27 | 28 | echo '
'; 29 | 30 | // 创建 article 31 | $article = $factory->createArticle(); 32 | $article->insert(); 33 | echo '
'; 34 | $article->select(); 35 | } 36 | } 37 | 38 | $client = new Client(); 39 | $client->run(); -------------------------------------------------------------------------------- /SimpleFactory/Factory.php: -------------------------------------------------------------------------------- 1 | numberA = $number; 42 | } 43 | 44 | /** 45 | * 给 numberB 赋值 46 | * 47 | * @param $number 48 | */ 49 | public function setNumberB($number) 50 | { 51 | $this->numberB = $number; 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /SimpleFactory/Operation.php: -------------------------------------------------------------------------------- 1 | numberA = $number; 42 | } 43 | 44 | /** 45 | * 给 numberB 赋值 46 | * 47 | * @param $number 48 | */ 49 | public function setNumberB($number) 50 | { 51 | $this->numberB = $number; 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /vendor/composer/autoload_static.php: -------------------------------------------------------------------------------- 1 | 11 | array ( 12 | 'Baijunyao\\DesignPatterns\\' => 25, 13 | ), 14 | ); 15 | 16 | public static $prefixDirsPsr4 = array ( 17 | 'Baijunyao\\DesignPatterns\\' => 18 | array ( 19 | 0 => __DIR__ . '/../..' . '/', 20 | ), 21 | ); 22 | 23 | public static function getInitializer(ClassLoader $loader) 24 | { 25 | return \Closure::bind(function () use ($loader) { 26 | $loader->prefixLengthsPsr4 = ComposerStaticInit88798c90f3cb8871fa59cc0f15b5142f::$prefixLengthsPsr4; 27 | $loader->prefixDirsPsr4 = ComposerStaticInit88798c90f3cb8871fa59cc0f15b5142f::$prefixDirsPsr4; 28 | 29 | }, null, ClassLoader::class); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Flyweight/index.php: -------------------------------------------------------------------------------- 1 | getFlyweight('170cm的模特'); 22 | $zhangsan1->show('第1件L号的衣服'); 23 | 24 | $zhangsan2 = $flyweight->getFlyweight('170cm的模特'); 25 | $zhangsan2->show('第99件L号的衣服'); 26 | 27 | var_dump($zhangsan1 === $zhangsan2); 28 | echo '
'; 29 | 30 | $lisi = $flyweight->getFlyweight('180cm的模特'); 31 | $lisi->show('第1件XXL号的衣服'); 32 | 33 | $wangmazi = new UnsharedConcreteFlyweight('190cm的模特'); 34 | $wangmazi->show('第1件XXXL号的衣服'); 35 | $wangmazi->delete(); 36 | $wangmazi->show('第1件XXXL号的衣服'); 37 | } 38 | } 39 | 40 | $client = new Client(); 41 | $client->run(); -------------------------------------------------------------------------------- /Iterator/NameIterator.php: -------------------------------------------------------------------------------- 1 | nameArray = $nameArray; 30 | } 31 | 32 | /** 33 | * 判断是否还有下一个姓名 34 | * 35 | * @return bool|mixed 36 | */ 37 | public function hasNext() 38 | { 39 | return $this->index < count($this->nameArray); 40 | } 41 | 42 | /** 43 | * 下一个姓名 44 | * 45 | * @return mixed|void 46 | */ 47 | public function next() 48 | { 49 | if ($this->hasNext()) { 50 | echo $this->nameArray[$this->index] . '
'; 51 | $this->index++; 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /vendor/composer/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) Nils Adermann, Jordi Boggiano 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is furnished 9 | to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /SimpleFactory/Bad.php: -------------------------------------------------------------------------------- 1 | add($classAdapter); 27 | $designPatterns->add($objectAdapter); 28 | $designPatterns->add($safeComposite); 29 | 30 | $componentFile = new File('Component.php'); 31 | $dirFile = new File('Dir.php'); 32 | $fileFile = new File('File.php'); 33 | $indexFile = new File('index.php'); 34 | 35 | $safeComposite->add($componentFile); 36 | $safeComposite->add($dirFile); 37 | $safeComposite->add($fileFile); 38 | $safeComposite->add($indexFile); 39 | 40 | echo $designPatterns->display(); 41 | } 42 | } 43 | 44 | $client = new Client(); 45 | $client->run(); 46 | -------------------------------------------------------------------------------- /FactoryMethod/index.php: -------------------------------------------------------------------------------- 1 | setNumberA(1); 23 | $operation->setNumberB(2); 24 | $result = $operation->getResult(); 25 | echo $result; 26 | 27 | echo '
'; 28 | 29 | // 计算 3+4 30 | $operation = new Add(); 31 | $operation->setNumberA(3); 32 | $operation->setNumberB(4); 33 | $result = $operation->getResult(); 34 | echo $result; 35 | } 36 | 37 | /** 38 | * 好的示例 new 产品对应的工厂 39 | */ 40 | public function good() 41 | { 42 | $factory = new AddFactory(); 43 | $operation = $factory->create(); 44 | $operation->setNumberA(1); 45 | $operation->setNumberB(2); 46 | $result = $operation->getResult(); 47 | echo $result; 48 | } 49 | } 50 | 51 | 52 | $client = new Client(); 53 | $client->bad(); 54 | echo '
'; 55 | $client->good(); -------------------------------------------------------------------------------- /Decorator/index.php: -------------------------------------------------------------------------------- 1 | name(); 23 | echo $shouzhuabing->price() . '元'; 24 | echo '
'; 25 | 26 | // 烤冷面 27 | $kaolengmian = new Kaolengmian(); 28 | echo $kaolengmian->name(); 29 | echo $kaolengmian->price() . '元'; 30 | echo '
'; 31 | 32 | // 手抓饼+蛋 33 | $egg = new Egg($shouzhuabing); 34 | echo $egg->name(); 35 | echo $egg->price() . '元'; 36 | echo '
'; 37 | 38 | // 手抓饼+肠 39 | $sausage = new Sausage($kaolengmian); 40 | echo $sausage->name(); 41 | echo $sausage->price() . '元'; 42 | echo '
'; 43 | 44 | // 烤冷面+辣条 45 | $latiao = new Latiao($shouzhuabing); 46 | echo $latiao->name(); 47 | echo $latiao->price() . '元'; 48 | echo '
'; 49 | } 50 | } 51 | 52 | $client = new Client(); 53 | $client->run(); 54 | -------------------------------------------------------------------------------- /TransparentComposite/index.php: -------------------------------------------------------------------------------- 1 | add($classAdapter); 27 | $designPatterns->add($objectAdapter); 28 | $designPatterns->add($transparentComposite); 29 | 30 | $componentFile = new File('Component.php'); 31 | $dirFile = new File('Dir.php'); 32 | $fileFile = new File('File.php'); 33 | $indexFile = new File('index.php'); 34 | 35 | $transparentComposite->add($componentFile); 36 | $transparentComposite->add($dirFile); 37 | $transparentComposite->add($fileFile); 38 | $transparentComposite->add($indexFile); 39 | 40 | echo $designPatterns->display(); 41 | } 42 | } 43 | 44 | $client = new Client(); 45 | $client->run(); 46 | -------------------------------------------------------------------------------- /AbstractFactory/index.php: -------------------------------------------------------------------------------- 1 | createUser(); 24 | $user->insert(); 25 | echo '
'; 26 | $user->select(); 27 | 28 | echo '
'; 29 | 30 | $factory = new MySQLFactory(); 31 | // 创建 article 32 | $article = $factory->createArticle(); 33 | $article->insert(); 34 | echo '
'; 35 | $article->select(); 36 | 37 | echo '

'; 38 | 39 | // 使用 SQLite 40 | $factory = new SQLiteFactory(); 41 | // 创建 user 42 | $user = $factory->createUser(); 43 | $user->insert(); 44 | echo '
'; 45 | $user->select(); 46 | 47 | echo '
'; 48 | 49 | $factory = new SQLiteFactory(); 50 | // 创建 article 51 | $article = $factory->createArticle(); 52 | $article->insert(); 53 | echo '
'; 54 | $article->select(); 55 | } 56 | } 57 | 58 | $client = new Client(); 59 | $client->run(); -------------------------------------------------------------------------------- /Prototype/index.php: -------------------------------------------------------------------------------- 1 | name = '特斯拉'; 22 | 23 | $shallowDrive = new ShallowDrive(); 24 | $shallowDrive->setCar($car); 25 | $shallowDrive->show(); 26 | 27 | $cloneDrive = clone $shallowDrive; 28 | $cloneDrive->show(); 29 | 30 | echo '
'; 31 | 32 | $car->name = '凯迪拉克'; 33 | $shallowDrive->show(); 34 | $cloneDrive->show(); 35 | } 36 | 37 | /** 38 | * 39 | */ 40 | public function deepCopy() 41 | { 42 | $car = new Car(); 43 | $car->name = '特斯拉'; 44 | 45 | $deepDrive = new DeepDrive(); 46 | $deepDrive->setCar($car); 47 | $deepDrive->show(); 48 | 49 | $cloneDrive = clone $deepDrive; 50 | $cloneDrive->show(); 51 | 52 | echo '
'; 53 | 54 | $car->name = '凯迪拉克'; 55 | $deepDrive->show(); 56 | $cloneDrive->show(); 57 | } 58 | } 59 | 60 | $client = new Client(); 61 | $client->shallowCopy(); 62 | echo '
-----------------------------
'; 63 | $client->deepCopy(); -------------------------------------------------------------------------------- /SimpleFactory/index.php: -------------------------------------------------------------------------------- 1 | getResult(1, '+', 2); 22 | echo $result; 23 | } 24 | 25 | /** 26 | * 不好的示例2 27 | * 28 | * @return int 29 | */ 30 | public function bad2() 31 | { 32 | // 计算 1+2 33 | $operation = new Add(); 34 | $operation->setNumberA(1); 35 | $operation->setNumberB(2); 36 | $result = $operation->getResult(); 37 | echo $result; 38 | 39 | echo '
'; 40 | 41 | // 计算 3+4 42 | $operation = new Add(); 43 | $operation->setNumberA(3); 44 | $operation->setNumberB(4); 45 | $result = $operation->getResult(); 46 | echo $result; 47 | } 48 | 49 | /** 50 | * 好的示例 51 | */ 52 | public function good() 53 | { 54 | $factory = new Factory(); 55 | $operation = $factory->create('+'); 56 | $operation->setNumberA(1); 57 | $operation->setNumberB(2); 58 | $result = $operation->getResult(); 59 | echo $result; 60 | } 61 | } 62 | 63 | 64 | $client = new Client(); 65 | $client->bad(); 66 | echo '
'; 67 | $client->bad2(); 68 | echo '
'; 69 | $client->good(); -------------------------------------------------------------------------------- /AbstractFactoryWithSimpleFactory/Factory.php: -------------------------------------------------------------------------------- 1 | db = $config['driver']; 19 | } 20 | 21 | /** 22 | * 创建 User 产品 23 | * 24 | * @return MySQLUser|SQLiteUser 25 | */ 26 | public function createUser() 27 | { 28 | switch ($this->db) { 29 | case 'MySQL': 30 | $user = new MySQLUser(); 31 | break; 32 | case 'SQLite': 33 | $user = new SQLiteUser(); 34 | break; 35 | default: 36 | throw new \InvalidArgumentException('暂不支持的数据库类型'); 37 | } 38 | return $user; 39 | } 40 | 41 | /** 42 | * 创建 Article 产品 43 | * 44 | * @return MySQLArticle|SQLiteArticle 45 | */ 46 | public function createArticle() 47 | { 48 | switch ($this->db) { 49 | case 'MySQL': 50 | $article = new MySQLArticle(); 51 | break; 52 | case 'SQLite': 53 | $article = new SQLiteArticle(); 54 | break; 55 | default: 56 | throw new \InvalidArgumentException('暂不支持的数据库类型'); 57 | } 58 | return $article; 59 | } 60 | } -------------------------------------------------------------------------------- /Bridge/index.php: -------------------------------------------------------------------------------- 1 | draw(); 27 | echo '
'; 28 | 29 | // 黄色的正方形 30 | $yellowSquare = new Square($yellow); 31 | $yellowSquare->draw(); 32 | echo '
'; 33 | 34 | // 绿色的正方形 35 | $greenSquare = new Square($green); 36 | $greenSquare->draw(); 37 | echo '
'; 38 | 39 | 40 | // 红色的三角形 41 | $redTriangle = new Triangle($red); 42 | $redTriangle->draw(); 43 | echo '
'; 44 | 45 | // 黄色的三角形 46 | $yellowTriangle = new Triangle($yellow); 47 | $yellowTriangle->draw(); 48 | echo '
'; 49 | 50 | // 绿色的三角形 51 | $greenTriangle = new Triangle($green); 52 | $greenTriangle->draw(); 53 | echo '
'; 54 | 55 | 56 | // 红色的圆形 57 | $redCircle = new Circle($red); 58 | $redCircle->draw(); 59 | echo '
'; 60 | 61 | // 黄色的圆形 62 | $yellowCircle = new Circle($yellow); 63 | $yellowCircle->draw(); 64 | echo '
'; 65 | 66 | // 绿色的圆形 67 | $greenCircle = new Circle($green); 68 | $greenCircle->draw(); 69 | echo '
'; 70 | 71 | } 72 | } 73 | 74 | $client = new Client(); 75 | $client->run(); -------------------------------------------------------------------------------- /AbstractFactoryWithReflection/Factory.php: -------------------------------------------------------------------------------- 1 | db = $config['driver']; 34 | } 35 | 36 | /** 37 | * 创建 User 产品 38 | * 39 | * @return MySQLUser|SQLiteUser 40 | */ 41 | public function createUser() 42 | { 43 | $className = $this->namespace . $this->db . 'User'; 44 | try { 45 | $class = new ReflectionClass($className); 46 | $user = $class->newInstance(); 47 | } catch (ReflectionException $Exception) { 48 | throw new \InvalidArgumentException('暂不支持的数据库类型'); 49 | } 50 | return $user; 51 | } 52 | 53 | /** 54 | * 创建 Article 产品 55 | * 56 | * @return MySQLArticle|SQLiteArticle 57 | */ 58 | public function createArticle() 59 | { 60 | $className = $this->namespace . $this->db . 'Article'; 61 | try { 62 | $class = new ReflectionClass($className); 63 | $article = $class->newInstance(); 64 | } catch (ReflectionException $Exception) { 65 | throw new \InvalidArgumentException('暂不支持的数据库类型'); 66 | } 67 | return $article; 68 | } 69 | } -------------------------------------------------------------------------------- /vendor/composer/autoload_real.php: -------------------------------------------------------------------------------- 1 | = 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); 27 | if ($useStaticLoader) { 28 | require_once __DIR__ . '/autoload_static.php'; 29 | 30 | call_user_func(\Composer\Autoload\ComposerStaticInit88798c90f3cb8871fa59cc0f15b5142f::getInitializer($loader)); 31 | } else { 32 | $map = require __DIR__ . '/autoload_namespaces.php'; 33 | foreach ($map as $namespace => $path) { 34 | $loader->set($namespace, $path); 35 | } 36 | 37 | $map = require __DIR__ . '/autoload_psr4.php'; 38 | foreach ($map as $namespace => $path) { 39 | $loader->setPsr4($namespace, $path); 40 | } 41 | 42 | $classMap = require __DIR__ . '/autoload_classmap.php'; 43 | if ($classMap) { 44 | $loader->addClassMap($classMap); 45 | } 46 | } 47 | 48 | $loader->register(true); 49 | 50 | return $loader; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /singleton/index.php: -------------------------------------------------------------------------------- 1 | '; 45 | var_dump($db2); 46 | echo '
'; 47 | var_dump($db3); 48 | echo '
'; 49 | var_dump($db4); 50 | echo '
'; 51 | var_dump($db5); 52 | echo '
'; 53 | 54 | 55 | /** 56 | * 单例 57 | * 58 | * Class Db2 59 | * @package Baijunyao\DesignPatterns\Singleton 60 | */ 61 | class Db2 62 | { 63 | private static $instance = null; 64 | 65 | public static function getInstance() 66 | { 67 | if (null === static::$instance) { 68 | static::$instance = new static(); 69 | } 70 | 71 | return static::$instance; 72 | } 73 | 74 | /** 75 | * 防止使用 new 创建多个实例 76 | * 77 | * Db2 constructor. 78 | */ 79 | private function __construct() 80 | { 81 | } 82 | 83 | /** 84 | * 防止 clone 多个实例 85 | */ 86 | private function __clone() 87 | { 88 | } 89 | 90 | /** 91 | * 防止反序列化 92 | */ 93 | private function __wakeup() 94 | { 95 | } 96 | } 97 | 98 | $db6 = Db2::getInstance(); 99 | $db7 = Db2::getInstance(); 100 | 101 | var_dump($db6); 102 | echo '
'; 103 | var_dump($db7); 104 | echo '
'; -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ### 文章 2 | 1. [php设计模式(一)序言](https://baijunyao.com/article/158) 3 | 2. [php设计模式(二)单例模式](https://baijunyao.com/article/159) 4 | 3. [php设计模式(三)简单工厂模式](https://baijunyao.com/article/161) 5 | 4. [php设计模式(四)工厂方法模式](https://baijunyao.com/article/162) 6 | 5. [php设计模式(五)抽象工厂模式](https://baijunyao.com/article/164) 7 | 6. [php设计模式(六)使用简单工厂来优化抽象工厂模式](https://baijunyao.com/article/165) 8 | 7. [php设计模式(七)使用反射来优化抽象工厂模式](https://baijunyao.com/article/166) 9 | 8. [php设计模式(八)原型模式](https://baijunyao.com/article/167) 10 | 9. [php设计模式(九)类适配器模式](https://baijunyao.com/article/168) 11 | 10. [php设计模式(十)对象适配器模式](https://baijunyao.com/article/169) 12 | 11. [php设计模式(十一)桥接模式](https://baijunyao.com/article/170) 13 | 12. [php设计模式(十二)装饰模式](https://baijunyao.com/article/172) 14 | 13. [php设计模式(十三)透明组合模式](https://baijunyao.com/article/174) 15 | 14. [php设计模式(十四)安全组合模式](https://baijunyao.com/article/175) 16 | 15. [php设计模式(十五)外观模式](https://baijunyao.com/article/176) 17 | 16. [php设计模式(十六)享元模式](https://baijunyao.com/article/177) 18 | 17. [php设计模式(十七)代理模式](https://baijunyao.com/article/178) 19 | 18. [php设计模式(十八)模板方法模式](https://baijunyao.com/article/179) 20 | 19. [php设计模式(十九)命令模式](https://baijunyao.com/article/182) 21 | 20. [php设计模式(二十)迭代器模式](https://baijunyao.com/article/183) 22 | 21. [php设计模式(二十一)观察者模式](https://baijunyao.com/article/184) 23 | 24 | ### 目录 25 | - [单例模式](https://github.com/baijunyao/design-patterns/tree/master/singleton) 26 | - [简单工厂模式](https://github.com/baijunyao/design-patterns/tree/master/SimpleFactory) 27 | - [工厂方法模式](https://github.com/baijunyao/design-patterns/tree/master/FactoryMethod) 28 | - [抽象工厂模式](https://github.com/baijunyao/design-patterns/tree/master/AbstractFactory) 29 | - [使用简单工厂来优化抽象工厂模式](https://github.com/baijunyao/design-patterns/tree/master/AbstractFactoryWithSimpleFactory) 30 | - [使用反射来优化抽象工厂模式](https://github.com/baijunyao/design-patterns/tree/master/AbstractFactoryWithReflection) 31 | - [原型模式](https://github.com/baijunyao/design-patterns/tree/master/Prototype) 32 | - [类适配器模式](https://github.com/baijunyao/design-patterns/tree/master/ClassAdapter) 33 | - [对象适配器模式](https://github.com/baijunyao/design-patterns/tree/master/ObjectAdapter) 34 | - [桥接模式](https://github.com/baijunyao/design-patterns/tree/master/Bridge) 35 | - [装饰模式](https://github.com/baijunyao/design-patterns/tree/master/Decorator) 36 | - [透明组合模式](https://github.com/baijunyao/design-patterns/tree/master/TransparentComposite) 37 | - [安全组合模式](https://github.com/baijunyao/design-patterns/tree/master/SafeComposite) 38 | - [外观模式](https://github.com/baijunyao/design-patterns/tree/master/Facade) 39 | - [享元模式](https://github.com/baijunyao/design-patterns/tree/master/Flyweight) 40 | - [代理模式](https://github.com/baijunyao/design-patterns/tree/master/Proxy) 41 | - [模板方法模式](https://github.com/baijunyao/design-patterns/tree/master/Template) 42 | - [命令模式](https://github.com/baijunyao/design-patterns/tree/master/Command) 43 | - [迭代器模式](https://github.com/baijunyao/design-patterns/tree/master/Iterator) 44 | - [观察者模式](https://github.com/baijunyao/design-patterns/tree/master/Observer) 45 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 设计模式-白俊遥 6 | 7 | 8 |

文章

9 |
    10 |
  1. php设计模式(一)序言
  2. 11 |
  3. php设计模式(二)单例模式
  4. 12 |
  5. php设计模式(三)简单工厂模式
  6. 13 |
  7. php设计模式(四)工厂方法模式
  8. 14 |
  9. php设计模式(五)抽象工厂模式
  10. 15 |
  11. php设计模式(六)使用简单工厂来优化抽象工厂模式
  12. 16 |
  13. php设计模式(七)使用反射来优化抽象工厂模式
  14. 17 |
  15. php设计模式(八)原型模式
  16. 18 |
  17. php设计模式(九)类适配器模式
  18. 19 |
  19. php设计模式(十)对象适配器模式
  20. 20 |
  21. php设计模式(十一)桥接模式
  22. 21 |
  23. php设计模式(十二)装饰模式
  24. 22 |
  25. php设计模式(十三)透明组合模式
  26. 23 |
  27. php设计模式(十四)安全组合模式
  28. 24 |
  29. php设计模式(十五)外观模式
  30. 25 |
  31. php设计模式(十六)享元模式
  32. 26 |
  33. php设计模式(十七)代理模式
  34. 27 |
  35. php设计模式(十八)代理模式
  36. 28 |
  37. php设计模式(十九)命令模式
  38. 29 |
  39. php设计模式(二十)迭代器模式
  40. 30 |
  41. php设计模式(二十一)观察者模式
  42. 31 |
32 |

目录

33 | 55 | 56 | -------------------------------------------------------------------------------- /vendor/composer/ClassLoader.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Autoload; 14 | 15 | /** 16 | * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. 17 | * 18 | * $loader = new \Composer\Autoload\ClassLoader(); 19 | * 20 | * // register classes with namespaces 21 | * $loader->add('Symfony\Component', __DIR__.'/component'); 22 | * $loader->add('Symfony', __DIR__.'/framework'); 23 | * 24 | * // activate the autoloader 25 | * $loader->register(); 26 | * 27 | * // to enable searching the include path (eg. for PEAR packages) 28 | * $loader->setUseIncludePath(true); 29 | * 30 | * In this example, if you try to use a class in the Symfony\Component 31 | * namespace or one of its children (Symfony\Component\Console for instance), 32 | * the autoloader will first look for the class under the component/ 33 | * directory, and it will then fallback to the framework/ directory if not 34 | * found before giving up. 35 | * 36 | * This class is loosely based on the Symfony UniversalClassLoader. 37 | * 38 | * @author Fabien Potencier 39 | * @author Jordi Boggiano 40 | * @see http://www.php-fig.org/psr/psr-0/ 41 | * @see http://www.php-fig.org/psr/psr-4/ 42 | */ 43 | class ClassLoader 44 | { 45 | // PSR-4 46 | private $prefixLengthsPsr4 = array(); 47 | private $prefixDirsPsr4 = array(); 48 | private $fallbackDirsPsr4 = array(); 49 | 50 | // PSR-0 51 | private $prefixesPsr0 = array(); 52 | private $fallbackDirsPsr0 = array(); 53 | 54 | private $useIncludePath = false; 55 | private $classMap = array(); 56 | private $classMapAuthoritative = false; 57 | private $missingClasses = array(); 58 | private $apcuPrefix; 59 | 60 | public function getPrefixes() 61 | { 62 | if (!empty($this->prefixesPsr0)) { 63 | return call_user_func_array('array_merge', $this->prefixesPsr0); 64 | } 65 | 66 | return array(); 67 | } 68 | 69 | public function getPrefixesPsr4() 70 | { 71 | return $this->prefixDirsPsr4; 72 | } 73 | 74 | public function getFallbackDirs() 75 | { 76 | return $this->fallbackDirsPsr0; 77 | } 78 | 79 | public function getFallbackDirsPsr4() 80 | { 81 | return $this->fallbackDirsPsr4; 82 | } 83 | 84 | public function getClassMap() 85 | { 86 | return $this->classMap; 87 | } 88 | 89 | /** 90 | * @param array $classMap Class to filename map 91 | */ 92 | public function addClassMap(array $classMap) 93 | { 94 | if ($this->classMap) { 95 | $this->classMap = array_merge($this->classMap, $classMap); 96 | } else { 97 | $this->classMap = $classMap; 98 | } 99 | } 100 | 101 | /** 102 | * Registers a set of PSR-0 directories for a given prefix, either 103 | * appending or prepending to the ones previously set for this prefix. 104 | * 105 | * @param string $prefix The prefix 106 | * @param array|string $paths The PSR-0 root directories 107 | * @param bool $prepend Whether to prepend the directories 108 | */ 109 | public function add($prefix, $paths, $prepend = false) 110 | { 111 | if (!$prefix) { 112 | if ($prepend) { 113 | $this->fallbackDirsPsr0 = array_merge( 114 | (array) $paths, 115 | $this->fallbackDirsPsr0 116 | ); 117 | } else { 118 | $this->fallbackDirsPsr0 = array_merge( 119 | $this->fallbackDirsPsr0, 120 | (array) $paths 121 | ); 122 | } 123 | 124 | return; 125 | } 126 | 127 | $first = $prefix[0]; 128 | if (!isset($this->prefixesPsr0[$first][$prefix])) { 129 | $this->prefixesPsr0[$first][$prefix] = (array) $paths; 130 | 131 | return; 132 | } 133 | if ($prepend) { 134 | $this->prefixesPsr0[$first][$prefix] = array_merge( 135 | (array) $paths, 136 | $this->prefixesPsr0[$first][$prefix] 137 | ); 138 | } else { 139 | $this->prefixesPsr0[$first][$prefix] = array_merge( 140 | $this->prefixesPsr0[$first][$prefix], 141 | (array) $paths 142 | ); 143 | } 144 | } 145 | 146 | /** 147 | * Registers a set of PSR-4 directories for a given namespace, either 148 | * appending or prepending to the ones previously set for this namespace. 149 | * 150 | * @param string $prefix The prefix/namespace, with trailing '\\' 151 | * @param array|string $paths The PSR-4 base directories 152 | * @param bool $prepend Whether to prepend the directories 153 | * 154 | * @throws \InvalidArgumentException 155 | */ 156 | public function addPsr4($prefix, $paths, $prepend = false) 157 | { 158 | if (!$prefix) { 159 | // Register directories for the root namespace. 160 | if ($prepend) { 161 | $this->fallbackDirsPsr4 = array_merge( 162 | (array) $paths, 163 | $this->fallbackDirsPsr4 164 | ); 165 | } else { 166 | $this->fallbackDirsPsr4 = array_merge( 167 | $this->fallbackDirsPsr4, 168 | (array) $paths 169 | ); 170 | } 171 | } elseif (!isset($this->prefixDirsPsr4[$prefix])) { 172 | // Register directories for a new namespace. 173 | $length = strlen($prefix); 174 | if ('\\' !== $prefix[$length - 1]) { 175 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); 176 | } 177 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 178 | $this->prefixDirsPsr4[$prefix] = (array) $paths; 179 | } elseif ($prepend) { 180 | // Prepend directories for an already registered namespace. 181 | $this->prefixDirsPsr4[$prefix] = array_merge( 182 | (array) $paths, 183 | $this->prefixDirsPsr4[$prefix] 184 | ); 185 | } else { 186 | // Append directories for an already registered namespace. 187 | $this->prefixDirsPsr4[$prefix] = array_merge( 188 | $this->prefixDirsPsr4[$prefix], 189 | (array) $paths 190 | ); 191 | } 192 | } 193 | 194 | /** 195 | * Registers a set of PSR-0 directories for a given prefix, 196 | * replacing any others previously set for this prefix. 197 | * 198 | * @param string $prefix The prefix 199 | * @param array|string $paths The PSR-0 base directories 200 | */ 201 | public function set($prefix, $paths) 202 | { 203 | if (!$prefix) { 204 | $this->fallbackDirsPsr0 = (array) $paths; 205 | } else { 206 | $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; 207 | } 208 | } 209 | 210 | /** 211 | * Registers a set of PSR-4 directories for a given namespace, 212 | * replacing any others previously set for this namespace. 213 | * 214 | * @param string $prefix The prefix/namespace, with trailing '\\' 215 | * @param array|string $paths The PSR-4 base directories 216 | * 217 | * @throws \InvalidArgumentException 218 | */ 219 | public function setPsr4($prefix, $paths) 220 | { 221 | if (!$prefix) { 222 | $this->fallbackDirsPsr4 = (array) $paths; 223 | } else { 224 | $length = strlen($prefix); 225 | if ('\\' !== $prefix[$length - 1]) { 226 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); 227 | } 228 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 229 | $this->prefixDirsPsr4[$prefix] = (array) $paths; 230 | } 231 | } 232 | 233 | /** 234 | * Turns on searching the include path for class files. 235 | * 236 | * @param bool $useIncludePath 237 | */ 238 | public function setUseIncludePath($useIncludePath) 239 | { 240 | $this->useIncludePath = $useIncludePath; 241 | } 242 | 243 | /** 244 | * Can be used to check if the autoloader uses the include path to check 245 | * for classes. 246 | * 247 | * @return bool 248 | */ 249 | public function getUseIncludePath() 250 | { 251 | return $this->useIncludePath; 252 | } 253 | 254 | /** 255 | * Turns off searching the prefix and fallback directories for classes 256 | * that have not been registered with the class map. 257 | * 258 | * @param bool $classMapAuthoritative 259 | */ 260 | public function setClassMapAuthoritative($classMapAuthoritative) 261 | { 262 | $this->classMapAuthoritative = $classMapAuthoritative; 263 | } 264 | 265 | /** 266 | * Should class lookup fail if not found in the current class map? 267 | * 268 | * @return bool 269 | */ 270 | public function isClassMapAuthoritative() 271 | { 272 | return $this->classMapAuthoritative; 273 | } 274 | 275 | /** 276 | * APCu prefix to use to cache found/not-found classes, if the extension is enabled. 277 | * 278 | * @param string|null $apcuPrefix 279 | */ 280 | public function setApcuPrefix($apcuPrefix) 281 | { 282 | $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; 283 | } 284 | 285 | /** 286 | * The APCu prefix in use, or null if APCu caching is not enabled. 287 | * 288 | * @return string|null 289 | */ 290 | public function getApcuPrefix() 291 | { 292 | return $this->apcuPrefix; 293 | } 294 | 295 | /** 296 | * Registers this instance as an autoloader. 297 | * 298 | * @param bool $prepend Whether to prepend the autoloader or not 299 | */ 300 | public function register($prepend = false) 301 | { 302 | spl_autoload_register(array($this, 'loadClass'), true, $prepend); 303 | } 304 | 305 | /** 306 | * Unregisters this instance as an autoloader. 307 | */ 308 | public function unregister() 309 | { 310 | spl_autoload_unregister(array($this, 'loadClass')); 311 | } 312 | 313 | /** 314 | * Loads the given class or interface. 315 | * 316 | * @param string $class The name of the class 317 | * @return bool|null True if loaded, null otherwise 318 | */ 319 | public function loadClass($class) 320 | { 321 | if ($file = $this->findFile($class)) { 322 | includeFile($file); 323 | 324 | return true; 325 | } 326 | } 327 | 328 | /** 329 | * Finds the path to the file where the class is defined. 330 | * 331 | * @param string $class The name of the class 332 | * 333 | * @return string|false The path if found, false otherwise 334 | */ 335 | public function findFile($class) 336 | { 337 | // class map lookup 338 | if (isset($this->classMap[$class])) { 339 | return $this->classMap[$class]; 340 | } 341 | if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { 342 | return false; 343 | } 344 | if (null !== $this->apcuPrefix) { 345 | $file = apcu_fetch($this->apcuPrefix.$class, $hit); 346 | if ($hit) { 347 | return $file; 348 | } 349 | } 350 | 351 | $file = $this->findFileWithExtension($class, '.php'); 352 | 353 | // Search for Hack files if we are running on HHVM 354 | if (false === $file && defined('HHVM_VERSION')) { 355 | $file = $this->findFileWithExtension($class, '.hh'); 356 | } 357 | 358 | if (null !== $this->apcuPrefix) { 359 | apcu_add($this->apcuPrefix.$class, $file); 360 | } 361 | 362 | if (false === $file) { 363 | // Remember that this class does not exist. 364 | $this->missingClasses[$class] = true; 365 | } 366 | 367 | return $file; 368 | } 369 | 370 | private function findFileWithExtension($class, $ext) 371 | { 372 | // PSR-4 lookup 373 | $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; 374 | 375 | $first = $class[0]; 376 | if (isset($this->prefixLengthsPsr4[$first])) { 377 | $subPath = $class; 378 | while (false !== $lastPos = strrpos($subPath, '\\')) { 379 | $subPath = substr($subPath, 0, $lastPos); 380 | $search = $subPath.'\\'; 381 | if (isset($this->prefixDirsPsr4[$search])) { 382 | $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); 383 | foreach ($this->prefixDirsPsr4[$search] as $dir) { 384 | if (file_exists($file = $dir . $pathEnd)) { 385 | return $file; 386 | } 387 | } 388 | } 389 | } 390 | } 391 | 392 | // PSR-4 fallback dirs 393 | foreach ($this->fallbackDirsPsr4 as $dir) { 394 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { 395 | return $file; 396 | } 397 | } 398 | 399 | // PSR-0 lookup 400 | if (false !== $pos = strrpos($class, '\\')) { 401 | // namespaced class name 402 | $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) 403 | . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); 404 | } else { 405 | // PEAR-like class name 406 | $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; 407 | } 408 | 409 | if (isset($this->prefixesPsr0[$first])) { 410 | foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { 411 | if (0 === strpos($class, $prefix)) { 412 | foreach ($dirs as $dir) { 413 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 414 | return $file; 415 | } 416 | } 417 | } 418 | } 419 | } 420 | 421 | // PSR-0 fallback dirs 422 | foreach ($this->fallbackDirsPsr0 as $dir) { 423 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 424 | return $file; 425 | } 426 | } 427 | 428 | // PSR-0 include paths. 429 | if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { 430 | return $file; 431 | } 432 | 433 | return false; 434 | } 435 | } 436 | 437 | /** 438 | * Scope isolated include. 439 | * 440 | * Prevents access to $this/self from included files. 441 | */ 442 | function includeFile($file) 443 | { 444 | include $file; 445 | } 446 | --------------------------------------------------------------------------------