批改状态:合格
老师批语:
面向对象就是把生活中要解决的问题都用对象的方式进行存储:把所有的数据用属性、方法表现出来。对象之间的互动是通过方法的调用完成互动。
class User{// 成员属性public $name;private $salary;protected $age;public function __construct($salary, $age){// $this代表本对象$this->salary = $salary;$this->age = $age;}// 成员方法public function salary(){return $this->salary;}}
对象:一个类的实例(Instance)
类的实例化为对象时使用关键字new,new之后紧跟类的名称和一对圆括号
-> 符号来访问
$name = '灭绝';$salary = 20000;$age = 18;// new 实例化 得到对象引用$mj = new User($salary, $age);// 访问对象的属性和方法$mj->name = $name;echo $mj->name; // 灭绝echo $mj->salary(); // 20000
对象的属性和方法有三种访问权限:
public是公有的类成员,可以在任何地方被访问,可以被类以及子类或者对象都可以访问
class User1{public $name;public function sayHello(){echo "Hello " . $this->name;}}$mj = new User1();$mj->name = '灭绝';echo $mj->name; // 灭绝echo $mj->sayHello(); //Hello 灭绝
注意:尽量不要使用公共属性,因为直接访问公共属性不能强制性地检验数据有效性。例如,无法阻止用户给 name 这样赋值:$mj->name = ‘12345’;,解决方法:将属性设为私有属性,然后定义公共方法来调用是由属性。
private私有的类成员,只能被自身访问,不能被子类继承,也不能被对象访问,只能在自身通过封装让外界访问(例如在类里面定义一个公开方法来调用私有属性);
class User{private $name;public function setName($name){if ($this->validateName($name)){$this->name = $name;} else {echo "name 格式有误!";}}public function getName(){echo $this->name;}// 数据验证方法,仅对象内部可见,外部无法访问private function validateName($name){if ($name == '' || is_numeric($name)){return false;} else if (strlen($name) < 2 || strlen($name) > 8){return false;} else {return true;}}}$mj = new User();$mj->setName('灭绝');$mj->getName(); // 灭绝
protected 受保护的类成员,与 private 类似,区别是可以被子类继承,可以被其自身以及继承的子类访问,但是不能被对象访问,只能通过封装的方式让对象访问
构造方法可以在对象实例化时自动运行,作用是:1,创建实例的初始化状态;2,可以给私有/受保护的属性初始化赋值。
构造方法必须是公共方法(public)。
定义构造方法关键字:__construct
class User{// 成员属性public $name;private $salary;protected $age;public function __construct($salary, $age){// $this代表本对象$this->salary = $salary;$this->age = $age;}// 成员方法public function salary(){return $this->salary;}}// 实例化时自动调用构造方法,将传入的参数赋值给属性 $salary, $age$mj = new User($salary, $age);// 属性 $name 没有在构造方法中赋值,需要手动赋值$mj->name = $name;
继承的好处:
子类:
// 父类class Product{public $name;protected $price;protected $num;public function __construct($name, $price, $num){$this->name = $name;$this->price = $price;$this->num = $num;}// 普通方法public function show(){// 特殊的对象引用 完成对象成员间的互相访问// 注意:界定符结尾标记必须顶行写,前面不能有任何输出,否则出错!// 界定符结尾标记后面也不能有注释return <<<SHOW1. 品名:$this->name2. 价格:$this->price3. 数量:$this->numSHOW;}}// 子类class Son extends Product{// 扩展public $brand;// overwrite 重写public function __construct($name, $price, $num, $brand){// parent:: 调用父类成员parent::__construct($name, $price, $num);$this->brand = $brand;}// 重写show方法public function show(){return <<<SHOW1. 品名:$this->name2. 价格:$this->price3. 数量:$this->num4. 品牌:$this->brandSHOW;}// 功能扩展public function total(){return "$this->name,数量为{$this->num},总计" . ($this->price * $this->num) . '元';}}// 子类实例化及调用成员$son1 = new Son('四件套', 289, 400, '法系');echo $son1->brand; // 法系echo $son1->show(); // 1. 品名:四件套 2. 价格:289 3. 数量:400 4. 品牌:法系echo $son1->total(); // 四件套,数量为400,总计115600元
class View{/*** 模板变量*/protected $data = [];// !当访问当前环境下未定义或不可访问的类属性时 ,重载方法__get会被调用。public function __get($name){return $this->data[$name];}// !当给当前环境下未定义或不可访问的类属性赋值时 ,重载方法__set会被调用。public function __set($name, $value){$this->data[$name] = $value;}// 自定义的赋值方法优先级大于 __setpublic function assign($name, $value = null){if (is_array($name)) {// array_merge() 将一个或多个数组中的值附加在前一个数组的后面。返回作为结果的数组$this->data = array_merge($this->data, $name);} else {$this->data[$name] = $value;}return $this;}// !当访问当前环境下未定义或不可访问的类普通方法时 ,重载方法__call会被调用。public function __call($name, $args){if ($name == 'show') {var_dump($this->data);} else if ($name == 'sum') {return array_sum($args);} else {echo '没有这个方法';}}}$v = new View;// 调用 __set 方法,给未定义属性赋值$v->username = 'peter';// 调用 __get 方法,访问未定义属性echo $v->username; // peter// 自定义的赋值方法优先级大于 __set$v->assign('username', 'admin');echo $v->username; // admin// 调用 __call 方法,访问未定义方法$v->hello(); // 没有这个方法// show()、sum() 方法不可以直接访问,通过 __call 方法访问$v->show(); // array(1) { ["username"]=> string(5) "admin" }echo $v->sum(10, 20, 60); // 90// 通过回调方法访问 __call 方法echo call_user_func([$v, 'sum'], 10, 20, 40); // 70echo call_user_func_array([$v, 'sum'], [10, 20, 80]); // 110
定义类加载器文件 autoload.php
// autoload.phpspl_autoload_register(function ($className) {$classFile = __DIR__ . DS . 'class' . DS . $className . '.php';if (is_file($classFile) && file_exists($classFile)) require $classFile;});
在页面引入加载器,不用一个一个 require 所需的 class 文件
const DS = DIRECTORY_SEPARATOR;require __DIR__ . DS . 'autoload.php';// 接下来用到的类都会自动加载$mj = new User($salary, $age);$i = new Product('iphone 12 promax', 6000, 12);$son1 = new Son('四件套', 289, 400, '法系');
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号