ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
# :-: 一、自动加载 > 普通加载文件 ```php include __DIR__ . '/inc/Test1.php'; include __DIR__ . '/inc/Test2.php'; include __DIR__ . '/inc/Test3.php'; // 查看完整的类名称 echo \inc\Test1::class, '<br>'; // inc/Test1 echo \inc\Test1::class, '<br>'; // inc/Test2 echo \inc\Test1::class, '<br>'; // inc/Test3 echo '<hr>'; // 调用导入的类,访问时, 需要带上类的命名空间 echo \inc\Test1::get(), '<br>'; echo \inc\Test2::get(), '<br>'; echo \inc\Test3::get(), '<br>'; echo '<hr>'; ``` >[info] Test1.php、Test2.php、Test3.php 文件 ```php <?php namespace inc; class Test1{ public static function get(){ return __CLASS__ . ' 类, 加载成功~~'; } } ``` >[info] 进阶加载 ```php // 如果当前脚本使用了几十上百这样的类, 上面的方式就很不人性 // 使用下面的自动加载机制, 会根据客户端调用的类, 自动进行加载,效率高, 不出错 // 发现的规律: // 以要加载的类名: inc\Test1为例, 它的命名空间与类所在目录具有对应关系 // 将类名inc\Test1, 替换成类文件: inc/Test1.php, 就可以实现自动加载 $path = str_replace('\\', '/', \inc\Test1::class); echo $path, '<br>'; // 加上完整的绝对路径与扩展名 echo __DIR__ . '/'.$path . '.php', '<br>'; // 更新$path $path = __DIR__ . '/'.$path . '.php'; // 加载 inc/Test1.php require $path; // 执行成功, 证明这种方式可以实现类文件加载 echo \inc\Test1::get(); ``` * `spl_autoload_register(callback)`: 通过回调自动加载外部文件 ```php // php标准函数库中提供了一个自动加载文件的注册函数,可以实现这个功能 // 这个函数,在当前脚本引用一个未加载的文件时, 会自动调用它的回调方法来加载这个文件 // 该函数的参数是一个回调,回调函数的参数就是当前要加载的类文件 spl_autoload_register(function ($className){ $path = str_replace('\\', '/', $className); $path = __DIR__ . '/'.$path . '.php'; if (file_exists($path)) { require $path; } }); echo \inc\Test1::get(), '<br>'; echo \inc\Test2::get(), '<br>'; echo \inc\Test3::get(), '<br>'; ``` -------------------------------------------- # :-: 二、抽象类 * `abstract`: 定义抽象方法/抽象类 * 类中只要有一个抽象方法, 该类就应该声明为抽象类 * 抽象类只能被继承,不能实例化,并且抽象方法必须在子类实现 * 实现抽象方法的子类方法可见性不能低于抽象方法原定义 * 抽象方法是public, 子类方法只能是public * 抽象方法是protected, 子类方法只能是protected/public ```php namespace admin; class Person{ protected $name; public function __construct($name='欧阳克'){ $this->name = $name; } public function getName(){ return $this->name; } public function setName($value){ $this->name = $value; } } $person = new Person(); echo '我的姓名: ' . $person->getName() . '<br>'; $person->setName('黄蓉'); echo '我的姓名: ' . $person->getName() . '<br>'; echo '<hr>'; ``` >[info] 一个抽象类必须被扩展为一个特定的类,我们才能创建类实例,使用类中功能 ```php abstract class Person{ protected $name; protected function __construct($name='peter zhu'){ $this->name = $name; } // 该方法不需要重写, 可以通过子类对象访问,应该设置为public public function getName(){ return $this->name; } // 修改属性方法,设置为抽象方法,交给子类实现 // 因为类中有了一个抽象方法, 所以这个类Person也必须设置抽象类, 不允许直接实例化 abstract protected function setName($value); } // 子类Stu 扩展了父类 Person class Stu extends Person{ // 注意: 构造方法不会自动继承, 必须手动重写 public function __construct(string $name = 'peter zhu'){ parent::__construct($name); } // 子类中必须实现抽象父类中的抽象方法 public function setName($value){ $this->name = $value; } } $stu = new Stu('欧阳克'); echo '白驼山: ' . $stu->getName() . '<br>'; // 调用子类的重写的抽象方法setName(),来设置属性 $stu->setName('黄蓉'); echo '桃花岛: ' . $stu->getName() . '<br>'; ``` * 在实际开发过程中, 通常并不会直接使用一个父类/超类,而是在父类中定义一些方法声明 * 并且确信这个方法肯定是会被子类重写的, 父类中没必要实现,只要给一个方法编写规范即可 * 这个规范包括方法的名称, 参数列表等,具体实现就完全交给子类去完成了 * 相当于公司的部门主管, 接受到老板的任务, 只把属于自己的部分做了, 其它部分, 设置一个标准交给下属去完成 * 这个老板就是接口,我们一会会讲到, 这个部门经理,我们用抽象类实现, 而下属就是子类啦,最终干活的就是子类 -------------------------------------------- # :-: 三、接口 * `interface`: 指定某个类必须实现的方法,但不需要定义方法的具体实现过程 * 接口中仅允许出现: 方法与类常量 * 接口的方法可见性必须是: public * 接口的方法体必须是空的 * 接口是类的代码模板, 可以像类一样有父子继承关系,例如父接口, 子接口 * `implements`: 类实现接口的关键字, 读音: ['ɪmplɪmɛnts,应波罗曼次] * 如果仅是部分实现接口中的方法, 请用一个抽象类来实现它 ```php namespace admin; interface iVehicle{ // 驱动方式: 汽车, 新能源 public function setFuel($fuel); // 用途 public function setPurpose($purpose); } // Car 类 实现了接口: iVehicle class Car implements iVehicle{ public $fuel; public $purpose; // 必须实现的接口方法 public function setFuel($fuel){ $this->fuel = $fuel; } // 必须实现的接口方法 public function setPurpose($purpose){ $this->purpose = $purpose; } // 类中自定义的对象方法 public function getInfo(){ return $this->fuel . $this->purpose . '车 <br>'; } } // Auto 类 实现了接口: iVehicle class Auto implements iVehicle{ public $fuel; public $purpose; // 必须实现的接口方法 public function setFuel($fuel){ $this->fuel = $fuel; } // 必须实现的接口方法 public function setPurpose($purpose){ $this->purpose = $purpose; } // 类中自定义的对象方法 public function getInfo(){ return $this->fuel . $this->purpose . '车 <br>'; } } // Car类的实例化 $car = new Car(); $car->setFuel('新能源'); $car->setPurpose('公交'); echo $car->getInfo(); // Auto类的实例化 $car = new Auto(); $car->setFuel('家用'); $car->setPurpose('燃油'); echo $car->getInfo(); ``` -------------------------------------------- # :-: 四、接口实战 * 数据库CURD接口与实现 ```php namespace admin; // 定义一个接口,实现数据库常用操作:增删改查 interface iCurd{ // 增加数据 public function create($data); // 读取数据 public function read(); // 更新数据 public function update($data, $where); // 删除数据 public function delete($where); } // 创建Db类, 实现iCurd接口,完成基本的数据库操作 class Db implements iCurd{ //数据库的连接对象 protected $pdo = null; // 数据表名 protected $table; // 构造方法: 连接数据库,并设置默认数据表名称 public function __construct($dsn, $user, $password, $table='user'){ $this->pdo = new \PDO($dsn, $user, $password); $this->table = $table; } // 读取 public function read($fields='*', $where='', $limit='0, 5'){ // 设置查询条件 $where = empty($where) ? '' : ' WHERE ' . $where; // 设置显示数量 $limit = ' LIMIT ' . $limit; // 预处理查询操作 $sql = 'SELECT '.$fields.' FROM '.$this->table.$where.$limit; $stmt = $this->pdo->prepare($sql); $stmt->execute(); // 返回二维数组表示的查询结果集 return $stmt->fetchAll(\PDO::FETCH_ASSOC); } // 新增, 参数是数组: 新记录的键值对 public function create($data){ // 字段列表 $fields = ' (name,phone,sex,pwd,status,last_time)'; // 值列表 $values = '(:name,:phone,:sex,:pwd,:status,:last_time)'; // 创建SQL语句 $sql = 'INSERT INTO '.$this->table.$fields.' VALUES '.$values; // 预处理执行新增操作 $stmt = $this->pdo->prepare($sql); $stmt->execute($data); // 返回新增数量, 新增记录的ID组成的数组 return [ 'count'=>$stmt->rowCount(), 'id'=>$this->pdo->lastInsertId() ]; } // 更新, 为了数据安全, 不允许无条件更新 public function update($data, $where){ // 难点在于SET 参数的处理上,利用传入的$data数组,进行拆装 // 获取数组的键名组成的数组 $keyArr = array_keys($data); $set = ''; // 遍历键名表示的字段列表,拼装预处理需要的sql语句,注意占符符的表示 foreach ($keyArr as $value) { $set .= $value . ' = :' .$value. ', '; } // 去掉最后一个逗号, 注意每个逗号后有一个空格,去除时也要带上这个空格 $set = rtrim($set,', '); // 预处理执行更新操作 $sql = 'UPDATE '.$this->table.' SET '.$set .' WHERE ' .$where; $stmt = $this->pdo->prepare($sql); $stmt->execute($data); // 返回被更新的记录数量 return $stmt->rowCount(); } // 删除: 与更新一样, 这也是危险的写操作, 不允许无条件删除 public function delete($where){ // 预处理执行删除操作 $sql = 'DELETE FROM '.$this->table.' WHERE '.$where; $stmt = $this->pdo->prepare($sql); $stmt->execute(); return $stmt->rowCount(); } } // 客户端的测试代码 // 实例化Db类 $dsn = 'mysql:host=localhost;dbname=ouyangke'; $user = 'root'; $password = 'root'; $db = new Db($dsn, $user, $password); // 遍历读取 // 全部 foreach ($db->read() as $item) { print_r($item); echo '<br>'; } // 设置查询条件 foreach ($db->read('uid, name, phone', 'age > 50') as $item) { print_r($item); echo '<br>'; } echo '<hr>'; // 新增数据 $data = [ 'phone'=>'13666668888', 'name'=>'郭靖', 'pwd'=>md5(123456), 'age'=>30, 'sex'=>1, 'status'=>1, 'last_time'=>time() ]; $res = $db->create($data); echo '成功新增'.$res['count'].'条记录,最新记录的主键ID是: '.$res['id']; // 更新记录 $data = [ 'name'=>'抗金英雄郭靖', 'age' => 40 ]; $where = 'uid = 11'; echo '成功更新了: ' .$db->update($data, $where). ' 条记录'; // 删除记录 $where = 'uid = 11'; echo '成功更新了: ' .$db->delete($where). ' 条记录'; ``` -------------------------------------------- # :-: 五、后期静态绑定 * 后期静态绑定,也叫"延迟静态绑定" * 这个技术应用在静态继承的上下文环境中,用于动态调用被重写的方法 * 调用被重写的静态方法使用关键字: `static` 加上"范围解析符"`::` * `::` 范围解析符的使用场景 * 访问类方法与类常量 * 访问被重写的对象或类方法 * static关键字用来调用重写方法的时候,可以动态的绑定当前调用的类