PHP 面试专栏正式起更,每周一、三、五更新,提供最好最优质的 PHP 面试内容。继上一篇“PHP 面试常考内容之面向对象(2)”发表后,今天更新面向对象的最后一篇(3)。需要(1),(2)的可以直接点文字跳转获取。PHP 面试常考内容之面向对象(1)整个面向对象文章的结构涉及的内容模块有:
一、面向对象与面向过程有什么区别?二、面向对象有什么特征?三、什么是构造函数和析构函数?四、面向对象的作用域范围有哪几种?五、PHP 中魔术方法有哪些?六、什么是对象克隆?七、this、self 和 parent 的区别是什么?八、抽象类与接口有什么区别与联系?九、PHP 面向对象的常考面试题讲解
关于 PHP 面向对象的内容将会被分为三篇文章进行讲解完整块内容,第一篇主要讲解一到四点内容,第二篇主要讲解五到八的内容,第三篇围绕第九点进行讲解。
以下正文的内容都来自《PHP 程序员面试笔试真题解析》书籍,如果转载请保留出处:
九、PHP 面向对象的常考面试题讲解
【真题 1】什么是面向对象?其主要特征是什么?
答案:面向对象是程序的一种设计方式,它是一种对现实世界的理解和抽象的方法,它可以提高程序的重用性,让程序结构更加清晰。面向对象的主要特征为:封装、继承、多态。
【真题 2】可以获得对象的类名的函数是()。
A.get_class_name B.get_class C.class_exists D.get_class_vars 答案:B。PHP 中获取对象的类名函数是 get_class()。所以,选项 B 正确。对于选项 A,不存在该方法。所以,选项 A 错误。对于选项 C,class_exists() 函数可以检查类是否存在。所以,选项 C 错误。对于选项 D,get_class_vars() 函数可以获取类的默认属性。所以,选项 D 错误。所以,本题的答案是 B。
【真题 3】请简单说明 PHP 的垃圾收集机制。
答案:在 PHP 中,当没有任何变量指向该对象时,该对象变为垃圾将会在内存中被销毁,可以防止内存溢出。内存中对变量有引用计数,当计数到 0 时变量被销毁。
【真题 4】多态与方法重写有什么关系?
答案:多态是指一个类可以被多个类继承,每个子类都可以对父类方法进行重写,每个类里的同名方法可以实现不同的功能从而表现出多种形态,它增强了软件的灵活性和重用性。重写是子类对父类中的方法进行改写。它们的关系是重写让类具备多态性。
【真题 5】面向对象几大原则是什么?
答案:面向对象存在五大基本原则,分别是:单一职责原则、开放封闭原则、替换原则、依赖原则、接口分离原则等。(1)单一职责原则所谓单一职责原则,即一个类最好只做一件事。为了提高内聚性减少引起变化,单一原则是低耦合、高内聚的面向原则上的引申。(2)开放封闭原则软件的功能应该是可扩展的,尽可能减少修改,因为修改程序,可能会对原来的程序造成影响。虽然建议尽可能不修改程序,但是允许通过添加功能来减少修改。(3)替换原则只有子类能够替换基类,在继承机制的约束规范中,子类替换基类时,可以保证运行期内识别子类,保证继承复用。(4)依赖倒置原则高层模块不依赖底层模块,二者都依赖于抽象,抽象不依赖于实体,而实体依赖于抽象。模块间的依赖是通过抽象方法发生的,实现类中不发生直接的依赖关系,而依赖关系是通过接口或抽象类产生的。即接口或抽象类不依赖于实现类,而实现类依赖于接口和抽象类。这种依赖倒置原则可以有效地减少类之间的耦合性,提高系统的稳定性,减少并发引起的风险,提高代码的可读性和可维护性。(5)接口隔离原则建议开发使用多个小的、专门的接口,避免使用一个大的总接口。即每一个功能有一个专门的功能接口,需要用到才调用,不需要全部功能汇总到一个接口,这样可以提高代码的灵活性,降低类之间的耦合性,提高稳定性。
【真题 6】以下有关 PHP 高级特性的说法中,正确的是()。
A.可以定义一个类去实现预定义接口 Iterator,然后就能像访问数组一样访问这个类创建的对象 B.spla_utoload_register() 提供了一种更加灵活的方式来实现类的自动加载,不再建议使用_autoload() 函数 C.PHP 在对象中调用一个不可访问方法时,invoke() 方法会被自动调用 D.匿名函数也叫闭包函数,常用作回调函数参数的值,但是不能作为变量的值来使用答案:B。对于选项 A,只有 ArrayAccess 能够提供像访问数组一样访问这个对象的接口,不能定义一个类或预定义接口 Iterator 去实现这个功能。所以,选项 A 错误。对于选项 B,因为可以通过 spla_utoload_register() 函数创建 autoload 函数的队列,按定义顺序逐个执行,比_autoload() 函数只可以定义一次使用更方便,所以不建议使用_autoload() 函数。所以,选项 B 正确。对于选项 C,_call 方法是在创建一个类实例化后就可以直接调用对象使用,当调用的方法不可访问或没有权限访问时,会自动调用_call 方法。所以,选项 C 错误。对于选项 D,匿名函数是可以赋值给变量的。所以,选项 D 错误。所以,本题的答案是 B。
【真题 7】__autoload() 函数的工作原理是什么?
答案:使用这个魔术函数的基本条件是,类文件的文件名要和类的名字保持一致。当程序执行到实例化某个类时,如果在实例化前没有引入这个类文件,那么就自动执行__autoload() 函数。这个函数根据实例化的类名去查找这个类的路径,一旦找到这个类后就会通过执行 include 或 require 载入该类,从而保证程序能够继续执行。如果没有找到,那么报错。
【真题 8】以下关于 PHP 命名空间的说法中,不正确的是()。
A.访问任意全局类、函数或常量,都可以使用完全限定名称,例如 strlen() 或 Exception 或 INI_ALLB.关键字 namespace 可用来显式访问当前命名空间或子命名空间中的元素,它等价于类中的 this 操作符 C.任意合法的 PHP 代码都可以包含在命名空间中,但只有三种类型的代码受命名空间的影响,它们是类、函数和常量 D.常量__NAMESPACE__的值是当前命名空间名称的字符串。如果是在全局中,那么它不包括任何命名空间中的代码,本身是一个空字符串答案:B。namespace 关键字是用来声明命名空间用的,它并不能等价于 this 操作符的功能。所以,选项 B 说法不对。所以,本题的答案是 B。
【真题 9】以下代码的运行结果是()。
<?php
class Person{
var $name;
}
$a = new Person();
$a->name = “ 张三 ”;
$b = $a;
$b->name = “ 李四 ”;
echo $a->name;
?>
A.张三 B.李四 C.Null D.什么都没有答案:B。首先 $a 实例化 Person 类,把张三赋值给类内的变量 name,把对象张三的值给了 $b,通过 $b 去修改类内 name 的值为李四,所以最后输出 Person 类内的 name,输出得到结果李四。所以,选项 B 正确,选项 A、选项 C、选项 D 错误。所以,本题的答案是 B。
【真题 10】下面说法错误的是()。
A.如果一个类的成员前面有访问修饰符 private,那么这些成员不能被继承,在类的外部不可见。但如果成员被指定为 protected 和 public,那么可以被继承,在类的外部也是可见的 B.PHP5 中,final 关键字可以禁止继承和重载 C.PHP5 中,析构函数的名称是__destruct(),并且不能有任何参数 D.继承接口的类必须实现接口中声明的所有方法,在 PHP 中,如果继承接口的类没有实现接口中的方法,那么将会产生一个致命错误答案:A。对于选项 A,private 修饰的成员是不可以被继承的,protected 的成员是可以被继承的,但是在外部不可见,选项 A 说法错误,所以,选项 A 正确。对于选项 B,final 关键字的方法是禁止被继承和重载的,选项 B 说法正确,所以选项 B 错误。对于选项 C,析构函数不能有参数,选项 C 说法正确,所以,选项 C 错误。对于选项 D,继承接口的类没有实现接口中的方法是会产生错误的,选项 D 说法正确,所以,选项 D 错误。所以,本题的答案是 A。
自己整理了一篇“个人编程 6 年的心得——如何学好编程?”的文章,关注公众号:“琉忆编程库”,回复:“学好”,我发给你。
【真题 11】定义类成员的访问权限控制符有哪些?默认修饰符是什么?
答案:类成员的访问修饰符有 public、private、protected,主要用来修饰类中的成员属性和方法。public 是公共类型,允许在类的内部或子类中使用,也可以在类外部被访问。private 是私有类型,只能在类的内部被使用,不能被继承使用。protected 是保护类型,只能在类的内部或子类中使用。如果不使用 public、private、protected 等关键字修饰方法或属性,那么可以使用 var 关键字,它的功能等同于 public,可以在类内或类外被调用,也可以被继承使用。其中,PHP 默认的修饰符是 public,即公有类型。类前面只能加 final、abstract 关键字,被 final 修饰的属性或方法是不能被继承的,只能在当前类中使用,abstract 定义的类或方法,叫作抽象类或抽象方法。属性前面:必须有访问修饰符(private,protected,public,var)。
【真题 12】PHP 的魔术方法包含哪些(越多越好)?在什么情况下被自动调用?
答案:PHP 可用的魔术方法会在特定情况下被自动调用,但是前提是特定的条件被触发,并且这些魔术方法可以在类中作为方法。PHP 的魔术方法有:1)_construct():构造函数,创建对象时自动被调用。2)_destruct():析构函数,对象的所有引用都被删除或者当对象被显式销毁时执行。3)__clone():克隆函数,调用 clone 方法时自动调用。4)__set():当程序试图写入一个不存在或不可见的成员变量时自动调用。该函数在类中定义时必须有两个参数:变量名和变量值。5)__get():当程序调用一个未定义或不可见的成员变量时自动调用__get() 来读取变量值。定义时必有有一个参数:变量名。6)__call():当程序试图调用不存在或不可见的成员方法时,自动调用__call()。__call() 方法一般用于监视错误的方法调用。为了避免当调用的方法不存在时产生错误,可以使用__call() 方法来避免。该方法包含两个参数:方法名和方法参数。其中,方法参数以数组形式存在。7)__sleep():使用 serialize() 实现序列化对象时,先调用该方法,可以用来清除对象并返回一个该对象中所有变量的数组。8)__wakeup():使用 unserialize() 还原一个被序列化的对象时,先执行该方法,恢复在序列化中可能丢失的数据库连接及相关工作。9)__toString():当使用 echo 或 print 输出对象时,将对象转化为字符串。10)__autoload():调用未被实例化的类时,自动调用,在指定路径下查找和该类名称相同的文件。
【真题 13】$this、self 和 parent 这三个关键词分别代表什么?在哪些场合下使用?
答案:$this 表示当前对象,在当前类中可以通过 -> 符调用类内的属性和方法。self 表示当前类,只能通过 self 的形式(“self:: 方法或属性”)调用类内的方法。parent 表示当前类的父类,调用父类内的方法只能使用“parent::”形式调用。
【真题 14】下面关于面向对象的描述中,错误的是()。
A.父类的构造函数与析构函数不会自动被调用 B.成员变量需要用 public、protected、private 修饰,在定义变量时不再需要 var 关键字 C.父类中定义的静态成员,不可以在子类中直接调用 D.包含抽象方法的类必须为抽象类,抽象类不能被实例化答案:A。对于选项 A,子类继承父类,如果子类没有构造函数和析构函数,那么实例化子类时会自动调用父类的构造函数和析构函数;但如果子类只有构造函数没有析构函数时,那么实例化子类时,自动调用的是子类的构造函数,销毁对象时调用父类的析构函数;如果子类没有构造函数只有析构函数,那么实例化子类时会自动调用父类的构造函数,销毁对象时调用子类的析构函数,选项 A 说法不完全。所以,选项 A 正确。对于选项 B,成员变量使用了 public、protected、private 修饰定义变量时是不需要 var 关键字的,选项 B 说法正确。所以,选项 B 错误。对于选项 C,父类中的静态成员,子类中是不可以直接访问的,选项 B 说法正确。所以,选项 C 错误。对于选项 D,一个包含抽象方法的类必须是抽象类,并且抽象类不能被实例化。选项 D 说法正确。所以,选项 D 错误。所以,本题的答案是 A。
【真题 15】在 PHP 中,如果派生类与父类有相同名字的函数,那么派生类的函数会替换父类的函数,有如下程序代码:
<?php
class A {
function disName(){
echo “Picachu”;
}
}
class B extends A {
var $tmp=”;
function disName(){
echo “Doraemon”;
}
}
$cartoon = new B;
$cartoon->disName();
?>
上述代码的运行结果为()。A.tmp B.Picachu C.disName D.Doraemon E.无输出答案:D。当派生类继承父类时,如果通过实例化一个派生类的对象来访问对象的方法时,派生类不存在父类中的方法,那么执行父类中的方法。如果派生类和父类存在相同名字的方法,那么派生类的方法会覆盖父类方法,执行派生类的方法。所以,本题中可以执行派生类的 disName() 方法。所以,选项 D 正确,选项 A、选项 B、选项 C、选项 E 错误。所以,本题的答案是 D。
【真题 16】什么是抽象类和接口?抽象类和接口有什么不同和相似的地方?
答案:被关键字 abstract 修饰的类叫作抽象类,抽象类是不能被实例化的。被 abstract 修饰的方法为抽象方法,一个类只要有一个抽象方法,这个类一定是抽象类。接口是通过关键字 interface 来定义的,可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体实现。PHP 类只支持是单重继承的,但通过接口可以实现 PHP 类的多重继承。抽象类和接口的不同和相似的地方如下所示。1)抽象类是一种不能被实例化的类,只能作为其他类的父类来使用。2)抽象类是通过关键字 abstract 来声明的。3)抽象类与普通类相似,都包含成员变量和成员方法,两者的区别在于,抽象类中至少要包含一个抽象方法。4)抽象方法没有方法体,该方法就是要被子类重写的。5)抽象方法的格式为:abstract function abstractMethod()。6)因为 PHP 中只支持单重继承,所以如果想实现多重继承,那么就要使用接口。也就是说,子类可以实现多个接口。7)接口类是通过 interface 关键字来声明的,接口类中的成员变量和方法都是 public 的,可以不用显式地使用 public 来修饰。8)接口中的方法没有方法体。接口中的方法就是要被子类继承实现的。9)子类继承抽象类使用 extends 关键字,子类实现接口使用 implements 关键字。
【真题 17】用类编程实现:Stu 类中有两个私有属性 name 和 sex,有两个公有方法,setName() 和 setSex() 参数自定,方法可实现对两个私有属性进行修改。在实例化类时要求对私有属性能初始化。
答案:实现代码如下:
<?php
Class Stu{
private $name;
private $sex;
public function setName($name){
$this->name = $name;
}
public function setSex($sex){
$this->sex = $sex;
}
}
?>
【真题 18】假如有一个类 Person,实例化(new)一个对象 $p,那么以下使用对象 $p 调用 Person 类中的 getInfo 方法的写法中,正确的是()。
A.$p=>getInfo(); B.$this->getInfo(); C.$p->getInfo(); D.$p::getInfo(); 参考答案:C。分析:“::”主要用于访问类中的静态成员,“->”主要用于访问类中的变量和方法,“=>”主要应用在数组中的 key 和 value 映射时使用。所以,选项 A、选项 B、选项 D 错误,选项 C 正确。
【真题 19】php 中 public、protected、private 三种访问控制模式的区别是什么?
参考答案:php 中 public、protected、private 三种访问控制模式的区别如下:访 问 模 式 描 述 public 共有,任何地方都可以访问 protected 继承,只能在本类或子类中访问,在其他地方不能使用 private 私有,只能在本类中访问,在其他地方不能使用
【真题 20】在 PHP 面向对象中,下面关于 final 修饰符的描述中,错误的是()。
A.使用 final 标识的类不能被继承 B.在类中使用 final 标识的成员方法,在子类中不能被覆盖 C.不能使用 final 标识成员属性 D.使用 final 标识的成员属性,不能在子类中再次定义参考答案:D。分析:因为 final 只能修饰类与方法,不能修饰类的属性。所以,选项 D 错误。
PS:由于真题较多,仅罗列 PHP 面向对象笔试中经常遇到的 20 道考题!
至此本周(2019-2-11 至 2019-2-15 的面向对象专题已更新完毕,以上的内容只是摘取了 PHP 面向对象中最常考的内容,个别内容没有罗列可以从原书中获取。)感谢大家的支持!
预告:下周(2019-2.18 —— 2.22)更新“PHP 面试常考内容之 Memcache 和 Redis 缓存的”专题,敬请期待。
以上内容摘自《PHP 程序员面试笔试真题解析》书籍,该书已在天猫、京东、当当等电商平台销售。
更多 PHP 相关的面试知识、考题可以关注公众号获取:琉忆编程库
对本文有什么问题或建议都可以进行留言,将不断完善追求极致,感谢你们的支持。