PHP面向对象(构造方法、析构方法)

  本节主要讲解 PHP面向对象中的 魔术方法 中的其中两种,构造方法析构方法,主要从以下三部分总结:

一、__construct 构造方法

二、__destruct 析构方法

三、构造方法 和 析构方法 【综合练习】



一、 __construct 构造方法

1) 格式:

修饰符 function __construct()
{
    方法体
}

实例1:构造方法执行

class cc
{
    public $name = '串串';
    public $age = 18;

    public function __construct()
    {
        echo "预备工作,准备干掉串串<br>";
    }
}

// 实例化
$a = new cc;

运行结果:

construct 构造方法

2) 特性

  ① 在实例化的瞬间,自动触发;

  ② 无返回值;

  ③ public 可以省略;

  ④ 构造方式 不允许重复。

3) 调用构造方法的两种方式:

① 自动调用

// 实例化
$a = new cc;

② 手动调用

$a->__construct();

4) 作用:

​ 常用于做 赋初始值 (完成一些对象的初始化工作)

实例2:构造方法 赋初始值

class cc
{
    public $name;
    public $age;

    // 此处的 $name是形参,与属性$name无关
    public function __construct($name, $age)
    {
        echo "预备工作,准备干掉串串";

        // 将 形参 给了 属性
        $this->name = $name;
        var_dump($this->name);

        echo "<hr>";
    }

    public function test1()
    {
        echo '<br>测试1<br>';
        echo $this->name;
        echo "<hr>";
        return $this;
    }
}

// 实例化
$a = new cc('串串', 18);
echo $a->name;
echo "<hr>";

$a->test1();

运行结果:

构造方法(赋初始值)

如何 将两个变量中的方法通用?

答案: 将 变量 变成 属性

class cc
{
    public $name;
    public $age;

    // 此处的 $name 与属性 $name无关
    public function __construct($name, $age)
    {
        // 将 形参 给了 属性
        $this->name = $name;
        $this->age = $age;
    }

    public function test1()
    {
        // 如何 将两个方法中的 变量通用?
        // 答案:将 变量 变成 属性
        echo $this->name;
        echo $this->age;
    }
}

实例3:如何 将两个方法中的 变量通用?

class cc
{
    public $name;
    public $age;

    // 此处的 $name是形参,与属性 $name 无关
    public function __construct($name, $age)
    {
        echo "预备工作,准备干掉串串<br>";

        // 将 形参 给了 属性
        $this->name = $name;
        var_dump($this->name); echo "<br>";
        $this->age = $age;
        var_dump($age); 

        echo "<hr>";
    }

    public function test1()
    {
        echo "<br>测试1<br>";
        echo $this->name;
        echo "<br>";
        // 如何 将两个方法中的变量 通用?
        // 答案:将变量 变成 属性 
        echo $this->age;
        echo "<br>";
        return $this;
    }
}

// 实例化
$a = new cc('串串', 18);
echo $a->name;
echo "<hr>";

$a->test1();

运行结果:

构造方法(两个方法中的变量通用)
注意事项:

​  没有构造方式时,如果方法名 和 类名相同,自动调用方法;有构造方法时,方法名不会自动调用。【建议:尽量方法名和类名不要相同】

实例4: 无构造方法时

class cc
{
    public $name;
    public $age;

    public function cc()
    {
        echo "测试1<br>";
    }
}

$a = new cc();
echo 222;

运行结果:可以看到,都没有构造方法的时候,类名方法名 相同会报错。

构造方式 不可重复

实例5:有构造方法时

class cc
{
    public $name;
    public $age;

    public function __construct()
    {
        echo "预备工作,准备干掉串串<br>";
    }

    public function cc()
    {
        echo "测试1<br>";
    }
}

$a = new cc();
echo 222;

运行结果:有构造方法时,方法名不会被调用,但是尽量不要让方法名和类名同名,否则没有构造方法的时候,是会报错的。

有构造方法时
不成文规定:

​  构造方法写在属性的最后面,方法的最前面。

class cc
{
    // 属性
    public $name;
    public $age;

    // 构造方法
    public function __construct()
    {
        echo "构造方法";
    }

    // 方法
    public function test()
    {
        echo "测试1<br>";
    }
}


二、__destruct 析构方法

  ​相当于 遗嘱 die()

​  在整个程序结束之前执行

1) 格式:

public function __destruct()
{
    方法体
}

2) 特性:

① 当对象被销毁时,自动调用;

  • 程序自然结束时,对象会自动消失;
  • 对象变量 被 unset;
  • 对象变量 被覆盖

② 不能有参数;

实例1:程序自然结束时

class cc
{
    public $name;
    public $age;

