哔哩哔哩观看,他人转发慕课网视频,韩天峰大佬教学🙇‍♀️


基础

PSR-0规范

  1. 命名空间必须与绝对路径一致
  2. 类名首字母必须大写
  3. 除入口文件外,其他”.php”必须只有一个类

类的自动载入

index.php

1
2
3
define("BASEDIR", __DIR__);
include BASEDIR . '/Tool/Loader.php';
spl_autoload_register('\\Tool\\Loader::autoload');

Loader.php

1
2
3
4
5
6
7
8
9
10
11
<?php

namespace Tool;

class Loader
{
static function autoload($class)
{
require BASEDIR . '/' . $class . '.php';
}
}

PHP中报500错误时如何查看错误信息

1
2
ini_set("display_errors", "On");
error_reporting(E_ALL);

链式操作

index.php

1
2
3
4
5
6
7
8
$db = new \Tool\Database();

/*$db->where('id=1');
$db->where('name=2');
$db->order('id desc');
$db->limit(10);*/

$db->where('id=1')->where('name=2')->order('id desc')->limit(10);

Database.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php

namespace Tool;

class Database
{
function where($where)
{
return $this; //链式操作的关键在于把$this返回
}

function order($order)
{
return $this;
}

function limit($limit)
{
return $this;
}
}

魔术方法

  • __get & __set 当调用不存在的属性时调用
  • __call & __callStatic 当调用不存在的方法时调用
  • __toString 当一个对象被当作字符串对待时调用
  • __invoke 把一个对象当函数使用时调用

index.php

1
2
3
4
5
6
7
8
9
10
11
$MagicMethods = new \Tool\MagicMethods();
$MagicMethods->title = 'hello word';
echo $MagicMethods->title;
echo '<br />';
echo $MagicMethods->test(123);
echo '<br />';
echo $MagicMethods::test(123);
echo '<br />';
echo $MagicMethods;
echo '<br />';
echo $MagicMethods('test');

MagicMethods.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php

namespace Tool;

class MagicMethods
{
protected $array = [];

function __set($key, $value)
{
$this->array[$key] = $value;
}

function __get($key)
{
return $this->array[$key];
}

function __call($name, $arguments)
{
return "magic function";
}

static function __callStatic($name, $arguments)
{
return "magic static function";
}

function __toString()
{
return __CLASS__;
}

function __invoke($param)
{
var_dump($param);
return 'invoke';
}
}

设计模式

面向对象编程的基本原则

  1. 单一职责:一个类,只需要做好一件事情。
  2. 开放封闭:一个类,应该是可扩展的,而不可修改的。
  3. 依赖倒置:一个类,不应该强依赖另外一个类。每个类对于另外一个类都是可替换的
  4. 配置化:尽可能地使用配置,而不是硬编码。
  5. 面向接口编程:只需要关心接口,不需要关心实现。

工厂模式

当一个类发生改变,只需要修改工厂模式中的类即可。如果直接 new 则需要修改大量的代码

index.php

1
2
$db = \Tool\Factory::createDatabase();
var_dump($db);

Factory.php

1
2
3
4
5
6
7
8
9
10
11
12
<?php

namespace Tool;
//工厂模式
class Factory
{
static function createDatabase()
{
$db = new Database();
return $db;
}
}

单例模式

只 new 出一个对象,省出大量 new 产生的内存(三私一公)

index.php

1
2
3
4
5
$db = \Tool\Singleton::getInstance();
$db->test();
echo '<hr />';
//$db2 = new \Tool\Singleton(); //Fatal error: Uncaught Error: Call to private Singleton::__construct() from invalid context in
//$db3 = clone $db; //Fatal error: Uncaught Error: Call to private Singleton::__clone() from context

Singleton.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php

namespace Tool;
//单例模式
class Singleton
{
static private $db;

private function __construct()
{

}

private function __clone()
{

}

static function getInstance()
{
if (self::$db) {
return self::$db;
} else {
self::$db = new self();
return self::$db;
}
}

public function test(){
echo 'test';
}
}

注册树模式

类不需要再直接 new,全局共享和交换对象。就像是一棵树一样,先把对象放在树上,用的时候取下来即可。
相当于laravel中的 Facades

index.php

1
2
$db = \Tool\Register::get('db');
var_dump($db);

Register.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php

namespace Tool;
//注册树模式
class Register
{
protected static $objects;

public static function set($alias, $object)
{
self::$objects[$alias] = $object;
}

public static function get($alias)
{
if (isset(self::$objects[$alias])) {
return self::$objects[$alias];
} else {
return false;
}
}

public static function _unset($alias)
{
unset(self::$objects[$alias]);
}
}

