# :-: 一、命名空间
* 命名空间: 解决全局成员的命名冲突问题, 借鉴了文件目录的基本思想
* 目录: 同一目录下不允许重名文件, 但不同目录下, 允许同名文件存在
* 空间: 同一空间内不允许成员重名, 但不同空间内, 允许同名成员存在
* 命名空间使用 "namespace" 关键字声明
```php
// 如果是相同的名字,php是不运行的
const NAME = '欧阳克';
function sum() {}
class Demo {}
const NAME = '黄蓉';
function sum() {}
class Demo {}
```
>[info] 使用命名空间
```php
namespace red;
class Test {}
namespace green;
class Test {}
namespace blue;
class Test {}
```
>[info] 命名空间,"大括号" 来声明空间
```php
namespace one
{
class Test {}
}
// 空间: two
namespace two
{
class Test {}
}
// 匿名空间代表: 全局空间, 也是默认的空间,或叫根空间,用 \ 表示
namespace
{
class Test {}
}
```
* 例如: php同时引入两个文件,文件中都有add方法。
* 例如: 合肥有条北京路, 上海也有条北京路, 但不会有人认为这是同一条路,因为用城市做了区隔
* 所以, 城市,就是路名的命名空间,这样的例子生活中到处都是,不难理解
* 目前我们只关心 "类" 的命名空间
*****
# :-: 二、类与对象
* 定义: `class`
* 实例化: `new`
```php
namespace admin;
// 关键词: 类, new, 类实例, 对象, 对象检测
// 类定义
// 类: 是生成对象的代码模板
class People
{
//...
}
// 对象: 类的实例化, 是类的一个具体实现案例
// 例如: 动物是类, 而小猪, 则是动物类的一个具体的实现案例
// 注意: "实例" 与 "对象" 是同义词, 大多情况下可互换
$obj1 = new People();
$obj2 = new People();
$obj3 = new People();
// 3个对象都是Demo01类的实例,有不同的#id
var_dump($obj1);
echo '<br>';
var_dump($obj2);
echo '<br>';
var_dump($obj3);
echo '<hr>';
// 检测对象是否是同一个类的实例
var_dump($obj1 instanceof Demo1);
echo '<br>';
var_dump($obj2 instanceof Demo1);
echo '<br>';
var_dump($obj3 instanceof Demo1);
echo '<hr>';
// 3个对象虽是同一个类的实例,但彼此并不相等,是完全独立的
var_dump($obj1 == $obj2);
echo '<br>';
var_dump($obj2 === $obj3);
```
*****
# :-: 三、对象属性
* 类中的属性,也叫: 成员变量
* 属性的语法与变量类似,但也是有区别的:
* 在类中声明属性变量时,需要通过访问限定符,设置它的作用域
* 属性: 初始化必须使用常数,不得使用表达式
* public 是访问限制符,可视为属性作用域(可见性)
* public 是指该属性不论是类内,类外,子类都是可访问的
* 访问限定符还有protected,private,目前我们先学习public
```php
namespace admin;
class Demo{
// 为什么叫实例属性? 因为只能用类的实例, 即对象来访问它
// 设置了初始值, 并约定在类外部可以访问
public $product = '手机';
public $price = 2800;
}
// 调用类/函数的代码叫: 客户端, 以后我们还会频繁的使用这个名词
// 以下代码其实都是客户端代码
// 通过类的实例对象访问
// 创建类实例对象
$obj = new Demo();
// 输出当前实例属性的值
echo '品名: ' .$obj->product .', 价格: ' . $obj->price . '<br>';
echo '<hr>';
// 动态对象属性:
// 属性除了可以声明在类的内外, 在类的外部,也可以动态的添加
$obj->brand = '华为';
echo '品牌: ' . $obj->brand;
// get_class_vars()返回类中public属性的属性组成的数组
// 因为使用了命名空间, 完整的类名应该包括了命名空间的, 可以使用::class来获取完整的类名
$properties = get_class_vars(Demo::class);
echo '<pre>'.print_r($properties,true);
// 注意: 用户自定义动态属性不会出现在属性清单中
```
* 动态属性: 肯定,必然是对象属性,只能通过对象添加与访问
* 动态属性: 因为是在类外部添加,所以只能是public类型
* 动态属性: 因为不在类中声明,不会得到编辑器的提示, 也不会检查拼写错误
* 所以, 实际开发中, 几乎用不到动态属性,大家知道即可, 尽可能不要去使用它
*****
# :-: 四、对象方法
* 对象方法的定义与访问
* `self`: 当前类
* `$this`: 当前类实例对象的引用
```php
namespace admin;
class Demo{
// 实例属性
public $product = '手机';
public $price = 2800;
// 实例方法
public function getInfo1(){
// self : 当前类
$obj = new self();
// 输出实例属性
return '品名: ' .$obj->product .', 价格: ' . $obj->price . '<br>';
}
// 实例方法
public function getInfo2(){
// 因为该方法必须通过对象调用,所有没必要在类中实例化
// 直接引用该类的实例化对象即可
// 在类中使用伪变量: "$this" 引用当前类的实例
// $this = new self(); 相当于先执行了这条语句,尽管你不需要这样做
return '品名: ' .$this->product .', 价格: ' . $this->price . '<br>';
}
}
// 类实例化
$obj = new Demo();
echo $obj->getInfo1();
echo $obj->getInfo2();
// 查看类中定义的对象方法: public 才会显示出来
$methods = get_class_methods(Demo::class);
echo '<pre>'.print_r($methods,true);
```
*****
# :-: 五、构造方法与析构方法
* 构造方法用来初始化对象成员
* 构造函数是类中的特殊方法,在类实例化时会被自动调用,可用来初始化实例成员
* 析构方法在对象被销毁的时候, 会被自动调用; 不过, 即使没有这个方法, 也会自动清理对象的
```php
namespace admin;
class Demo{
// 实例属性
public $product;
public $price;
// 构造方法
public function __construct($product, $price){
$this->product = $product;
$this->price = $price;
}
// 对象方法
public function getInfo(){
return '品名: ' .$this->product .', 价格: ' . $this->price . '<br>';
}
// 析构方法: 在对象被删除/清理时自动调用
public function __destruct(){
echo '<h3 style="color:red">对象已被清理</h3>';
}
}
// 实例化
$obj = new Demo4('电脑', 5800);
echo $obj->getInfo();
unset($obj);
// $obj = null;
```
>[info] 实战: 自动连接数据库
```php
namespace admin;
class Db{
// 连接对象
public $pdo;
// 希望在实例化时, 自动连接数据库, 这个需求很常见
public function __construct($dsn, $user, $password){
// 使用PDO方式管理数据库, 连接成功则返回PDO对象,赋值给对象属性pdo
$this->pdo = new \PDO($dsn, $user, $password);
}
// 析构方法: 在对象被删除/清理时自动调用
public function __destruct(){
echo '<h3 style="color:red">连接已断开</h3>';
}
}
// 实例化
$db = new Db('mysql:host=localhost;dbname=php', 'root', 'root');
if ($db->pdo) {
echo '<h2>连接成功</h2>';
}
// 读取数据库测试
$stmt = $db->pdo->prepare('SELECT * FROM `user`');
$stmt->execute();
foreach ($stmt->fetchAll(\PDO::FETCH_ASSOC) as $cate) {
print_r($cate); echo '<br>';
}
```
*****
# :-: 六、类的继承
* 继承: `extends`
* 扩展: `__construct()`, `method()`
* 重写: `function parentMethod(){...}` 重写主要指方法重写, 属性重写意义不大
>[info] 类的继承
```php
namespace admin;
class Demo{
// 对象属性
public $product;
public $price;
// 构造方法
public function __construct($product, $price){
$this->product = $product;
$this->price = $price;
}
// 对象方法
public function getInfo(){
return '品名: ' .$this->product .', 价格: ' . $this->price . '<br>';
}
}
// 子类Sub1, 代码复用
class Sub1 extends Demo{
// ...
}
// 实例化子类Sub, 尽管子类中无任何成员,但是它可以直接调用父类Demo中的全部成员
$sub1 = new Sub1('手机', 3500);
echo $sub1->getInfo() . '<hr>';
```
>[info] 扩展父类功能
```php
// 子类Sub2, 增加属性和方法
class Sub2 extends Demo{
public $num; // 数量
// 子类的构造方法
public function __construct($product, $price, $num){
// 调用父类的构造方法,否则还要手工把父类中的属性初始化语句全部写一遍
// parent:: 调用被覆写的父类方法内容
parent::__construct($product, $price);
// 只需要添加子类中的成员初始化代码
$this->num = $num;
}
// 子类中增加一个新方法: 计算总价
public function total(){
return round($this->price * $this->num, 2);
}
}
// 实例化子类
$sub2 = new Sub2('电脑',3980, 13);
// 调用子类方法, 计算总价
echo $sub2->product . '的总价: ' . $sub2->total() . '<hr>';
```
>[info] 方法重写
```php
// 为了促销, 通常会根据总价,给予一定的折扣,刺激消费者购买更多的商品或服务
// 第三个子类, 继承自Sub2, 而Sub2又继承自Demo5,这就形成了多层级的继承关系
class Sub3 extends Sub2{
// 重写父类Sub2total()方法, 增加计算折扣价功能
public function total(){
// 先获取未打折时的商品总金额
$total = parent::total();
// 设置折扣率
switch (true) {
case ($total > 20000 && $total < 40000):
$discountRate = 0.88; // 88折
break;
case ($total > 40000 && $total < 60000):
$discountRate = 0.78; // 78折
break;
case ($total >= 60000):
$discountRate = 0.68; // 68折
break;
default: // 小于20000元不打折
$discountRate = 1;
}
// 结果四舍五入,保留2位小数
// 获取折后价
$discountPrice = round($total*$discountRate, 2);
// 如果折扣率小于1, 表示已打折, 给折扣率描红显示
if ($discountRate < 1) {
$discountPrice = $discountPrice.' 元, <span style="color: red"> ('.$discountRate.'折)</span>';
}
// 返回折扣价
return $discountPrice;
}
}
// 实例化子类, 88折
$sub3 = new Sub3('电脑',3980, 13); // 7.8折
$sub3 = new Sub3('电脑',3980, 23); // 7.8折
$sub3 = new Sub3('电脑',3980, 3); // 不打折
echo '折扣价: ' . $sub3->total();
```
*****
# :-: 七、访问控制
* `public`: 默认, 类内,类外,子类都可见
* `protected`: 类内, 子类可见, 类外不可见
* `private`: 类内可见, 子类, 类外不可见
```php
namespace admin;
class Demo{
// 对象属性
public $name; // 姓名
protected $position; // 职位
private $salary; // 工资
protected $department; // 部门
// 构造方法
public function __construct($name, $position, $salary, $department){
$this->name = $name;
$this->position = $position;
$this->salary = $salary;
$this->department = $department;
}
// 对于不能通过类实例访问的属性,应该设置对外的访问接口
// 获取器方法
public function getPosition(){
// 职位: 如果不是培训部员工, 无权查看
return $this->department === '培训部' ? $this->position : '无权查看';
}
public function getSalary(){
// 工资: 如果不是财务部员工, 无权查看
return $this->department === '财务部' ? $this->salary : '无权查看';
}
// 设置器方法
public function setSalary($value){
// 如果是设置salary工资,则必须是财务部有权限
return $this->department === '财务部' ? $this->salary = $value : '无权更新';
}
}
// 类外部
$obj = new Demo('欧阳克', '讲师', 8888, '培训部');
//$obj = new Demo('欧阳克, '讲师', 8888, '财务部');
echo $obj->name, '<br>'; // public
// protected: 外部不能访问
//echo $obj1->position;
//private: 外部不能访问
//echo $obj1->salary;
// 培训部,有权查看职位,但无权查看和设置工资
// 财务部, 无权查看职位, 但是有权查看和设置工资
echo $obj->getPosition(), '<br>';
echo $obj->getSalary(), '<br>';
echo $obj->setSalary(6666);
echo '<hr>';
```
> 继承,访问控制
```php
// 创建子类Sub, 演示权限的继承与扩展
// 如果在子类中访问父类中的私有属性private
class Sub extends Demo6{
public function salary(){
// 在子类中直接访问父类中的private成员是不允许的
// return $this->salary;
}
}
$obj = new Sub('欧阳克', '讲师', 9999, '财务部');
// 在正常的思维中, 父类中的private $salary 是只能在Demo6类中使用, 子类不能访问
echo $obj->salary(); // 报错,子类中无法访问父类中的private成员
// 但是我在父类中创建了一个私有成员的访问接口: getSalary(), 而它的访问限制中public,可以被子类继承
// 所以,通过父类中的私有成员的访问接口方法, 就可以在子类访问父类中的私有成员了,包括私有属性和方法都可以
echo $obj->getSalary();
// 不仅能访问父类的私有属性, 我还能通过父类提供的访问接口设置私有属性的值
$obj->setSalary(5656);
echo '<br>';
echo $obj->getSalary();
```
- 序言
- PHP基础
- 认识PHP
- 环境安装
- PHP语法
- 流程控制
- PHP数组
- PHP函数
- PHP类与对象
- PHP命名空间
- PHP7新特性
- PHP方法库
- PHP交互
- 前后端交互
- 项目常规开发流程
- MySQL数据库
- 会话控制
- Ajax分页技术
- 细说函数
- 类与对象
- 对象进阶
- 类与对象进阶
- OOP面向对象
- 设计模式
- 路由与模板引擎
- 异常类
- PHP爬虫
- PHP抓取函数
- PHP匹配函数
- 正则表达式
- PHP字符串函数
- 抓取实战
- PHP接口
- 了解接口
- PHP插件
- PHPSpreadsheet
- ThinkPHP6
- 安装
- 架构
- 数据库
- 数据库操作
- 视图
- 模版
- 模型
- 杂项
- 命令行
- 交互
- 微信小程序
- 介绍
- 配置
- 组件
- 交互
- API
- 其他知识
- 百度小程序
- 介绍
- 配置
- 组件
- 交互
- API
- 其他知识
- Linux
- 服务器上线流程
- 安装svn
- MySQL
- 认识MySQL
- MySQL函数
- 杂项
- composer依赖管理工具