__construct() 和 __destory() 在 PHP 中需要注意的地方-php教程

资源魔 30 0

根本上一切的编程言语正在类中城市有结构函数以及析构函数的概念。结构函数是正在函数实例创立时能够用来做一些初始化的工作,而析构函数则能够正在实例销毁前做一些清算工作。绝对来讲,结构函数咱们应用患上十分多,而析构函数则普通会用正在开释资本上,比方数据库链接、文件读写的句柄等。

结构函数与析构函数的应用

咱们先来看看失常的结构与析构函数的应用:

class A
{
    public $name;
    public function __construct($name)
    {
        $this->name = $name;
        echo "A:结构函数被挪用,{$this->name}", PHP_EOL;
    }
    public function __destruct()
    {
        echo "A:析构函数被挪用,{$this->name}", PHP_EOL;
    }
}
$a = new A('$a');
echo '-----', PHP_EOL;
class B extends A
{
    public function __construct($name)
    {
        $this->name = $name;
        parent::__construct($name);
        echo "B:结构函数被挪用,{$this->name}", PHP_EOL;
    }
    public function __destruct()
    {
        parent::__destruct();
        echo "B:析构函数被挪用,{$this->name}", PHP_EOL;
    }
}
class C extends A
{
    public function __construct($name)
    {
        $this->name = $name;
        echo "C:结构函数被挪用,{$this->name}", PHP_EOL;
    }
    public function __destruct()
    {
        echo "C:析构函数被挪用,{$this->name}", PHP_EOL;
    }
}
class D extends A
{
}
// unset($a); // $a的析构提前
// $a = null; // $a的析构提前
$b = new B('$b');
$c = new C('$c');
$d = new D('$d');
echo '-----', PHP_EOL;exit;
// A:结构函数被挪用,$a
// -----
// A:结构函数被挪用,$b
// B:结构函数被挪用,$b
// C:结构函数被挪用,$c
// A:结构函数被挪用,$d
// -----
// A:析构函数被挪用,$d
// C:析构函数被挪用,$c
// A:析构函数被挪用,$b
// B:析构函数被挪用,$b
// A:析构函数被挪用,$a

下面的代码是否是有一些内容以及咱们的预期没有太同样?没事,咱们一个一个来看:

子类假如重写了父类的结构或析构函数,假如没有显式地应用parent::__constuct()挪用父类的结构函数,那末父类的结构函数没有会执行,如C类子类假如不重写结构或析构函数,则默许挪用父类的析构函数假如没显式地将变量置为NULL或许应用unset()的话,会正在剧本执行实现落后行挪用,挪用程序正在测试代码中是相似于栈的方式进步前辈后出(C->B->A,C先被析构),但正在效劳器环境中则纷歧定,也就是说程序纷歧定固定

析构函数的援用成绩

当工具中蕴含本身互相的援用时,想要经过设置为NULL或许unset()来挪用析构函数可能会呈现成绩。

class E
{
    public $name;
    public $obj;
    public function __destruct()
    {
        echo "E:析构函数被挪用," . $this->name, PHP_EOL;
        echo '-----', PHP_EOL;
    }
}
$e1 = new E();
$e1->name = 'e1';
$e2 = new E();
$e2->name = 'e2';
$e1->obj = $e2;
$e2->obj = $e1;

相似于这样的代码,$e1以及$e2都是E类的工具,他们又各矜持有对方的援用。其实简略点来讲的话,本人持有本人的援用城市呈现相似的成绩。

$e1 = new E();
$e1->name = 'e1';
$e2 = new E();
$e2->name = 'e2';
$e1->obj = $e2;
$e2->obj = $e1;
$e1 = null;
$e2 = null;
// gc_collect_cycles();
$e3 = new E();
$e3->name = 'e3';
$e4 = new E();
$e4->name = 'e4';
$e3->obj = $e4;
$e4->obj = $e3;
$e3 = null;
$e4 = null;
echo 'E destory', PHP_EOL;

假如咱们没有关上gc_collect_cycles()那一行的正文,析构函数执行的程序是这样的:

// 没有应用gc收受接管的后果
// E destory
// E:析构函数被挪用,e1
// -----
// E:析构函数被挪用,e2
// -----
// E:析构函数被挪用,e3
// -----
// E:析构函数被挪用,e4
// -----

假如咱们关上了gc_collect_cycles()的正文,析构函数的执行程序是:

// 应用gc收受接管后后果
// E:析构函数被挪用,e1
// -----
// E:析构函数被挪用,e2
// -----
// E destory
// E:析构函数被挪用,e3
// -----
// E:析构函数被挪用,e4
// -----