适配器模式

可以将截然不同的函数接口封装成统一的API
实际应用举例:PHP的数据库操作有mysql、mysqli、pdo3种,可以用适配器模式统一成一致。类似的场景还有cache适配器,将memcache、redis、file、apc等不同的缓存函数统一成一致。

相当于laravel中的 数据库操作

index.php

1
2
3
4
5
$db = new \Tool\Database\PDO();
$db->connect('mysql', 'root', 'root', 'default');
$res = $db->query('show databases');
var_dump($res->fetchAll(\PDO::FETCH_ASSOC));
$db->close();

PDO.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php

namespace Tool\Database;
//适配器模式
use Tool\IDatabase;

class PDO implements IDatabase
{
protected $conn;

function connect($host, $user, $passwd, $dbname)
{
$conn = new \PDO("mysql:host={$host};dbname={$dbname};", $user, $passwd);
$this->conn = $conn;
}

function query($sql)
{
$res = $this->conn->query($sql);
return $res;
}

function prepare($sql)
{
$res = $this->conn->prepare($sql);
return $res->execute();
}

function close()
{
unset($this->conn);
}
}

策略模式

将一组特定的行为和算法封装成类,以适应某些特定的上下文环境
实际应用举例:假如一个电商网站系统,针对男性女性用户要求各自跳转到不同的商品类目,并且所有广告位展示不同的广告。

相当于laravel中的 用户认证

index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Page
{
protected $strategy;

function index()
{
echo 'AD:';
$this->strategy->showAd();
echo '<br />';
echo 'Category:';
$this->strategy->showCategory();
}

function setStrategy(\Tool\UserStrategy $strategy)
{
$this->strategy = $strategy;
}
}

$page = new Page();
if (isset($_GET['female'])) {
$strategy = new \Tool\Strategy\FemaleUserStrategy();
}
{
$strategy = new \Tool\Strategy\MaleUserStrategy();
}
$page->setStrategy($strategy);
$page->index();

UserStrategy.php

1
2
3
4
5
6
7
8
9
10
<?php

namespace Tool;
//策略模式
interface UserStrategy
{
function showAd();

function showCategory();
}

MaleUserStrategy.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

namespace Tool\Strategy;

use Tool\UserStrategy;

class MaleUserStrategy implements UserStrategy
{
function showAd()
{
echo '华为P40';
}

function showCategory()
{
echo '电子产品';
}
}

FemaleUserStrategy.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

namespace Tool\Strategy;

use Tool\UserStrategy;

class FemaleUserStrategy implements UserStrategy
{
function showAd()
{
echo '2021新款女装';
}

function showCategory()
{
echo '女装';
}
}

数据对象映射模式

将对象和数据存储映射起来,对一个对象的操作会映射为对数据存储的操作

相当于laravel中的 模型

index.php

1
2
3
4
5
$user = new \Tool\User(1);
var_dump($user);
$user->mobile = '16666666666';
$user->name = '张三';
$user->regtime = date('Y-m-d H:i:s');

User.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php

namespace Tool;
//数据对象映射模式
class User
{
public $id;
public $name;
public $mobile;
public $regtime;

protected $db;

function __construct($id)
{
$this->db = new \Tool\Database\PDO();
$this->db->connect('mysql', 'root', 'root', 'default');
$res = $this->db->query("select * from user where `id`={$id} limit 1");
$data = $res->fetch(\PDO::FETCH_ASSOC);
$this->id = $data['id'];
$this->name = $data['name'];
$this->mobile = $data['mobile'];
$this->regtime = $data['regtime'];
}

function __destruct()
{
try {
$this->db->prepare("update user set `name`='{$this->name}',`mobile`='{$this->mobile}',`regtime`='{$this->regtime}' where `id`={$this->id} ");
echo '<br />';
}catch (Exception $e){
var_dump($e);
}
}
}

结合工厂模式、注册器模式使用

index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Page1
{
function index()
{
$user = \Tool\Factory::getUser(1);
$user->regtime = date('Y-m-d H:i:s');
var_dump($user);
echo '<br />';
$this->test();
}

function test()
{
$user = \Tool\Factory::getUser(1);
var_dump($user);
$user->mobile = '16666666666';
}
}

$page = new Page1();
$page->index();

Factory.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php

