3.2、抽象一个类和实例化对象

PHP 同时被 3 个专栏收录
19 篇文章 0 订阅
16 篇文章 0 订阅
15 篇文章 0 订阅

一、抽象一个类
所谓抽象一个类,就是怎么创建一个类。
1、类的声明
类的声明只需要使用关键字class,有时候需要在关键字前加上修饰类的关键字,如abstract或者final等,有时候还有Trait等关键字来取代class。声明格式如下:
【修饰类的关键字】class 类名{
类中成员
}
实例:eg:

<?php
class Base {
    public function sayHello() {
        echo 'Hello ';
    }
}

类名、变量名、函数名的命名规则,需要遵循PHP自定义名称的命名规则。如果由多个单词组成,习惯上每个单词的首字母要大写。
2、类的成员属性
类的成员属性声明,需要public,protected,private,static等关键字来修饰
eg:

<?php 

class test 
{ 
    public $var1 = 1; 
    protected $var2 = 2; 
    private $var3 = 3; 
    static $var4 = 4; 
} 

3、类的成员方法
类的成员方法声明和其属性类似,只是要加关键字function,也要有关键修饰词:public,protected 和 private等。
eg:

<?php
class MyClass
{
    private $foo = FALSE;

    public function __construct()
    {
        $this->$foo = TRUE;

        echo($this->$foo);
    }
}

二、实例化对象
我们在创建类之后,并不是直接使用类,而是通过类来实例化出对象。
1、实例化对象
实例化对象需要使用的new关键字,一个类可以被实例化出多个对象,对象之间没有关联。
eg:

<?php
	class MyClass
	{
	    private $foo = FALSE;
	
	    public function __construct()
	    {
	        $this->foo = TRUE;
	
	        echo($this->foo);
	    }
	}
	
	$bar = new MyClass();

2、对象类型在内存中分配情况
内存大体上被分为四段:
1)栈空间段
该空间段主要特点是:空间小,被访问速度快,后进先出(先进后出)。用于存储占用空间不变且占用空间小的数据类型的内存段。例如整型1、10、10000在内存中占用的空间是等长的,都是32位4字节。整型、double、boolean等类型都可以存储在栈空间段。
2)堆空间段
用于存储数据长度不定长,而且占用空间很大的数据类型的数据,例如字符串、数组、对象。该段是动态分配的。
3)初始化数据段
用于存放可执行文件中已初始化的全局变量,数据段存储经过初始化的全局和静态变量
4)代码段
存放可执行文件的操作指令,就是可执行程序在内存中的镜像。代码段需要防止在运行时被非法修改,所以只允许读取操作,不允许写入(修改)操作。例如程序中的函数就存储在该内存段中。
其各段特点简要说明如下图:
这里写图片描述

实例说明:eg:

<?php
	class person{
		public $name;
		public $sex;
		public function say(){
			echo '666';
		}
	}
	$p1 = new person();
	$p2 = new person();
	$p3 = new person();
	/**$p1是第一个对象的引用变量(通过“=”把第一个对象的首地址"0xff001",赋值给了$p1),
	 * 存放的是一个十六进制的整数被存放在栈内存中。相当于一个指针指向堆里边的对象。
	 * 所以访问对象里边的成员都需要通过引用变量$p1
	 */

上段代码图形说明如下:
这里写图片描述
易混淆点:
1、当将对象赋值给另一个变量时,此时是将对象的“首地址”赋值给了另一个变量,堆内的对象并没有复制一份。
实例说明eg1:

<?php
	class test{
		public $name;
	}
	$a = new test();
	$b = $a;//这里与$b = &$a效果是一样的,仅针对对象
	$b->name = 123;
	var_dump($a->name);//输出123,说明只是将第一个对象的“首地址”赋值给了$b,改变的都是一个堆内的对象属性值
	unset($a);
	var_dump($b->name);//输出123,unset释放的只是第一个对象栈中的引用变量。
	

示例1说明图:
这里写图片描述
2、如果想得到一个对象的副本,用$a =clone $b; 用了clone后会产生一个新对象,分配内存,独立于原来的$a。
eg2:

