1. 写出 php 的 public、protected、private 三种访问控制模式的区别(新浪⽹技


术部)


public:公有,任何地⽅都可以访问


protected:继承,只能在本类或⼦类中访问,在其它地⽅不允许访问


private:私有,只能在本类中访问,在其他地⽅不允许访问


相关题⽬:请写出 PHP5 权限控制修饰符


2. 设计模式考察:请⽤单态设计模式⽅法设计类满⾜如下需求:


请⽤ PHP5 代码编写类实现在每次对数据库连接的访问中都只能获得唯⼀的⼀个


数据库连接,具体连接数据库的详细代码忽略,请写出主要逻辑代码(新浪⽹技术


部)


3.魔术⽅法


__sleep serialize 之前被调⽤


__wakeup unserialize 时被调⽤


__toString 打印⼀个对象时被调⽤


__set_state 调⽤ var_export 时被调⽤,⽤__set_state的返回值作为 var_export


的返回值


__construct 构造函数,实例化对象时被调⽤


__destruct 析构函数,当对象销毁时被调⽤


__call 对象调⽤某个⽅法,若存在该⽅法,则直接调⽤,若不存在,则调


⽤__call 函数


__get 读取⼀个对象属性时,若属性存在,则直接返回,若不存在,则调⽤__get


函数


__set 设置⼀个对象的属性时,若属性存在,则直接赋值,若不存在,则调


⽤__set 函数


__isset 检测⼀个对象的属性是否存在时被调⽤


__unset unset ⼀个对象的属性时被调⽤


__clone 克隆对象时被调⽤


__autoload 实例化⼀个对象时,如果对应的类不存在,则该⽅法被调⽤


相关题⽬:请写出 php5 的构造函数和析构函数


构造函数:__construct


析构函数:__destruct4.接⼝和抽象类的区别是什么?


抽象类是⼀种不能被实例化的类,只能作为其他类的⽗类来使⽤。抽象类是通过关


键字abstract 来声明的。


抽象类与普通类相似,都包含成员变量和成员⽅法,两者的区别在于,抽象类中⾄


少要包含⼀个抽象⽅法,抽象⽅法没有⽅法体,该⽅法天⽣就是要被⼦类重写的。


抽象⽅法的格式为:abstract function abstractMethod();


接⼝是通过 interface 关键字来声明的,接⼝中的成员常量和⽅法都是 public 的,


⽅法可以不写关键字 public,接⼝中的⽅法也是没有⽅法体。接⼝中的⽅法也天⽣


就是要被⼦类实现的。


抽象类和接⼝实现的功能⼗分相似,最⼤的不同是接⼝能实现多继承。在应⽤中选


择抽象类还是接⼝要看具体实现。


⼦类继承抽象类使⽤ extends,⼦类实现接⼝使⽤ implements。


5.autoload()函数是如何运作的?


使⽤这个魔术函数的基本条件是类⽂件的⽂件名要和类的名字保持⼀致。


当程序执⾏到实例化某个类的时候,如果在实例化前没有引⼊这个类⽂件,那么就


⾃动执⾏__autoload()函数。


这个函数会根据实例化的类的名称来查找这个类⽂件的路径,当判断这个类⽂件路


径下确实存在这个类⽂件后就执⾏ include 或者 require 来载⼊该类,然后程序继


续执⾏,如果这个路径下不存在该⽂件时就提示错误。


7.PHP处理数组的常⽤函数?(重点看函数的‘参数’和‘返回值’)


 ①array()创建数组;


 ②count()返回数组中元素的数⽬;


 ③array_push()将⼀个或多个元素插⼊数组的末尾(⼊栈);


 ④array_column()返回输⼊数组中某个单⼀列的值;


 ⑤array_combine()通过合并两个数组来创建⼀个新数组;


 ⑥array_reverse()以相反的顺序返回数组;


 ⑦array_unique()删除数组中的重复值;


 ⑧in_array()检查数组中是否存在指定的值;