namespace Tool;
//工厂模式
class Factory
{
static function createDatabase()
{
$db = new Database();
Register::set('db', $db);//环境初始化,先在工厂模式中生产对象,在通过注册树模式注册
return $db;
}

/**
* 数据对象映射模式结合工厂模式、注册器模式使用
* @param $id
* @return User
*/
static function getUser($id)
{
$key = 'user_' . $id;
$user = Register::get($key);
if (!$user) {
$user = new \Tool\User($id);
Register::set($key, $user);
}

return $user;
}
}

观察者模式

当一个对象状态发生改变时,依赖他的对象全部会收到通知,并自动更新
场景:一个事件发生后,要执行一连串更新操作。传统的编程方式,就是在事件的代码之后直接加入处理逻辑。当更新的逻辑增多之后,代码会变得难以维护。这种方式是耦合的,侵入式的,增加新的逻辑需要修改事件主体的代码
观察者模式实现了低耦合,非侵入式的通知与更新机制

相当于laravel中的 事件系统

index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Event extends \Tool\EventGenerator
{
function trigger()
{
echo 'Event<br />';

$this->notify();
}
}

class Observer1 implements \Tool\Observer
{
function update($event_info = null)
{
echo '逻辑1<br />';
}
}

class Observer2 implements \Tool\Observer
{
function update($event_info = null)
{
echo '逻辑2<br />';
}
}

$event = new Event();
$event->addObserver(new Observer1());
$event->addObserver(new Observer2());
$event->trigger();

Observer.php

1
2
3
4
5
6
7
8
<?php

namespace Tool;
//观察者模式
interface Observer
{
function update($event_info = null);
}

EventGenerator.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

namespace Tool;
//观察者模式
abstract class EventGenerator
{
private $observers = [];
function addObserver(Observer $observer)
{
$this->observers[] = $observer;
}

function notify()
{
foreach ($this->observers as $observer) {
$observer->update();
}
}
}

原型模式

与工厂模式作用类似,都是用来创建对象
与工厂模式的实现不同,原型模式是先创建好一个原型对象,然后通过clone原型对象来创建新的对象。这样就免去了类创建时重复的初始操作
原型模式适用于大对象的创建。创建一个大对象需要很大的开销,如果每次new就会消耗很大,原型模式仅需要内存拷贝即可

index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$canvas1 = new \Tool\Canvas();
$canvas1->init();
$canvas1->rect(3, 6, 4, 12);
$canvas1->draw();
echo '<br />';
$canvas2 = new \Tool\Canvas();
$canvas2->init();
$canvas2->rect(1, 3, 2, 6);
$canvas2->draw();
echo '<br />';
//因为init产生了20x10=200次的循环,上述方法多次new对象,消耗很大内存
$prototype = new \Tool\Canvas();
$prototype->init();
//-----------------
$canvas1 = clone $prototype;
$canvas1->rect(3, 6, 4, 12);
$canvas1->draw();
echo '<br />';
$canvas2 = clone $prototype;
$canvas2->rect(1, 3, 2, 6);
$canvas2->draw();

Canvas.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php

namespace Tool;
//原型模式
class Canvas
{
public $data;

protected $decorators = [];

function init($width = 20, $height = 10)
{
$data = [];
for ($i = 0; $i < $height; $i++) {
for ($j = 0; $j < $width; $j++) {
$data[$i][$j] = '*';
}
}
$this->data = $data;
}

function draw()
{
$this->beforeDraw();
foreach ($this->data as $line) {
foreach ($line as $char) {
echo $char;
}
echo "<br />\n";
}
$this->afterDraw();
}

function rect($a1, $a2, $b1, $b2)
{
foreach ($this->data as $k1 => $line) {
if ($k1 < $a1 || $k1 > $a2) continue;
foreach ($line as $k2 => $char) {
if ($k2 < $b1 || $k2 > $b2) continue;
$this->data[$k1][$k2] = '&nbsp;';
}
}
}
}

迭代器模式

在不需要了解内部实现的前提下,遍历一个聚合对象的内部元素
相比于传统的编程模式,迭代器模式可以隐藏遍历元素的所需的操作

index.php

1
2
3
4
$users = new \Tool\AllUser();
foreach ($users as $item) {
var_dump($item->name);
}

AllUser.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php

namespace Tool;
//迭代器模式
class AllUser implements \Iterator
{
protected $ids;
protected $index;
protected $data = [];

function __construct()
{
$db = new \Tool\Database\PDO();
$db->connect('mysql', 'root', 'root', 'default');
$res = $db->query('select id from user order by id asc');
$this->ids = $res->fetchAll(\PDO::FETCH_ASSOC);
}

function current()
{
$id = $this->ids[$this->index]['id'];
return Factory::getUser($id);
}

function key()
{
return $this->index;
}

function next()
{
++$this->index;
}

function rewind()
{
$this->index = 0;
}

function valid()
{
return $this->index < count($this->ids);
}
}

