一、课堂代码全部上机操作至少一遍以上
1、单例模式 demo1.php
代码
<?php
namespace _1205;
//use PDO;
// 单例模式
class Temp
{
//只是一个类,不需要成员,为了演示 ...
}
//获取第一个对象
$obj1 = new Temp();
//获取第二个对象
$obj2 = new Temp();
//查看两个都是从一个类实例化对象的类型
var_dump($obj1, $obj2);
echo '<br>';
//查看两个对象是否完全一样
var_dump($obj1 === $obj2);
echo '<hr>';
// 单例模式原理
class Demo1
{
// 构造方法私有化,禁止外部访问
//外部实例化该类时,首先调用构造函数
private function __construct()
{
}
// 目前 由于构造函数已经私有化,外部调用是非法的,所以只能在类中的内部将类实例化
// 当前类的实例 静态属性
public static $instance = null;
// 实例化当前类的方法 静态方法
public static function getInstance()
{
// 实例化当前类,并返回类实例/对象
// 判断当前类是否已经被实例化过了,如果没有的话就实例化,如果已实例化,就返回它
//is_null()这个函数用来判断变量值是否为null,如果是null,返回true否则false
if (is_null(self::$instance)) {
//在当前类中调用类属性,使用self,同时self也是类本身
//对类进行实例化new self(),然后返回类实例对象,保存在变量$instance当中
self::$instance = new self();
}
//如果已经实例化,返回类实例对象本身
return self::$instance;
}
// 禁用克隆魔术方法
private function __clone()
{
// ...
}
}
//new Demo1();
$obj1 = Demo1::getInstance();
$obj2 = Demo1::getInstance();
//查看两个实例对象是否完全相同
var_dump($obj1 === $obj2);
echo '<br>';
//查看两个对象的类型
var_dump($obj1, $obj2);
echo '<hr>';
结果
2、单例模式应用场景
代码
<?php
// 单例模型应用场景
class Db
{
// 构造方法私有化 禁止外部调用
//...$connectParams是可变参数...$connectParams===$dsn,$username,$password
private function __construct(...$connectParams)
{
//初始化变量
$dsn = $connectParams[0];
$username = $connectParams[1];
$password = $connectParams[2];
//连接数据库
self::$pdo = new \PDO($dsn, $username, $password);
}
// 目前 由于构造方法的私有化,所以只能在类中的内部将类实例化
// 当前类的实例 静态属性
public static $pdo = null;
// 实例化当前类的方法
public static function getInstance(...$connectParams)
{
// 实例化当前类,并返回类实例/对象
// 判断当前类是否已经被实例化过了,如果没有的话就实例化,如果已实例化,就返回它
if (is_null(self::$pdo)) {
// 构造函数不需要返回,这里需要特别注意
new self(...$connectParams);
}
//返回数据库连接
return self::$pdo;
}
// 禁用克隆魔术方法
private function __clone()
{
// ...
}
}
echo '<hr>';
//客户端调用
//配置数据库连接参数$dsn,$username,$password
$connectParams = ['mysql:host=localhost;dbname=mt', 'root', '111'];
//实例化同时,传入数据库连接参数,连接数据库
$pdo = Db::getInstance(...$connectParams);
//这里直接调用了query()方法,是为了简便演示进程,没有使用预处理过程,一般数据是从数据库中获取
//在这里直接打印输出
//PDO中的query和fetchAll方法
echo '<pre>' .print_r($pdo->query('SELECT * FROM `user`')->fetchAll(),true) .'</pre>';
结果
3、工厂模式 demo2.php
代码
<?php
namespace _1205;
// 工厂模式: 用于批量创建类的实例/对象
use mvc\Facade;
class Demo2
{
// ...
}
//如果需要很多类的对象,那就需要做大量重复的操作,
// file1.php
$obj = new Demo2();
// file2.php
$obj = new Demo2();
// file3.php
$obj = new Demo2();
/********************************************/
class Test1
{
//构造函数,外部调用该类时,首先调用构造函数
public function __construct($arg1)
{
echo '对象创建成功, 参数是: ' . $arg1;
}
}
class Test2
{
public function __construct($arg1, $arg2)
{
echo '对象创建成功, 参数是: ' . implode(', ', [$arg1, $arg2]);
}
}
class Test3
{
public function __construct($arg1, $arg2, $arg3)
{
//implode(',',[$arg1,$arg2,$arg3])= '$arg1,$arg2,$arg3';
echo '对象创建成功, 参数是: ' . implode(', ', [$arg1, $arg2, $arg3]);
}
}
// 工厂类, 专用于创建类实例
class Factory
{
//静态方法 $className 类名 ...$arguments是可变变量
public static function create($className, ...$arguments)
{
//根据传过来的类名和参数,对类进行实例化,并返回实例对象
return new $className(...$arguments);
}
}
//echo Test1::class; // _1205\Test1: 完整的类名, 带有命名空间的
//Test1::class是完整的类名,是带有命名空间的类名,在本命名空间下是指 _1205\Test1
// 用工厂类来创建类实例/对象
Factory::create(Test1::class, 100);
echo '<br>';
Factory::create(Test2::class, 100, 200);
echo '<br>';
Factory::create(Test3::class, 100, 200, 300);
结果
4、_1205\base\Travel1.php
代码
<?php
// ***类: 使用最传统的方式
namespace base;
// 设置引用的外部类名的别名
use base\inc1\Car;
use base\inc1\Train;
use base\inc1\Plane;
require __DIR__ . '/autoload.php';
class Travel1
{
// 交通工具 私有属性 只能在类内部调用,子类也不能调用
private $vehicle;
// 构造方法
public function __construct($vehicle)
{
//根据外部传入参数来对私有属性$vehicle存入相应类实例化得到的对象
switch (strtolower($vehicle)) {
case 'car':
$this->vehicle = new Car();
break;
case 'train':
$this->vehicle = new Train();
break;
case 'plane':
$this->vehicle = new Plane();
}
}
// 调用外部一个依赖对象
public function travelModel()
{
//此时的$this->vehicle就是某个类的实例化对象,所以会调用相应类中的方法
return $this->vehicle->drive() . ' : 去***';
}
}
// 客户端调用
echo (new Travel1('car'))->travelModel(), '<br>';
echo (new Travel1('train'))->travelModel(), '<br>';
echo (new Travel1('plane'))->travelModel(), '<br>';
结果
5、_1205\base\Travel2.php
代码
<?php
// ***类: 使用最传统的方式
namespace base;
// 设置引用的外部类名的别名
use base\inc1\Car;
use base\inc1\Train;
use base\inc1\Plane;
use base\inc1\Ship;
require __DIR__ . '/autoload.php';
// 工厂类, 专用于创建类实例
class Factory
{
//添加静态变量static $instance 用于存储类实例
protected static $instance = null;
//外部传入参数,得到相应类的实例对象
public static function getInstance($vehicle)
{
switch (strtolower($vehicle)) {
case 'car':
//类内调用该类属性使用self::
self::$instance = new Car();
break;
case 'train':
self::$instance = new Train();
break;
case 'ship':
self::$instance = new Ship();
break;
case 'plane':
self::$instance = new Plane();
}
// 返回当前具体的交通工具
return self::$instance;
}
}
class Travel2
{
// 交通工具
private $vehicle;
// 构造方法
public function __construct($vehicle)
{
//Factory::getInstance($vehicle)==self::$instance
//此时的$this->vehicle就是Factory::getInstance($vehicle)==self::$instance
//就是一个类实例
$this->vehicle = Factory::getInstance($vehicle);
}
// 调用外部一个依赖对象
public function travelModel()
{
//$this->vehicle是类实例,可以调用相应的类中的方法
return $this->vehicle->drive() . ' : @@@@ 去***';
}
}
// 客户端调用
echo (new Travel2('car'))->travelModel(), '<br>';
echo (new Travel2('train'))->travelModel(), '<br>';
echo (new Travel2('plane'))->travelModel(), '<br>';
echo (new Travel2('ship'))->travelModel(), '<br>';
结果
6、_1205\base\Travel3.php
代码
<?php
// 旅行类: 使用最传统的方式
namespace base;
// 设置引用的外部类名的别名
use base\inc2\Car;
use base\inc2\Train;
use base\inc2\Plane;
use base\inc2\Ship;
use base\inc2\iVehicle;
require __DIR__ . '/autoload.php';
class Travel3
{
// 交通工具 私有属性,只能在本类内部调用,外部、子类都不能调用
private $vehicle;
// 构造方法
public function __construct(iVehicle $vehicle)
{
//属性$this->vehicle初始化
$this->vehicle = $vehicle;
}
// 调用外部一个依赖对象
public function travelModel()
{
return $this->vehicle->drive() . ' : ======= 去旅行';
}
}
// 客户端调用
$car = new Car();
echo (new Travel3($car))->travelModel(), '<br>';
//new Train()作为参数传给new Travel3(),然后调用travelModel()
echo (new Travel3(new Train()))->travelModel(), '<br>';
echo (new Travel3(new Plane()))->travelModel(), '<br>';
echo (new Travel3(new Ship()))->travelModel(), '<br>';
结果
7、容器 _1205\lesson1\demo1.php
代码
<?php
namespace _1205;
require 'Product.php';
require 'Maker.php';
// 先不用容器,将外部类的对象的依赖直接放在本类中实例化
class Client1
{
// 输出商品与制造商
public function show()
{
// 创建产品的实例
$product = new Product();
// 创建制造商的实例
$maker = new Maker();
// 制造商注入到产品类中
return $product->get($maker);
}
}
// 客户端调用
echo (new Client1())->show();
结果
8、容器 _1205\lesson1\demo2.php
代码
<?php
namespace _1205;
require 'Product.php';
require 'Maker.php';
require 'Container.php';
//使用容器类
class Client2
{
// 输出商品与制造商
public function show(Product $product, Maker $maker)
{
// 制造商注入到产品类中
return $product->get($maker);
}
}
// 客户端调用
// 将类实例绑定到容器中并实例化且返回
$container = new Container();
// 将实例化代码绑定到容器中
$container->bind('product', function () {return new Product();});
$container->bind('maker', function () {return new Maker();});
// 创建类实例并返回
$product = $container->make('product');
$maker = $container->make('maker');
echo (new Client2())->show($product, $maker);
结果
二、手写1205.md
三、总结
1、容器Container
容器中存入了所依赖的类的实例对象队列,并且将类与类实例化代码的闭包函数绑定到容器中,bind()方法是放进去,make()是调用容器中的实例化方法。
2、依赖注入
类分为工作类和依赖类
工作类中需要调用其它类时,为了降低耦合度,需要将对被依赖的类的实例过程中的new消灭掉,这就是依赖注入的目的。