能够看出,必需要让php应用gc收受接管一次,确定工具的援用都被开释了之后,类的析构函数才会被执行。援用假如不开释,析构函数是没有会执行的。

结构函数的低版本兼容成绩

正在PHP5之前,PHP的结构函数是与类名同名的一个办法。也就是说假如我有一个F类,那末function F(){}办法就是它的结构函数。为了向低版本兼容,PHP仍然保存了这个特点,正在PHP7当前假如有与类名同名的办法,就会报过期正告,但没有会影响顺序执行。

class F
{
    public function f() 
    {
        // Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; F has a deprecated constructor 
        echo "F:这也是结构函数,与类同名,没有区别巨细写", PHP_EOL;
    }
    // function F(){
    //     // Deprecated: Methods with the same name as their class will not be constructors in a future version of PHP; F has a deprecated constructor 
    //     echo "F:这也是结构函数,与类同名", PHP_EOL;
    // }
    // function __construct(){
    //     echo "F:这是结构函数,__construct()", PHP_EOL;
    // }
}
$f = new F();

假如__construc()以及类同名办法同时存正在的话,会优先走__construct()。另外需求留意的是,函数名没有区别巨细写,以是F()以及f()办法是同样的城市成为结构函数。同理,由于没有区别巨细写,以是f()以及F()是不克不及同时存正在的。当然,咱们都没有倡议应用类同名的函数来做为结构函数,究竟结果曾经是过期的特点了,说没有定哪天就被勾销了。

结构函数重载

PHP是没有运转办法的重载的,只支稳健写,就是子类重写父类办法,但不克不及界说多个同名办法而参数没有同。正在Java等言语中,重载办法十分不便,特地是正在类实例化时,能够不便地完成多态才能。

$r1 = new R(); // 默许结构函数
$r2 = new R('arg1'); // 默许结构函数 一个参数的结构函数重载,arg1
$r3 = new R('arg1', 'arg2'); // 默许结构函数 两个参数的结构函数重载,arg1,arg2

就像上述代码同样,假如你测验考试界说多个__construct(),PHP会很间接地通知你运转没有了。那末有无此外办法完成上述代码的性能呢?当然有,不然咱也没有会写了。

class R
{
    private $a;
    private $b;
    public function __construct()
    {
        echo '默许结构函数', PHP_EOL;
        $argNums = func_num_args();
        $args = func_get_args();
        if ($argNums == 1) {
            $this->constructA(...$args);
        } elseif ($argNums == 2) {
            $this->constructB(...$args);
        }
    }
    public function constructA($a)
    {
        echo '一个参数的结构函数重载,' . $a, PHP_EOL;
        $this->a = $a;
    }
    public function constructB($a, $b)
    {
        echo '两个参数的结构函数重载,' . $a . ',' . $b, PHP_EOL;
        $this->a = $a;
        $this->b = $b;
    }
}
$r1 = new R(); // 默许结构函数
$r2 = new R('arg1'); // 默许结构函数 一个参数的结构函数重载,arg1
$r3 = new R('arg1', 'arg2'); // 默许结构函数 两个参数的结构函数重载,arg1,arg2

绝对来讲比Java之类的言语要费事一些,然而也的确是完成了相反的性能哦。

结构函数以及析构函数的拜访限度

结构函数以及析构函数默许都是public的,以及类中的其余办法默许值同样。当然它们也能够设置成private以及protected。假如将结构函数设置成非公共的,那末你将无奈实例化这个类。这一点正在单例模式被宽泛使用,上面咱们间接经过一个单例模式的代码看来。

class Singleton
{
    private static $instance;
    public static function getInstance()
    {
        return self::$instance == null ? self::$instance = new Singleton() : self::$instance;
    }
    private function __construct()
    {
    }
}
$s1 = Singleton::getInstance();
$s2 = Singleton::getInstance();
echo $s1 === $s2 ? 's1 === s2' : 's1 !== s2', PHP_EOL;
// $s3 = new Singleton(); // Fatal error: Uncaught Error: Call to private Singleton::__construct() from invalid context

当$s3想要实例化时,间接就报错了。对于单例模式为何要让内部无奈实例化的成绩,咱们能够看看以前的设计模式零碎文章中的单例模式。

总结

没想到咱们每天用到的结构函数还能玩出这么多把戏来吧,一样平常正在开发中比拟需求留意的就是子类承继时对结构函数重写时父类结构函数的挪用成绩和援用时的析构成绩。

保举教程:《PHP教程》

以上就是__construct() 以及 __destory() 正在 PHP 中需求留意之处的具体内容,更多请存眷资源魔其它相干文章!

标签: php php开发教程 php开发资料 php开发自学

抱歉,评论功能暂时关闭!