装饰器模式

可以动态的添加修改类的功能
一个类提供了一项功能,如果要在修改并添加额外的功能,传统的编程模式,需要写一个子类继承它,并重新实现类的方法
使用装饰器模式,仅需在运行时添加一个装饰器对象即可实现,可以实现最大的灵活性

相当于laravel中的 中间件模型中的事件

index.php

1
2
3
4
5
6
$canvas1 = new \Tool\Canvas();
$canvas1->init();
$canvas1->addDecorator(new \Tool\Decorator\ColorDrawDecorator('blue'));
$canvas1->addDecorator(new \Tool\Decorator\SizeDrawDecorator(30));
$canvas1->rect(3, 6, 4, 12);
$canvas1->draw();

DrawDecorator.php

1
2
3
4
5
6
7
8
9
10
<?php

namespace Tool;
//装饰器模式
interface DrawDecorator
{
function beforeDraw();

function afterDraw();
}

Canvas.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<?php

namespace Tool;
//原型模式
class Canvas
{
public $data;

protected $decorators = [];

function init($width = 20, $height = 10)
{
$data = [];
for ($i = 0; $i < $height; $i++) {
for ($j = 0; $j < $width; $j++) {
$data[$i][$j] = '*';
}
}
$this->data = $data;
}

//--装饰器模式
function addDecorator(DrawDecorator $decorator)
{
$this->decorators[] = $decorator;
}

function beforeDraw()
{
foreach ($this->decorators as $decorator) {
$decorator->beforeDraw();
}
}

function afterDraw()
{
$decorator = array_reverse($this->decorators);
foreach ($this->decorators as $decorator) {
$decorator->afterDraw();
}
}

//--装饰器模式

function draw()
{
$this->beforeDraw();
foreach ($this->data as $line) {
foreach ($line as $char) {
echo $char;
}
echo "<br />\n";
}
$this->afterDraw();
}

function rect($a1, $a2, $b1, $b2)
{
foreach ($this->data as $k1 => $line) {
if ($k1 < $a1 || $k1 > $a2) continue;
foreach ($line as $k2 => $char) {
if ($k2 < $b1 || $k2 > $b2) continue;
$this->data[$k1][$k2] = '&nbsp;';
}
}
}
}

ColorDrawDecorator.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php

namespace Tool\Decorator;
//装饰器模式
use Tool\DrawDecorator;

class ColorDrawDecorator implements DrawDecorator
{
protected $color;

function __construct($color = 'red')
{
$this->color = $color;
}

function beforeDraw()
{
echo "<div style='color: {$this->color}'>";
}

function afterDraw()
{
echo "</div>";
}
}

SizeDrawDecorator.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php

namespace Tool\Decorator;
//装饰器模式
use Tool\DrawDecorator;

class SizeDrawDecorator implements DrawDecorator
{
protected $size;

function __construct($size = '14')
{
$this->size = $size;
}

function beforeDraw()
{
echo "<div style='font-size: {$this->size}px'>";
}

function afterDraw()
{
echo "</div>";
}
}

代理模式

在客户端与实体之间建立一个代理对象(proxy),客户端对实体进行操作全部委派给代理对象,隐藏实体的具体实现细节
Proxy还可以与业务代码分离,部署到另外的服务器。业务代码中通
例如、mysql的主从结构,读写分离。读请求从库,写请求主库

index.php

1
2
3
4
5
6
$proxy = new \Tool\Proxy();
$id = 1;
$name = '张三';
var_dump($proxy->getUserName($id));
echo '<br />';
var_dump($proxy->setUserName($id, $name));

IUserPorxy.php

1
2
3
4
5
6
7
8
9
10
<?php

namespace Tool;
//代理模式
interface IUserPorxy
{
function getUserName($id);

function setUserName($id, $name);
}

Proxy.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php

namespace Tool;
//代理模式
class Proxy implements IUserPorxy
{
protected $db;

function __construct()
{
$this->db = new \Tool\Database\PDO();
$this->db->connect('mysql', 'root', 'root', 'default');
}

function getUserName($id)
{
$res = $this->db->query("select name from user where `id`={$id} limit 1");
return $res->fetch(\PDO::FETCH_ASSOC);
}

function setUserName($id, $name)
{
return $this->db->prepare("update user set `name`='{$name}' where `id`={$id}");
}
}