整个面向对象文章的结构涉及到的内容模块有:
1. 面向对象和面向过程有什么区别?
2、面向对象有什么特点?
3. 什么是构造函数和析构函数?
4. 面向对象作用域有哪些类型?
5. PHP中有哪些神奇的方法?
6. 什么是对象克隆?
7. this, self 和有什么区别?
8、抽象类和接口有什么区别和联系?
9. PHP面向对象面试常见问题详解
PHP面向对象的内容将分为三篇文章来讲解完整的内容。 第一篇主要讲解一到四点的内容,第二篇主要讲解五到八点的内容,第三篇重点讲解第九点。 解释。
以下文字内容来自《PHP程序员面试笔试指南》一书。 如有转载,请保留出处:
5. PHP中有哪些神奇的方法?
在 PHP 中,保留所有以 __(两个下划线)开头的类方法作为魔术方法。 因此,在定义类方法时,不建议使用__作为方法的前缀。 下面介绍一下各个魔法方法的作用。
1. __get, __set,,
这四个方法是为类及其父类中未声明的属性而设计的。
1)访问类属性时,如果该属性可以访问,则直接返回; 如果无法访问,则会调用__get函数。
方法签名为:mixed __get ( $name )
2)设置对象的属性时,如果属性可以访问,则直接赋值; 如果无法访问,则会调用__set函数。
方法签名为: void __set ( $name , mix $value )
3) 当对不可访问的属性调用isset()或empty()时,()将被调用。
方法签名为:bool ($name)
4) 当对不可访问的属性调用 unset() 时,() 将被调用。
方法签名为:bool ($name)
需要说明的是,上述不可访问的属性包括未定义的属性,或者属性的访问控制为或(无访问权限的属性)。
下面是在另一个数组中保存对象变量的示例。
程序运行的结果是
2.,
1)构造函数,在实例化对象时调用。
2)析构函数,在对象被销毁时调用。 通常情况下,PHP只会释放该对象占用的内存和相关资源。 程序员自己请求的资源需要显式释放。 通常,需要释放资源的操作可以放在析构函数中,这样可以保证当对象被释放时,程序员申请的资源也能被释放。
例如,您可以在构造函数中打开一个文件,然后在析构函数中关闭该文件。
3. ()和()
1)($,$):当调用不可访问的方法时,会调用该方法。
2) 与()类似。 当调用的静态方法不存在或权限不足时,会自动调用()。
使用示例如下:
程序运行的结果是
调用对象方法''参数1
调用静态方法''参数2
4. ()和()
1) 在序列化期间调用。
2) 反序列化期间调用。
也就是说,执行()和()时,会先调用这两个函数。 例如,在序列化一个对象时,如果该对象有数据库连接,而你想在反序列化时恢复连接的状态,则可以通过重载这两个方法来实现。 示例代码如下:
5.()
打印对象时会调用它。 你可以在这个方法中实现你想要打印的对象的信息。 使用示例如下:
程序运行的结果是
年龄:20
6.()
引入这个魔术方法后,你可以直接将对象名作为方法来调用,它就会间接调用这个方法。 使用示例如下:
程序运行的结果是
你好世界
7.()
调用时,以 的返回值作为返回值。 使用示例如下:
程序运行的结果是
::(大批(
'名字' => '詹姆斯',
'年龄' => 20,
)) 无效的
8.()
克隆对象时会调用此方法。 PHP 提供的 () 方法对对象实例进行浅表复制。 也就是说,通过值传递的方式来复制对象中的基本数值类型。 当对象内部存在对象成员变量时,最好重写该方法来实现对这个对象变量的深拷贝。 使用示例如下:
程序运行的结果是
年龄:20 年龄:30
可以看出,对象复制后,修改一个对象的值并不会影响另一个对象。
9.()
实例化对象时,如果对应的类不存在,则调用该方法。 这种方法常见的使用方法是根据方法体中的类名找到类文件,然后导入该文件。 至此,该对象就可以成功创建了。 使用示例如下:
测试.php:
索引.php:
程序运行的结果是
你好世界
在index.php中,由于没有包含Test.php,因此在实例化Test对象时会自动调用该方法。 参数$class的值是类名Test。 该函数中会引入 Test.php ,因此 Test 对象可以正确实例化。
这种方法的缺点是需要在代码中硬编码文件路径。 当文件结构修改时,代码也必须修改。 另一方面,当多个项目需要互相引用对方的代码时,每个项目可能都有自己的,这会造成两次冲突。 当然也可以修改为一。 这会导致代码的可扩展性和可维护性较差。 从PHP5.1开始引入,可以通过r注册多个自定义方法。 使用示例如下:
索引.php
是()的默认实现,它会查找$(.php/.inc)。 除了常用的r之外,还有以下方法:
1) 默认实现:()。
2): 该方法将尝试调用所有已注册的方法来加载请求的类。
3)ns:获取所有注册的方法。
4)r:注册方法。
5)ter:取消注册的方法。
6)ons:注册并返回方法使用的默认文件扩展名。
延伸:PHP 有哪些神奇的常量?
除了魔法变量之外,PHP 还定义了以下常用的魔法常量。
1): 返回文件中的当前行号。
2):返回当前文件的完整路径。
3): 返回函数名。
4):返回类的名称。
5):返回类方法的名称。 不同的是,返回的是“class::”的形式,而返回的是“”的形式。
6):返回文件所在目录。 如果在包含文件中使用,则返回包含文件所在的目录(PHP 5.3.0 中的新功能)。
7): 返回当前命名空间的名称(区分大小写)。 该常量在编译时定义(PHP 5.3.0 中的新增功能)。
8): 返回定义Trait时的名称。 Trait 名称包括声明它们的范围(PHP 5.4.0 中的新增功能)。
6. 什么是对象克隆?
对于对象,PHP使用引用传递,也就是说对象之间的赋值操作只是分配一个引用的值,而不是整个对象的内容。 下面通过一个例子来说明引用传递的问题:
因为PHP使用引用传递,所以执行$obj2 = $obj1后,$obj1和$obj2都指向同一个内存区域(它们在内存中的关系如下图所示)。 对一个对象属性的任何修改都会使另一个对象也可见。
微信截图_216.png
在许多情况下,您希望从一个对象复制一个相同但独立的对象。 PHP提供了clone关键字来复制对象。 如下例所示:
$obj2 = clone $obj1 复制 obj1 的整个内存空间并将其存储在新的内存空间中,并让 obj2 指向这个新的内存空间。 通过clone克隆后,它们在内存中的关系如下图所示。
微信截图_226.png
此时,对obj2的修改对于obj1来说是不可见的,因为它们是两个独立的对象。
学习C++时,有深拷贝和浅拷贝的概念。 显然,PHP也存在同样的问题。 通过clone关键字克隆的对象只是对象的浅拷贝。 当对象中没有引用变量时可以使用此方法。 工作正常,但是当对象中有引用变量时,这种复制方法就会出现问题。 下面举个例子来说明:
这种情况下,这两个对象在内存中的关系如下图所示。
微信截图_234.png
从上图可以看出,虽然obj1和obj2指向的对象占用独立的内存空间,但对象的属性color仍然指向同一个存储空间。 因此,当 obj2->color 的值被修改时,就意味着 c 的值被修改,显然这个修改对于 obj1 也是可见的。 这是一个非常典型的浅拷贝的例子。 为了使两个对象完全独立,需要对对象进行深拷贝。 那么如何实施呢? PHP提供了类似的方法(类似于C++的复制构造函数)。 在该方法中复制需要深复制的属性:使用示例如下:
深拷贝后,它们在内存中的关系如图1-4所示。
微信截图_247.png
通过方法中复制对象的引用变量color,obj1和obj2完全占据了两个独立的存储空间,对obj2的修改对于obj1来说是不可见的。
7. this, self 和有什么区别?
this、self这三个关键词从字面意思上比较容易理解,分别指的是this、、。 其中,this指指向当前对象的指针(C语言中暂时用指针来描述),self指指向当前类的指针,self指指向父类的指针。
下面将详细分析这三个关键词。
##1. 这个关键字##
上面的例子中,第5行和第12行分别使用了this指针,那么this指向谁呢? 事实上,这决定了实例化时它指向谁。 例如,当第一次实例化对象时(第 16 行),this 指向 $ 对象。 那么在第12行打印时,print($this ->name) 就变成了 print($->name),输出“”。
对于第二个实例化对象, print( $this->name ) 变为 print( $->name ),因此输出“PHP5”。
因此,这是一个指向当前对象实例的指针,并不指向任何其他对象或类。
2. self 关键字
首先必须明确self指向的是类本身,即self并不指向任何实例化的对象。 一般情况下,self用于访问类中的静态变量。
上面的例子中,第4行定义了一个静态变量$,初始值为0。然后第9行调用这个值,使用self,中间使用域运算符“::”。 连接,此时调用的是类本身定义的静态变量$。 它与下面对象的实例无关,但与类有关。 不能使用this引用,而只能使用self引用,因为self指向类本身,与任何实例无关。
3、关键词
它是一个指向父类的指针,一般用来调用父类的构造函数。
10
11
12
13
14
15
16
17 号
18
19
20
21
22
23
24
25
26
27
28
29
30
上面的例子中,所有的成员属性,尤其是父类的成员属性,都是通过this来供继承类访问的。 第18行:::( "" ) 用于调用父类的构造函数来初始化父类。 因为父类的所有成员都是私有的,所以可以在继承类中直接使用this来访问父类。 类继承的属性。
8、抽象类和接口有什么区别和联系?
抽象类应用程序的定义如下:
班级 {
抽象类具有以下特点:
1)定义一些方法。 子类必须实现父类的所有抽象方法。 只有这样才能实例化子类。 否则,子类仍然是抽象类。
2)抽象类不能被实例化,其意义是要扩展的。
3)抽象方法不必实现具体功能,由子类完成。
4)当子类实现抽象类的方法时,这些方法的访问控制可以与父类中的相同,也可以具有较高的可见性,但不能具有较低的可见性。 例如,如果一个抽象方法声明为 ,那么子类中实现的方法应该声明为 or ,而不是声明为 。
5)如果抽象方法有参数,那么子类的实现也必须有相同数量的参数并且必须匹配。 但有一个例外:子类可以定义一个可选参数(这个可选参数必须有一个默认值)。 即使父类的抽象方法的声明中没有这个参数,两个声明之间也不存在冲突。 我们通过一个例子来加深理解:
10
11
12
13
程序运行的结果是
你好詹姆斯
好詹姆斯
定义抽象类时,一般需要遵循以下规则:
1)只要一个类至少包含一个抽象方法,就必须声明为抽象类。
2) 抽象方法不能包含方法体。
接口可以指定类必须实现哪些方法,但不需要定义这些方法的具体内容。 在PHP中,接口是通过关键字来实现的,这与定义类类似。 唯一的区别是接口中定义的方法都是的,并且方法没有方法体。 接口中的所有方法都是公共的,接口中也可以定义常量。 接口常量的使用方式与类常量完全相同,但不能被子类或子接口覆盖。 要实现一个接口,可以通过关键字来完成。 实现接口的类必须实现接口中定义的所有方法。 尽管PHP不支持多重继承,但一个类可以实现多个接口,只需将多个接口的名称用逗号分隔即可。 接口使用示例如下:
10
11
12
13
14
15
16
17 号
18
19
20
21
22
23
24
25
程序运行的结果是
香蕉
接口和抽象类的主要区别如下:
抽象类:PHP5支持抽象类和抽象方法。 定义为抽象的类无法实例化。 如果任何类中至少有一个方法被声明为抽象,则该类必须被声明为抽象。 定义为抽象的方法只声明其调用方法和参数,而不能定义其具体的功能实现。 抽象类是使用关键字声明的。
接口:可以指定类必须实现哪些方法,但不需要定义这些方法的具体内容。 在这种情况下,可以通过关键字定义接口,并且接口中声明的方法不能有方法体。
虽然都定义了抽象方法,但实际上它们之间还是有很大的区别。 主要区别如下:
1)接口的实现是通过关键字来实现的,而抽象类继承是通过类继承的关键字来实现的。
2)接口没有数据成员(可以有常量),但抽象类有数据成员(各种类型的成员变量),抽象类可以封装数据。
3)接口没有构造函数,但抽象类可以有构造函数。
4)接口中的方法都是类型,抽象类中的方法可以用 , 或 修饰。
5)一个类可以同时实现多个接口,但只能实现一个抽象类。