9.PHP处理字符串的常⽤函数?


 ①trim()移除字符串两侧的空⽩字符和其他字符;  ②substr_replace()把字符串的⼀部分替换为另⼀个字符串;


 ③substr_count()计算⼦串在字符串中出现的次数;


 ④substr()返回字符串的⼀部分;


 ⑤strtolower()把字符串转换为⼩写字⺟;


 ⑥strtoupper()把字符串转换为⼤写字⺟;


 ⑦strtr()转换字符串中特定的字符;


 ⑧strrchr()查找字符串在另⼀个字符串中最后⼀次出现;


 ⑨strstr()查找字符串在另⼀字符串中的第⼀次出现(对⼤⼩写敏感);


 ⑩strrev()反转字符串;


 ⑪strlen()返回字符串的⻓度;


 ⑫str_replace()替换字符串中的⼀些字符(对⼤⼩写敏感);


 ⑬print()输出⼀个或多个字符串;


 ⑭explode()把字符串打散为数组;


 ⑮is_string()检测变量是否是字符串;


 ⑯strip_tags()从⼀个字符串中去除HTML标签;


 ⑰mb_substr()⽤来截中⽂与英⽂的函数


10.什么是事务?及其特性?


 答:事务:是⼀系列的数据库操作,是数据库应⽤的基本逻辑单位。


 事务特性:


 (1)原⼦性:即不可分割性,事务要么全部被执⾏,要么就全部不被执⾏。


 (


2)⼀致性或可串性。事务的执⾏使得数据库从⼀种正确状态转换成另⼀种


正确状态


 (


3)隔离性。在事务正确提交之前,不允许把该事务对数据的任何改变提供


给任何其他事务,


 (


4) 持久性。事务正确提交后,其结果将永久保存在数据库中,即使在事务


提交后有了其他故障,事务的处理结果也会得到保存。


 或者这样理解:


 事务就是被绑定在⼀起作为⼀个逻辑⼯作单元的SQL语句分组,如果任何⼀


个语句操作失败那么整个操作就被失败,以后操作就会回滚到操作前状态,或者是


上有个节点。为了确保要么执⾏,要么不执⾏,就可以使⽤事务。要将有组语句作


为事务考虑,就需要通过ACID测试,即原⼦性,⼀致性,隔离性和持久性。


11.什么是构造函数,什么是析构函数,作⽤是什么?  答:构造函数(⽅法)是对象创建完成后第⼀个被对象⾃动调⽤的⽅法。它存


在于每个声明的类中,是⼀个特殊的成员⽅法。作⽤是执⾏⼀些初始化的任务。


Php中使⽤construct()声明构造⽅法,并且只能声明⼀个。


 析构函数(⽅法)作⽤和构造⽅法正好相反,是对象被销毁之前最后⼀个被对


象⾃动调⽤的⽅法。是PHP5中新添加的内容作⽤是⽤于实现在销毁⼀个对象之前


执⾏⼀些特定的操作,诸如关闭⽂件和释放内存等。


12.OOP是什么?


答:oop是⾯向对象编程,⾯向对象编程是⼀种计算机编程架构,OOP 的⼀条


基本原则是计算机程序是由单个能够起到⼦程序作⽤的单元或对象组合⽽成。


OOP具有三⼤特点:


1、封装性:也称为信息隐藏,就是将⼀个类的使⽤和实现分开,只保留部分接⼝


和⽅法与外部联系,或者说只公开了⼀些供开发⼈员使⽤的⽅法。于是开发⼈员只


需要关注这个类如何使⽤,⽽不⽤去关⼼其具体的实现过程,这样就能实现MVC


分⼯合作,也能有效避免程序间相互依赖,实现代码模块间松藕合。


2、继承性:就是⼦类⾃动继承其⽗级类中的属性和⽅法,并可以添加新的属性和


⽅法或者对部分属性和⽅法进⾏重写。继承增加了代码的可重⽤性。PHP只⽀持单


继承,也就是说⼀个⼦类只能有⼀个⽗类。