<?php
	class test{
		public $name;
	}
	$a = new test();
	$b = clone $a;
	$b->name = 123;
	var_dump($a->name);//输出null
	unset($a);
	var_dump($b->name);//输出123

示例2图形说明:
这里写图片描述

3、当一个对象的引用断了的时候,这个对象在堆中就被当做垃圾,php就会执行垃圾回收机制,将这个对象回收,如图
这里写图片描述
4、栈内后进先出(先进后出)机制
eg3:

<?php
class test  
{  
    public $name;  
    //构造函数,当类被实例化时,会自动执行
    public function __construct($name)  
    { 
        $this -> name = $name;  
        echo $this->name."这里被执行了<br>";  
    }  
    public function __destruct()  
    {  
        echo $this->name."我被回收了<br>";  
    }  
}
$p1 = new test('王二');
$p1 = 1;  
$p2 = new test("张三");  
$p3 = new test("李四");  
/**输出 
 * 王二这里被执行了
 * 王二我被回收了
 * 张三这里被执行了 
 * 李四这里被执行了 
 * 李四我被回收了 
 * 张三我被回收了 
 */
//因为$p1引用被重新赋值,最先失去了引用,所以调用了析构函数。
//然后在这个脚本执行完成后,开始自动调调用后边对象的析构函数,
//因为$p2,$p3引用存储在栈内,因为栈内后进先出机制,最后创建的对象最先被释放,所以$p3先被销毁。

三、$this
在对象的内部,在对象的成员方法中访问自己对象的成员属性,或者对象内的其他成员方法,可以用特殊对象应用 t h i s 。 一 旦 我 们 n e w 了 一 个 对 象 , 那 么 对 象 中 的 每 个 成 员 方 法 中 都 存 在 一 个 特 殊 的 对 象 应 用 ‘ this。 一旦我们new了一个对象,那么对象中的每个成员方法中都存在一个特殊的对象应用` thisnewthis。成员方法属于那个对象,那么$this就代表哪个对象。就像你别人要访问你的性别,要用“张三是男生”,但是你自己访问自己的性别,你要用“我是男生”一样。eg3中的例子就用到了$this`。

四、构造函数和析构函数
1、构造函数__construct ([ mixed $args [, $... ]] )
具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
注意:
如果子类中定义了构造函数则不会调用其父类的构造函数。
要执行父类的构造函数,需要在子类的构造函数中调用 parent::__construct()。
如果子类没有定义构造函数则会如同一个普通的类方法一样从父类继承(假如没有被定义为 private 的话)。

eg1:

<?php
class Base {
   function __construct() {
       print "1";
   }
}

class Sub extends Base {
   function __construct() {
       parent::__construct();
       print "2";
   }
}

class OtherSub1 extends Base {
   function __construct() {
       print "2";
   }
}

class OtherSub2 extends Base {
   
}

$obj = new Base();//输出1
$obj = new Sub();//输出12
$obj = new OtherSub1();//输出2
$obj = new OtherSub2();//输出1

附:构造函数的参数
eg:

<?php
	class Base {
		public $name;
		public function __construct($name = '小王') {
		   $this->name = $name;
		}
		
		public function name(){
			echo $this->name;
		}
	}
	$name1 = new Base('小李');
	$name1->name();//输出‘小李’
	$name2 = new Base();
	$name2->name();//输出‘小王’

2、析构函数__destruct ( void )
析构函数并是不销毁什么,而是会在到某个对象的所有引用都被删除或者当对象被销毁时执行。
注意
析构函数没有参数,
和构造函数一样,父类的析构函数不会被子类中调用,
要执行父类的析构函数,必须在子类的析构函数体中显式调用 parent::__destruct()。
此外也和构造函数一样,子类如果自己没有定义析构函数则会继承父类的。
析构函数即使在使用 exit() 终止脚本运行时也会被调用。在析构函数中调用 exit() 将会中止其余对象的所有引用都被删除或者当对象被销毁的析构函数的执行。这一点,可以通过实例细细体会。

  • 1
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值