构造函数
构造函数总结
- 构造函数在对象产生时,自动执行,为对象成员变量赋初始值,也可以显示调用,但没有意义
- 构造函数的作用是完成对象成员属性的初始化任务,而不是创建对象本身
- 构造函数的权限修饰符可以是public、protected、private,一般是
public
,不写则默认public
- 构造函数一般不写返回值,自动返回
null
就行了,也可以写返回值,但没有意义 - php函数在同一个作用域不能重复定义,包括类方法,构造函数…
默认构造函数
- 如果类中中没有定义构造函数,系统会自动生成一个默认构造函数, 什么事情都不干
- 一旦自定义了构造函数,默认构造函数就被覆盖,创建对象时会使用自定义的构造函数
析构函数
析构函数总结
- 析构函数会在到某个对象(内存)的所有引用都被删除或者php程序执行完毕后执行
- 析构函数最重要的作用,就是释放对象创建的资源,如:数据库链接,文件句柄…
- 析构函数都是public,且没有形参
- 析构函数和构造函数都是是由系统调用的
析构函数其他说明
- 当没有变量指向某个对象(内存)时,该对象(内存)会被销毁
- 在销毁对象(内存)前,析构函数会被调用
- 析构函数不是销毁对象本身,而是在对象销毁前给程序员一个机会,可以让程序员去及时的回收该对象创建的资源。比如数据库链接等
将对象的引用删除
- 使用
unset()
将对象名删除 - $对象名 = null
- $对象名 = ‘abc’
显示销毁与隐示销毁
- 上面写的三种方式都是显示销毁,显示销毁即程序员主动删除对象引用
- 如果程序员不去显示销毁对象,那么程序执行完毕后,这个对象就会被系统销毁,即隐示销毁
php文件执行流程
特点: 一次请求对应一次回应,然后整个空间全部销毁
优势:极少存在内存泄漏,因为即使程序中的资源、数据库…都没有关闭,程序执行完毕后系统会自动销毁
流程分析:
- 浏览器请求访问test.php文件
- 该请求会发至apache
- apache会根据自己的机制找到test.php文件
- 然后在内存中生成代码区,栈区,数据区
- 将全部代码调入数据区编译,将每句代码依次扔进栈区执行,结果存入数据区
- 代码全部执行完毕,将执行结果返回给apache,此时,内存区的所有数据全部销毁
- apache拿到页面数据返回给浏览器,浏览器解析,显示给用户
代码示例
表面讲的析构函数,但更多的是要理解php的运行及内存回收机制
- 隐示销毁示例
// 先创建的对象后销毁,后创建的对象先销毁
class People {
function __construct($name) {
$this->name = $name;
}
function __destruct() { // 析构函数
echo '析构函数执行',$this->name,'<br>';
}
}
$p1 = new People('小和尚');
echo '=======','<br>';
$p2 = new People('大和尚');
$p3 = new People('老和尚');
/*
执行结果:
=======
析构函数执行老和尚
析构函数执行大和尚
析构函数执行小和尚
结论:隐示销毁,先创建的对象后销毁,后创建的对象先销毁
原因:栈的特点是先入后出,类似饭盒结构
*/
- 显示销毁示例
// 需求:p1对象用完后,需要马上销毁,可以节省内存,提高效率
class People {
function __construct($name) {
$this->name = $name;
}
function __destruct() { // 析构函数
echo '析构函数执行',$this->name,'<br>';
}
}
$p1 = new People('小和尚');
$p1 = null; // 显示销毁 unset($p1) $p1=2 一样的效果或
echo '=======','<br>';
$p2 = new People('大和尚');
$p3 = new People('老和尚');
/*
执行结果:
析构函数执行小和尚
=======
析构函数执行老和尚
析构函数执行大和尚
分析:$p1 = null; p1指向#1,#1指向数据空间,销毁p1
此时不再有对象指向#1,#1的引用为0,立即触发析构函数
*/
- 测试代码
class People {
function __construct($name) {
$this->name = $name;
}
function __destruct() { // 析构函数
echo '析构函数执行',$this->name,'<br>';
}
}
$p1 = new People('小和尚');
/*// 案例1
$pp = $p1;
$p1 = null;
echo '=======','<br>';*/
/*// 案例2
$pp = &$p1;
$p1 = null;
echo '=======','<br>';*/
/*// 案例3
$pp = $p1;
unset($p1);
echo '=======','<br>';*/
/*// 案例4
$pp = &$p1;
unset($p1);
echo '=======','<br>';*/
$p2 = new People('大和尚');
$p3 = new People('老和尚');
析构函数作用,回收对象创建的资源
释放数据连接,在销毁对象(内存)圈闭引用后,销毁了对象,但是打开的资源仍然可以用,此时就可以用析构函数去关闭资源
- 关于析构函数释放资源的问题,如果对运行效率,没有很高的要求,完全可以不使用析构函数,程序运行完毕也会自动关闭
- 如果不确定后续代码是否还会用到该资源,也不建议使用析构函数关闭资源
- 项目有特殊明确要求时,我们可以使用析构函数,在显示销毁对象时,在析构函数中,关闭资源
class MySql{
public $conn;
public function __construct($host,$user,$pwd){
$this->conn = mysqli_connect($host,$user,$pwd);
}
public function __destruct(){
echo '析构函数被调用','<br>';
// 这里强制关闭资源!
mysqli_close($this->conn);
}
}
$obj = new MySql('localhost','root','');
// 测试数据库已连接
var_dump($obj->conn);
mysqli_select_db($obj->conn,'test');
// 查询数据
$sql = 'select * from msg';
$res = mysqli_query($obj->conn,$sql);
while ($row = mysqli_fetch_assoc($res)){
print_r($row);
echo '<br>';
}
// 现在销毁这个对象内存 没变量指向 销毁
$obj = null;
// 在执行下面无关代码之前 要求数据库销毁
echo '1','<br>';
echo '2','<br>';
// 但是 灵异现象出现 这里仍然可以调用资源
$sql = 'select * from msg';
$res = mysqli_query($obj->conn,$sql);
while ($row = mysqli_fetch_assoc($res)){
print_r($row);
echo '<br>';
}
垃圾回收机制
- 在php中,当一个对象(内存)没有没有任何引用只想他时,就会成为一个垃圾对象,php将启用垃圾绘回收器将对象销毁
- 当程序执行完毕退出前,php也将启用垃圾绘回收器,销毁对象
内存图
class People {
$this->age = 18;
}
$p1 = new People();
unset($p1)
:p1不在指向#1,虽然#1还指向对象内存,但#1没有任何意义,对象内存变为垃圾对象
$p1 = null
:p1置空,标识符#1变为null,不再指向对象内存,对象内存变为垃圾对象
$p2=$p1
$p1 = null
:p1置空,标识符#1变为null,不再指向对象内存,但p2仍然通过复制的#1指向对象内存,对象内存不销毁