3、多态性:⼦类继承了来⾃⽗级类中的属性和⽅法,并对其中部分⽅法进⾏重


写。于是多个⼦类中虽然都具有同⼀个⽅法,但是这些⼦类实例化的对象调⽤这些


相同的⽅法后却可以获得完全不同的结果,这种技术就是多态性。多态性增强了软


件的灵活性。


1、易维护


采⽤⾯向对象思想设计的结构,可读性⾼,由于继承的存在,即使改变需求,那么


维护也只是在局部模块,所以维护起来是⾮常⽅便和较低成本的。


2、质量⾼


在设计时,可重⽤现有的,在以前的项⽬的领域中已被测试过的类使系统满⾜业务


需求并具有较⾼的质量。


3、效率⾼


在软件开发时,根据设计的需要对现实世界的事物进⾏抽象,产⽣类。使⽤这样的


⽅法解决问题,接近于⽇常⽣活和⾃然的思考⽅式,势必提⾼软件开发的效率和质


量。


4、易扩展


由于继承、封装、多态的特性,⾃然设计出⾼内聚、低耦合的系统结构,使得系统更灵活、更容易扩展,⽽且成本较低。


14.include 和 require 都能把另外⼀个⽂件包含到当前⽂件中 他们有什么区别?


include 和 include_once ⼜有什么区别?


⼆者区别只有⼀个,那就是对包含⽂件的需求程度


include 就是包含,如果被包含的⽂件不存在的话, 那么则会提示⼀个


错误,但是程序会继续执⾏下去。


require 意思是需要,如果被包含⽂件不存在或者 ⽆法打开的时候,则


会提示错误,并且会终⽌程序的执⾏。


这两种结构除了在如何处理失败之外完全⼀样。


once 的意思是⼀次,那么 include_once 和 require_once 表示只包含


⼀次,避免重复包含。


15.表单中 get 与 post 提交⽅法的区别?


3.1、GET 请求能够被 cache,GET 请求能够被保存在浏览器的浏览历


史 ⾥⾯(密码等重要数据 GET 提交,别⼈查看历史记录,就可以直接


看 到这些私密数据)POST 不进⾏缓存。


3.2、GET 参数是带在 URL 后⾯,传统 IE 中 URL 的最⼤可⽤⻓度为


2053 字符,其他浏览器对 URL ⻓度限制实现上有所不同。POST 请求


⽆⻓ 度限制(⽬前理论上是这样的)。


3.3、GET 提交的数据⼤⼩,不同浏览器的限制不同,⼀般在 2k-8K 之


间, POST 提交数据⽐较⼤,⼤⼩靠服务器的设定值限制,⽽且某些


数据 只能⽤ POST ⽅法「携带」,⽐如 file。


3.4、全部⽤ POST 不是⼗分合理,最好先把请求按功能和场景分下


类, 对数据请求频繁,数据不敏感且数据量在普通浏览器最⼩限定的


2k 范围内,这样的情况使⽤ GET。其他地⽅使⽤ POST。


3.5、GET 的本质是「得」,⽽ POST 的本质是「给」。⽽且,GET 是


「幂 等」的,在这⼀点上,GET 被认为是「安全的」。但实际上


server 端 也可以⽤作资源更新,但是这种⽤法违反了约定,容易造成


CSRF(跨 站请求伪造)。16.session 与 cookie 的关系和区别?


COOKIE保存在客户端,⽽SESSION则保存在服务器端


从安全性来讲,SESSION的安全性更⾼


从保存内容的类型的⻆度来讲,COOKIE只保存字符串(及能够⾃动转换成字符


串)


从保存内容的⼤⼩来看,COOKIE保存的内容是有限的,⽐较⼩,⽽SESSION基


本上没有这个限制


从性能的⻆度来讲,⽤SESSION的话,对服务器的压⼒会更⼤⼀些


SEEION依赖于COOKIE,但如果禁⽤COOKIE,也可以通过url传递


17.print()、echo、print_r()、var_dump()等区别。