    public function test1()
    {
        echo "测试1<br>";
    }

    public function __destruct()
    {
        echo "老母鸡";
    }
}

$a = new cc;

$a->test1();

echo "小母鸡<br>";

运行结果:

程序自然结束时

实例2:对象变量 被 unset时

class cc
{
    public $name;
    public $age;

    public function test1()
    {
        echo "测试1<br>";
    }

    public function __destruct()
    {
        echo "老母鸡<br>";
    }
}

$a = new cc;
$a->test1();

unset($a);

echo "小母鸡<br>";

运行结果:
对象变量 被 unset
实例3:对象变量 被覆盖

class cc
{
    public $name;
    public $age;

    public function test1()
    {
        echo "测试1<br>";
    }

    public function __destruct()
    {
        echo "老母鸡<br>";
    }
}

$a = new cc;
$a->name;

$a = 10;

echo "小母鸡<br>";

运行结果:

对象变量 被覆盖

3) 作用:

  ​给对象写临时前的遗嘱。(即对象在销毁之前的清理工作)

不成文规定:

​  析构方法 一般写在方法的最后面

class cc
{
    public $name;
    public $age;

    // 方法
    public function test1()
    {
        echo "测试1<br>";
    }

    // 析构方法
    public function __destruct()
    {
        echo "老母鸡<br>";
    }
}


三、构造方法 和 析构方法 【综合练习】

实例1: 构造方法 和 析构方法 (综合练习1)

class test
{
    // 构造方法
    public function __construct()
    {
        static $x = 0;
        $x++;
        echo $x."<br>";
    }

    // 方法
    public function hello()
    {
        echo "母鸡<br>";
    }

    // 析构方法
    public function __destruct()
    {
        static $y = 10;
        $y++;
        echo $y."<br>";
    }
}

$a = new test; // 1 
$a->hello(); // 母鸡 
$a = new test; // 2 11 12

运行结果:

构造方法 和 析构方法 (综合练习1)
分析结果:

  ① $a = new test; 先 执行构造方法,输出 1,由于后面还有代码,因此不会 执行析构方法;

  ② $a->hello(); 输出 母鸡;

  ③ $a = new test; 等号的优先级是先做右边,因此先执行右边的 new test,new 的一瞬间,再次执行 构造方法,由于构造方法中,已经输出1,再次执行 输出 2

​  ④ 再执行左边,此时第一个 $a 被覆盖,因此触发 第一次 new test 的析构方法,输出 11;(执行 第一个 new test的析构)

​  ⑤ 由于下面再没有代码执行,因此触发第二次析构方法(此时已经输出为11),再次执行 输出 12 (执行第二个 new test的析构)

执行步骤归纳:

​  为了方便归纳总结:现将代码继续排序:

   a. $a = new test;

   b. $a->hello();

   c. $a = new test;

  1) a 中的 构造方法,输出 1
  2) b 中的 方法,输出 母鸡
  3) c 中的 构造方法, 输出 2;(执行的是 c中的右边)
  4) a 中的 析构方法, 输出 11;(由于c 中的 $a覆盖了 a中的$a,因此触发a 中的析构方法)
  5) c 中的 析构方法,输出12.

实例2:构造方法 和 析构方法 (综合练习2)

class test
{
    // 构造方法
    public function __construct()
    {
        static $x = 0;
        $x++;
        echo $x."<br>";
    }

    // 方法
    public function hello()
    {
        echo "母鸡<br>";
    }

    // 析构方法
    public function __destruct()
    {
        static $y = 10;
        $y++;
        echo $y."<br>";
    }
}

$a = new test;
$a->hello();
$b = new test;

运行结果:

这里写图片描述
执行步骤归纳:

  为了方便归纳总结:现将代码继续排序:

   a. $a = new test;

   ​b. $a->hello();

   c. $b = new test;

  1)a 中的 构造方法,输出1
  2) b 中的 方法, 输出母鸡
  3) c 中的 构造方法,输出2;(等号的优先级,先执行右边,实例化的同时,触发 构造方法)
  4) c 中的 析构方法,输出11;(等号的左边,由于以下没有代码,触发 c中的 析构方法,根据 数据结构中的 “后进先出” 执行 c中的析构方法)
  5)a 中的 析构方法, 输出12.

注:虽然和先前的执行结果是一样的,但是 原理不同,遵循的是 数据结构中的堆栈思想(先进后出).

实例3:构造方法 和 析构方法 (综合练习3)

class test
{
    // 构造方法
    public function __construct()
    {
        static $x = 0;
        $x++;
        echo $x."<br>";
    }

    // 方法
    public function hello()
    {
        echo "母鸡<br>";
    }

