学习目标
ü OOP中内存的分配情况
ü 类的封装性
ü 类的继承性
ü 类的多态性
ü 最终类和最终方法
静态属性和静态方法
1、概述
ü static关键字修饰的属性,就是静态属性;
ü static关键字修饰的方法,就是静态方法;
ü 静态属性:就是类的属性,与类相关,与对象无关;
ü 静态方法:就是类的方法,与类相关,与对象无关;
ü 类的东西(类常量、静态属性、静态方法),通过类名::
来调用;
ü 静态属性或静态方法,在内存中只有一份,被所有对象去共享;
ü 静态属性或静态方法的好处:就是为了节省内存。例如:创建了100个对象,而静态属性只有一份。
ü 静态属性和类常量的区别:类常量在一次HTTP请求过程值永远不变;但是静态属性可以改变。
ü 静态属性和静态方法,都可以加权限控制符,而类常量没有权限。
2、举例说明
4、self关键字使用
ü $this是指向当前对象的指针,而self是指向当前类的指针;
ü $this关键字用来调用对象的属性和方法;
ü self用来调用类常量、静态属性、静态方法;
ü $this关键字只能在成员方法中使用;
ü self关键字可以在成员方法和静态方法中使用;
提示:对象可以调用:成员属性、成员方法、静态方法
提示:self可以调用:类常量、静态属性、静态方法、成员方法
综合案例
设计一个“学生类”,要求如下:
定义一个“学生类”,并由此类实例化两个“学生对象”。该类包括姓名,性别,年龄等基本信息,并至少包括一个静态属性(表示总学生数)和一个常量,以及包括构造方法和析构方法。该对象还可以调用一个方法来进行“自我介绍”(显示其中的所有属性)。构造方法可以自动初始化一个学生的基本信息,并显示“xx加入传智,当前有xx个学生”。
<?php
class Student
{
const TITLE = '313班学生类对象';
private static $stu_num = 0;
private $name;
private $age;
private $gender;
public function __construct($name, $age, $gender)
{
$this->name = $name;
$this->age = $age;
$this->gender = $gender;
self::$stu_num++; // 创建对象时总人数加一
$this->show_info();
}
private function show_info()
{
echo self::TITLE . "<br>";
echo "我是学生{$this->name},我今年{$this->age}岁了,我是{$this->gender}生。" . "<br>";
echo "该班级当前有" . self::$stu_num . "名学生。" . "<br>"; // 静态属性不能在字符串中输出
}
public function __destruct()
{
echo "{$this->name}学生被开除辣...";
self::$stu_num--; // 销毁对象时总人数减一
echo "该班级当前有" . self::$stu_num . "名学生。" . "<br>"; // 静态属性不能在字符串中输出
}
}
$stu_01 = new Student('喜羊羊', 20, '男');
// $stu_01.show_info();
$stu_02 = new Student('美羊羊', 18, '女');
// $stu_01.show_info();
// unset($stu_02);
OOP中内存的分配情况
1、为什么使用var_dump打印对象时,只能看到成员属性呢?
2、OOP中内存的分配情况
3、什么是值传递?
ü 所谓“值传递”,就是将一个变量的“数据”或“值”,复制一份,传递给另一个变量;
ü 这两个变量之间没有任何关系,修改其中一个变量的值,另一个变量的值不受影响;
ü 默认情况下,PHP值传递的数据类型有:字符串型、整型、浮点型、布尔型、数组型、NULL。
值传递在内存中如何表现?
4、什么是引用传递?
ü 所谓“引用传递”,就是将一个变量的“数据地址”,复制一份,传递给另一个变量;
ü 这两个变量指向“同一个地址”,修改其中一个变量的值,另一个变量的值也会受影响;
ü 默认情况下,PHP引用传递的数据类型有:对象和资源。
对于海量数据,使用“引用传地址”,要比“传值”速度快。
5、其它类型变量使用引用传递
如果其它类型变量使用引用传递,只需要在引用的变量前加“&”符号即可。
提示:$obj2 = $obj1 和$obj2 = &$obj1效果是一样的(数组可以使用)。
<?php
$arr_01 = [1, 2, 3];
$arr_02 = &$arr_01;
$arr_01[0] = 10;
print_r($arr_02); // Array ( [0] => 10 [1] => 2 [2] => 3 )
类的封装性
1、什么是类的封装性
ü 类的三大特性:封装性、继承性、多态性;
ü 封装性:将敏感的数据保护起来,不被外界访问;还可以理解为,将一个功能的方方面面,封装成一个整体,即类;
ü 类的封装性,是通过访问权限修饰符来实现的;
ü 提示:在项目中,属性基本都是私有的。通过公有的方法,对私有的属性进行赋值和取值。
2、访问权限修饰符介绍
ü public(公共的权限):在任何地方都可以被访问,主要是类内、类外、子类中都可以被访问。
ü private(私有的权限):只能在本类中被访问,类外和子类中无权访问。
ü protected(受保护的权限):只能在本类中和子类中被访问,在类外不能访问。
3、实例:封装一个简单的数据库工具类
<?php
// 定义一个数据库链接工具类
class ConnectDatabase
{
// 定义私有属性
private $db_host;
private $db_username;
private $db_password;
private $sheet_name;
private $charset;
private $sql_link;
// 数据库对象的初始化
public function __construct($info_arr = array())
{
// 传递变量
$this->db_host = $info_arr['host'];
$this->db_username = $info_arr['username'];
$this->db_password = $info_arr['password'];
$this->sheet_name = $info_arr['sheet_name'];
$this->charset = $info_arr['charset'];
// 启动各个服务
$this->connect_sql();
$this->select_sheet();
$this->set_charset();
}
// 链接数据库的方法
private function connect_sql()
{
if (!($this->sql_link = @mysqli_connect($this->db_host, $this->db_username, $this->db_password))) {
echo "链接数据库{$this->db_host}失败!!!";
die();
}
}
// 设置字符集的方法
private function select_sheet()
{
if (!mysqli_select_db($this->sql_link, $this->sheet_name)) {
echo "链接数据表" . $this->sheet_name . "失败!!!";
die();
}
}
// 选择数据表
private function set_charset()
{
mysqli_set_charset($this->sql_link, $this->charset);
}
// 执行sql语句
public function do_sql_query($sql_query)
{
$result = mysqli_query($this->sql_link, $sql_query);
return $result;
// 对返回结果集的类型做判断
// if (gettype($result) == 'object') {
// return $result;
// }elseif(gettype($result) == 'boolean') {
// return $result;
// } else {
// echo "数据库返回集非'object'也非'boolean',在程序未考虑到这种情况,请修改源代码。";
// die();
// }
}
// 公共构析
public function __destruct()
{
mysqli_close($this->sql_link);
}
}
$info_arr = array(
'host' => 'localhost',
'username' => 'imageSystem',
'password' => 'imageSystem',
'sheet_name' => 'imageSystem',
'charset' => 'utf8'
);
$my_database = new ConnectDatabase($info_arr);
$result = $my_database->do_sql_query("SELECT * FROM photos");
// $my_database->do_sql_query("UPDATE photos SET viewsNum=viewsNum+1 WHERE id=1");
$arrs = mysqli_fetch_all($result, MYSQLI_ASSOC);
print_r($arrs);
类的继承性
1、什么是类的继承性?
ü CSS样式继承:父标签定义的样式,可以在子标签中直接使用。相同的样式只写一遍,减少代码量。
ü 如果一个B类拥有了A类的所有特征信息,我们就说B类继承了A类。
ü A类可以称为:基础类(最顶层的类)、父类、上层类。
ü B类可以称为:最终类(最终的类)、子类、下层类。
ü 提示:如果多个子类拥有相同的属性和方法,可以将相同的属性和方法提取出来,放到“父类”中,然后,再创建子类并继承父类;这样一样,重复的代码只写一遍,减少代码量,提高工作效率。
ü 为什么要使用类的继承?是为了实现功能的升级和扩展。
ü 功能的升级:原来有的功能,在子类进行完善。
ü 功能的扩展:原来没有的功能,在子类增加新功能。
2、继承的语法格式
<?php
// 继承的语法特征
class SubClass extends ParentsClass
{
// 子类的内容定义
}
// SubClass:要创建的子类的名称
// extends:继承的关键字
// ParentsClass:SubClass要继承的父类的名称
3、单继承和多继承
ü 单继承:只能从一个父类来继承功能。如:Java、PHP、C#等。
ü 多继承:同时从多个父类来继承功能。如:C++
4、实例:单继承的简单演示
<?php
// 定义一个学生类
class Student
{
const TITLE = "给排水一班学生"; // 定义常量
protected static $stu_num = 60; // 定义静态变量
protected $class_name = '给排水';
protected static function read_my_function()
{
return __METHOD__;
}
// private function a() // 私有方法只能在本类中使用,儿子都用不了
protected function a()
{
return __METHOD__; // 返回方法的名称
}
}
// 定义一个小团体类
class FreeTeam extends Student
{
// protected $class_name = '自由社'; // 子类中重新赋值会覆盖父类中的属性或者方法
public function print_info()
{
echo self::TITLE . "<br>"; // 给排水一班学生
echo self::$stu_num . "<br>"; // 60
echo $this->class_name . "<br>"; // 给排水
echo self::read_my_function() . "<br>"; // Student::read_my_function
echo $this->a() . "<br>"; // Student::a
}
}
$demo = new FreeTeam();
$demo->print_info();
php中const
和static
的区别和联系:
const
是类中的常量,类外用define
来定义常量;const
只可以修饰类的属性,不能修饰类的方法,static
可以修饰属性,也可以修饰方法;const
和static
都属于类本身,而不属于new后的类实例.类内访问使用self::
,类外使用类名::
来访问;类内的$this
指代类实例本身,const
和static
属于类本身,所以无法用$this
访问;self::NAME
指代const
,self::$name
指代static
,const
是常量,是不需要变量符号的.static
修饰的变量,需要变量符;const
一旦被定义不可更改,static
修饰的变量是可以被更改的;static
方法中,不能使用类的普通成员和方法;这很好理解,调用静态方法的时候,不能肯定类有没有被实例化.类的普通方法中可以使用static
属性和static
方法。
5、parent关键字
ü self代表当前类,parent代表父类。
ü self和parent可以存在于所有方法(成员方法和静态方法)中。
ü self用来调用本类的内容,包括:类常量、静态属性、静态方法、成员方法;
ü parent用来调用父类的内容,包括:类常量、静态属性、静态方法、成员方法;
ü self和parent都使用范围解析符"::"来调用其它内容。
ü 语法:parent::类常量 | 静态属性 | 静态方法 | 成员方法
<?php
// 定义一个学生类
class Student
{
const TITLE = "给排水一班学生"; // 定义常量
protected static $class_name = '给排水';
}
// 定义一个小团体类
class FreeTeam extends Student
{
const TITLE = "自由社牛逼"; // 定义常量
protected static $class_name = '嘿嘿嘿';
protected $demo_num = 1;
public function print_info()
{
echo self::TITLE . "<br>"; // 自由社牛逼
echo self::$class_name . "<br>"; // 嘿嘿嘿
echo parent::TITLE . "<br>"; // 给排水一班学生
echo parent::$class_name . "<br>"; // 给排水
echo $this->demo_num;
}
}
$demo = new FreeTeam();
$demo->print_info();
类的多态
1、什么是类的多态?
ü 类的多态,就是类的多种形态。
ü 类的多态主要指方法重载或方法重写。
ü 方法重载:在同一个类中定义两个同名方法,PHP不支持。
ü 方法重写:在子类中定义一个与父类同名的方法,就是“方法重写”。
ü 为什么要重写方法?主要是实现功能的升级。父类中有的方法,子类中再用同样的名字再定义一次,一般来说,子类中方法的功能比父类更完善、更详尽。
2、方法重写的要求
- ü 子类中重写的方法,要与父类中的方法同名;
- ü 子类中重写的方法形参个数,要与父类中的同名方法形参个数一致;
- ü 子类中重写的方法类型,要与父类中同名方法类型一致;
ü 子类中重写的方法的访问权限,不能低于父类中同名方法的访问权限;
- þ 父类方法权限为public,子类同名方法权限只能是public;
- þ 父类方法权限为protected,子类同名方法权限可以是protected和public;
- þ 父类方法权限为private,子类无法继承,也无法重写。
- ü 注意:对于重写构造方法(__construct),就比较特殊,就没有形参个数的要求。
3、实例:方法重写的要求
方法重写的四点要求:
- 权限只能高,不能低;
- 静态对静态;
- 函数名称一致;
- 参数个数一致(?)。
<?php
// 定义一个学生类
class Student
{
public function demo($num_01, $num_02)
{
return $num_01 + $num_02;
}
}
// 定义一个小团体类
class FreeTeam extends Student
{
// public function demo($num_01, $num_02, $num_03) // 报错
// public function demo($num_01, $num_02, $arr = array()) // 不会报错
public function demo($num_01, $arr = array()) // 不会报错
{
//...
}
}
4、实例:商品子类重写商品基础类中的方法
<?php
// 创建商品父类
class Good
{
// 商品的私有属性
private $name;
private $price;
// 受保护的构造方法
protected function __construct($name, $price)
{
// 对属性赋值
$this->name = $name;
$this->price = $price;
}
// 构造商品基本信息
protected function print_info()
{
return "该商品{$this->name}的价格是{$this->price}";
}
}
// 创建手机商品的类,并且继承商品类
class Phone extends Good
{
// 创建手的的私有属性
private $brand;
private $origin_place;
// 重写父类商品的构造方法
public function __construct($name, $price, $brand, $origin_place)
{
//传递父类的属性
parent::__construct($name, $price);
// 对私有属性赋值
$this->brand = $brand;
$this->origin_place = $origin_place;
}
// 重写父类的商品基本信息函数
public function print_info()
{
$result_str = parent::print_info();
$result_str .= "<br>" . "手机的品牌为:{$this->brand},产地为{$this->origin_place}。";
return $result_str;
}
}
// 创建图书商品的类,并且继承商品类
class Book extends Good
{
// 创建手的的私有属性
private $author;
private $publish;
// 重写父类商品的构造方法
public function __construct($name, $price, $author, $publish)
{
//传递父类的属性
parent::__construct($name, $price);
// 对私有属性赋值
$this->author = $author;
$this->publish = $publish;
}
// 重写父类的商品基本信息函数
public function print_info()
{
$result_str = parent::print_info();
$result_str .= "<br>" . "图书的作者为:{$this->author},出版社为{$this->publish}。";
return $result_str;
}
}
$xiaomi = new Phone('小米MAX', '1999', '小米', '中国');
echo $xiaomi->print_info(); // 该商品xiaomi4的价格是1999 \n 手机的品牌为:小米,产地为中国。
$new_book = new Book('PHP从入门到放弃', '50', '武大郎', '北京出版社');
echo $new_book->print_info(); //该商品PHP从入门到放弃的价格是50 \n 图书的作者为:武大郎,出版社为北京出版社。