print()、echo 都是语⾔结构,不同的是前者打印只能接受⼀个变量,后者可以


输出多个。


print_r()和var_dump()都是函数。


前者格式化打印变量。但print_r()输出布尔值和NULL的结果没有意义,打印true


返回1,null则不显示。


后者也是格式化打印变量。但会详细的打印出变量的类型,⻓度,数值,如果包


含多层将递归打印。更适合调试。


18.常⻅状态码


1xx (临时响应)表示临时响应并需要请求者继续执⾏操作的状态代码。


100 (继续) 请求者应当继续提出请求。 服务器返回此代码表示已收到请求的


第⼀部分,正在等待其余部分。


101 (切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换。


102 由WebDAV(RFC 2518)扩展的状态码,代表处理将被继续执⾏。


2xx (成功)表示成功处理了请求的状态代码。


200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的⽹


⻚。


201 (已创建) 请求成功并且服务器创建了新的资源。


202 (已接受) 服务器已接受请求,但尚未处理。


203 (⾮授权信息) 服务器已成功处理了请求,但返回的信息可能来⾃另⼀来


源。


204 (⽆内容) 服务器成功处理了请求,但没有返回任何内容。205 (重置内容) 服务器成功处理了请求,但没有返回任何内容。


206 (部分内容) 服务器成功处理了部分 GET 请求。


207 由WebDAV(RFC 2518)扩展的状态码,代表之后的消息体将是⼀个XML消


息,并且可能依照之前⼦请求数量的不同,包含⼀系列独⽴的响应代码。


3xx (重定向) 表示要完成请求,需要进⼀步操作。 通常,这些状态代码⽤来


重定向。


300 (多种选择) 针对请求,服务器可执⾏多种操作。 服务器可根据请求者


(useragent)选择⼀项操作,或提供操作列表供请求者选择。


301 (永久移动) 请求的⽹⻚已永久移动到新位置。 服务器返回此响应(对


GET 或HEAD请求的响应)时,会⾃动将请求者转到新位置。


302 (临时移动) 服务器⽬前从不同位置的⽹⻚响应请求,但请求者应继续使


⽤原有位置来进⾏以后的请求。


303 (查看其他位置) 请求者应当对不同的位置使⽤单独的 GET 请求来检索响


应时,服务器返回此代码。


304 (未修改) ⾃从上次请求后,请求的⽹⻚未修改过。 服务器返回此响应


时,不会返回⽹⻚内容。


305 (使⽤代理) 请求者只能使⽤代理访问请求的⽹⻚。 如果服务器返回此响


应,还表示请求者应使⽤代理。


307 (临时重定向) 服务器⽬前从不同位置的⽹⻚响应请求,但请求者应继续使


⽤原有位置来进⾏以后的请求。


4xx (请求错误) 这些状态代码表示请求可能出错,妨碍了服务器的处理。


400 (错误请求) 服务器不理解请求的语法。


401 (未授权) 请求要求身份验证。 对于需要登录的⽹⻚,服务器可能返回此


响应。


402 该状态码是为了将来可能的需求⽽预留的。


403 (禁⽌) 服务器拒绝请求。


404 (未找到) 服务器找不到请求的⽹⻚。


405 (⽅法禁⽤) 禁⽤请求中指定的⽅法。


406 (不接受) ⽆法使⽤请求的内容特性响应请求的⽹⻚。


407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授


权使⽤代理。


408 (请求超时)服务器等候请求时发⽣超时。


409 (冲突) 服务器在完成请求时发⽣冲突。 服务器必须在响应中包含有关冲


突的信息。410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。


411 (需要有效⻓度) 服务器不接受不含有效内容⻓度标头字段的请求。


412 (未满⾜前提条件) 服务器未满⾜请求者在请求中设置的其中⼀个前提条


件。


413 (请求实体过⼤) 服务器⽆法处理请求,因为请求实体过⼤,超出服务器的


处理能⼒。


414 (请求的 URI 过⻓) 请求的 URI(通常为⽹址)过⻓,服务器⽆法处理。这


⽐较少⻅,通常的情况包括:本应使⽤POST⽅法的表单提交变成了GET⽅法,


导致查询字符串(Query String)过⻓。


415 (不⽀持的媒体类型) 请求的格式不受请求⻚⾯的⽀持。


416 (请求范围不符合要求) 如果⻚⾯⽆法提供请求的范围,则服务器会返回此


状态代码。


417 (未满⾜期望值) 服务器未满⾜”期望”请求标头字段的要求。


5xx (服务器错误)这些状态代码表示服务器在尝试处理请求时发⽣内部错误。


这些错误可能是服务器本身的错误,⽽不是请求出错。


500 (服务器内部错误) 服务器遇到错误,⽆法完成请求。


501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器⽆法识别请求


⽅法时可能会返回此代码。


502 (错误⽹关) 服务器作为⽹关或代理,从上游服务器收到⽆效响应。


503 (服务不可⽤) 服务器⽬前⽆法使⽤(由于超载或停机维护)。 通常,这


只是暂时状态。


504 (⽹关超时) 服务器作为⽹关或代理,但是没有及时从上游服务器收到请


求。


505 (HTTP 版本不受⽀持)服务器不⽀持请求中所⽤的 HTTP 协议版本。


19.PHP垃圾回收机制


php中的变量存储在变量容器zval中,zval中除了存储变量类型和值外,还有


is_ref和refcount字段。refcount表示指向变量的元素个数,is_ref表示变量表示


是否是引⽤变量。如果refcount为0时,就回收该变量容器。


php5和php7的垃圾回收机制都是利⽤引⽤计数


我们先来看看什么叫做引⽤计数:


由于PHP是⽤C来写的,C⾥⾯有⼀种东⻄叫做结构体,我们PHP的变量在C中就是


⽤这种⽅式存储的每个PHP的变量都存在于⼀个叫做zval的容器中,⼀个zval容器,除了包含变量名和


值,还包括两个字节的额外信息,⼀个叫做'is_ref',是个布尔值,⽤来表示这个变量是


否属于引⽤集合,通过这个字节,我们php才能把普通变量和引⽤变量区分开来.第


⼆个额外字节就是'refcount',⽤来表示指向这个容器的变量的个数


我们在PHP中定义⼀个变量


$name='看看';


我们现在可以使⽤xdebug_debug_zval()函数来获得函数内变量的相关信息


xdebug_debug_zval('name');


//输出 name:(refcount=1,is_ref=0)='new String'


现在我们把$name赋值给$money


$money = $name;


再来查看⼀下:


xdebug_debug_zval('name');


//输出 name:(refcount=2,is_ref=0)='new String'


这时候我们会看到refcount的字段的值增加了1,代表现有两个变量指向了相同的


⼀个名字叫做name的aval容器


根据引⽤计数的规则,当这个refcount=0的时候,php就会把这个容器当做垃圾进


⾏回收.


同样我们执⾏


unset($name); //⼀样也会把name容器的引⽤计数设置为0


以上的结论只是针对标量类型的,下⾯我们来看看负责类型的


数组:


$person=['name'=>'请欢','age'=>19];


var_dump(xdebug_debug_zval('person'));


在PHP5输出:


person:


(refcount=1, is_ref=0),


array (size=2)


'name' => (refcount=1, is_ref=0),string '看看' (length=6)


'age' => (refcount=1, is_ref=0),int 19在PHP7中输出:


person:


(refcount=2, is_ref=0)


array (size=2)


'name' => (refcount=1, is_ref=0)string '看看' (length=6)


'age' => (refcount=0, is_ref=0)int 19


由此可⻅,对于复杂的数据类型,PHP5和PHP7的引⽤计数算法是不⼀样的


我们来试试循环引⽤的情况


在上⾯代码的基础上,添加⼀⾏代码


$person['hello'] = $person['name']


在PHP7中输出:


person:


(refcount=1, is_ref=0)


array (size=3)


'name' => (refcount=3, is_ref=0)string '看看' (length=6)


'age' => (refcount=0, is_ref=0)int 19


'hello' => (refcount=3, is_ref=0)string '看看' (length=6)


在PHP5中输出:


person:


(refcount=1, is_ref=0),


array (size=3)


'name' => (refcount=2, is_ref=0),string '看看' (length=6)


'age' => (refcount=1, is_ref=0),int 19


'hello' => (refcount=2, is_ref=0),string '看看' (length=6)


⼩总结:


PHP5和PHP7的垃圾回收机制都属于引⽤计数,但是在复杂数据类型的算法处理上:


在 PHP7 中 zval 有了新的实现⽅式。最基础的变化就是 *zval 需要的内存不再是


单独从堆上分配,不再⾃⼰存储引⽤计数。复杂数据类型(⽐如字符串、数组和


对象)的引⽤计数由其⾃身来存储。这种实现⽅式有以下好处:*


*简单数据类型不需要单独分配内存,也不需要计数;*


*不会再有两次计数的情况。在对象中,只有对象⾃身存储的计数是有效的;*


*由于现在计数由数值⾃身存储,所以也就可以和⾮ zval 结构的数据共享,⽐如


zval 和 hashtable key 之间;*


20.传值和传引⽤、传地址的区别


1、传值,是把实参的值赋值给⾏参


那么知对⾏参的修道改,不会影响实参的值


2、传地址


是传值的⼀种特殊⽅式,只是他传递的是地址,不是普通的如int


那么传地址以后,实参和⾏参都专指向同⼀个对象


3、传引⽤


真正的以地址的⽅式传递参数


传递以后,⾏参和实参都是同⼀个对象,只是他们名字不同⽽已


对⾏参的修改将影属响实参的值


21.魔术常量


__LINE__


⽂件中的当前⾏号


__FILE__


⽂件的完整路径和⽂件名。如果⽤在被包含⽂件中,则返回被包含的⽂件名。


⾃ PHP 4.0.2 起,__FILE__ 总是包含⼀个绝对路径(如果是符号连接,则是解析


后的绝对路径),⽽在此之前的版本有时会包含⼀个相对路径。


__DIR__


⽂件所在的⽬录。如果⽤在被包括⽂件中,则返回被包括的⽂件所在的⽬录。


__FUNCTION__


函数名称(PHP 4.3.0 新加)。⾃ PHP 5 起本常量返回该函数被定义时的名字


(区分⼤⼩写)。在 PHP 4 中该值总是⼩写字⺟的。__CLASS__


类的名称(PHP 4.3.0 新加)。⾃ PHP 5 起本常量返回该类被定义时的名字(区


分⼤⼩写)。


在 PHP 4 中该值总是⼩写字⺟的。类名包括其被声明的作⽤区域(例如


Foo\Bar)。注意⾃ PHP 5.4 起 __CLASS__ 对 trait 也起作⽤。当⽤在 trait ⽅法


中时,__CLASS__ 是调⽤ trait ⽅法的类的名字。


__NAMESPACE__


当前命名空间的名称(区分⼤⼩写)。此常量是在编译时定义的(PHP 5.3.0 新


增)。


__METHOD__


类的⽅法名(PHP 5.0.0 新加)。返回该⽅法被定义时的名字(区分⼤⼩写)。


<?php


function test() {


echo '函数名为:' . __METHOD__ ;}test();


?>


__TRAIT__


Trait 的名字(PHP 5.4.0 新加)。⾃ PHP 5.4.0 起,PHP 实现了代码复⽤的⼀个


⽅法,称为 traits。


Trait 名包括其被声明的作⽤区域(例如 Foo\Bar)。


从基类继承的成员被插⼊的 SayWorld Trait 中的 MyHelloWorld ⽅法所覆盖。其


⾏为 MyHelloWorld 类中定义的⽅法⼀致。优先顺序是当前类中的⽅法会覆盖


trait ⽅法,⽽ trait ⽅法⼜覆盖了基类中的⽅法。