    // 析构方法
    public function __destruct()
    {
        static $y = 10;
        $y++;
        echo $y."<br>";
    }
}

$a = new test;
$a->hello();
$b = new test;
$a->hello();
$b = new test;

运行结果:

构造方法 和 析构方法 (综合练习3)

分析结果:

​  ① $a = new test; (实例化的时候,执行 构造方法,输出 1),由于下面还有代码,则继续执行;

​  ② $a->hello(); 输出 母鸡

  ③ $b = new test; (根据等号的优先级,先执行左边,实例化的时候,再次执行 构造方法 ,先前输出1,此时输出 2),由于下面还有代码,则继续执行;

  ④ $a->hello(); 输出 母鸡

​  ⑤ $b = new test; (根据等号的优先级,先执行左边,实例化的时候,再次执行 构造方法,先前输出3, 此时输出 3);

​  ⑥ 再执行右边,由于 此处的 $b,覆盖了 ③ 中的 $b,因此触发了 ③中的析构方法,输出 ③中的 $b, 输出为 11;

​  ⑦ 由于⑤ 以下已经没有代码,因此触发了⑤中的 析构方法,由于先前输出 11,此处输出 12

​  ⑧ 最后触发① 中$a的 析构方法,先前输出12, 此处 输出 13.

执行步骤归纳:

​  为了方便归纳总结:现将代码继续排序:

​   a. $a = new test;

   b. $a->hello();

   c. $b = new test;

   d. $a->hello();

   e. $b = new test;

  1) a 中的 构造方法,输出1
  2) b 中的 方法,输出 母鸡
  3) c 中的 构造方法,输出 2
  4) d 中的 方法, 输出 母鸡
  5) e 中的 构造方法,输出 3
  6) c 中的 析构方法, 输出 11;(由于e中的 $b覆盖了 c中的$b,触发了 c中的析构方法)
  7) e 中的 析构方法, 输出 12;(由于e下面没有代码执行了)
  8) a 中的 析构方法,输出 13

实例4:构造方法 和 析构方法(综合练习4)

class test
{
    // 构造方法
    public function __construct()
    {
        static $x = 0;
        $x++;
        echo $x."<br>";
    }

    // 方法
    public function hello()
    {
        echo "母鸡<br>";
    }

    // 析构方法
    public function __destruct()
    {
        static $y = 10;
        $y++;
        echo $y."<br>";
    }
}

$a = new test;
$a->hello();
$a = new test;
$a->hello();
$a = new test;

运行结果:

构造方法 和 析构方法 (综合练习4)

分析结果:

  ① $a = new test;(实例化的时候,触发 构造方法,输出1

  ② $a->hello(); (输出母鸡

  ③ $a = new test;(第二个 new test),根据等号的优先级,先执行右边;当实例化的时候,会触发 构造方法,先前输出1,此处输出2

  ④ 执行 第二个 new test的左边(即第二个$a),由于会把 第一个\$a覆盖,会触发 第一个\$a的 析构方法,输出11

  ⑤ $a = hello(); (输出母鸡

  ⑥ $a = new test(第三个 new test),根据等号的优先级,先执行右边;当实例化的时候,会触发 构造方法,先前输出2,此处输出3

  ⑦ 执行 第三个new test的左边(即第三个$a),由于会把 第二个\$a覆盖,会触发 第二个\$a的 析构方法,先前输出11,此处输出12

  ⑧ 由于 第三个 new test下面再无代码,因此会触发 第三个$a的 析构方法,先前输出12,此处输出13.

执行步骤归纳:

  为了方便归纳总结:现将代码继续排序:

   a. $a = new test;

   b. $a->hello();

   c. $a = new test;

​   d. $a->hello();

​   e. $a = new test;

  1)a 中的 构造方法,输出1
  
  2) b 中的 方法,输出母鸡
  
  3) c 中的 构造方法, 输出2;(等号的优先级,先执行右边,会触发 构造方法)

  4) a 中的 析构方法,输出11;(执行c中的左边,左边的$a 会覆盖 a中的 $a,因此触发 a中的析构方法)

  5) d 中的 方法, 输出母鸡

  6) e 中的 构造方法,输出3;(等号的优先级,先执行右边,会触发 构造方法)

  7) c 中的 析构方法, 输出12;(执行e中的左边,左边的$a 会覆盖 c中的 $a,因此触发 c中的析构方法)

  8) e 中的 析构方法,输出13;(e下面再无代码,会触发 e中的析构方法)

以上只是我学习过程中涉及到的,有缺漏处,之后补充。

猜你喜欢

转载自blog.csdn.net/studyphp123/article/details/81778265