PHP面试题汇总(一)

PHP面试题汇总(基础)

文章内容主要参考:https://github.com/ycrao/mynotes

1. echo(),print(),print_r()的区别?

三者均可以输出信息,但是各有自己的特点:

类型 输出变量个数 输出变量类型 返回值 速度
echo 语言结构 一个或多个 简单类型变量,如int、string 最快
print 语言结构 一个 简单类型变量,如int、string int
print_r 函数 一个 复杂类型,如数组、对象 bool

2. 语句include和require的区别是什么?

在失败的时候:

include 产生一个 warning ,而 require 直接产生错误中断;

require 在运行前载入;

include 在运行时载入;

require_onceinclude_once 可以避免重复包含同一文件。

3. php中传值与传引用有啥区别?

&表示传引用;
函数中参数传引用会将参数进行改变;
一般在输出参数有多个的时候可以考虑使用引用。

1
2
3
4
5
6
$num = 10
function multiply(&$num){
$num = $num * 10;
}
multiply($num);
echo $num;

4. 下面哪项没有将john添加到users数组中?

1
2
3
4
(a) $users[] = 'john';
(b) array_add($users,'john');
(c) array_push($users,'john');
(d) $users ||= 'john';

答案为bd,php 里面无 array_add 函数,d项为语法错误的表达。

5. HTTP协议中几个状态码的含义。

1
2
3
4
5
6
7
8
9
10
11
12
200 OK 客户端请求成功
301 Moved Permanently 请求永久重定向
302 Moved Temporarily 请求临时重定向
304 Not Modified 文件未修改,可以直接使用缓存的文件。
400 Bad Request 由于客户端请求有语法错误,不能被服务器所理解。
401 Unauthorized 请求未经授权。这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden 服务器拒绝执行请求,即没有权限
404 Not Found 请求的资源不存在,例如,输入了错误的URL
500 Internal Server Error 服务器发生不可预期的错误,导致无法完成客户端的请求。
502 Bad Gateway 错误的网关,上游服务器错误(如php-fpm挂掉了)
503 Service Unavailable 服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常。
504 Gateway Timeout 网关超时(上游服务器超时)

参考:
HTTP状态码详解
502 VS 504

6. 写出一些php魔术方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
__construct() 实例化类时自动调用。
__destruct() 类对象使用结束时自动调用。
__set() 在给未定义的属性赋值的时候调用。
__get() 调用未定义的属性时候调用。
__isset() 使用isset()或empty()函数时候会调用。
__unset() 使用unset()时候会调用。
__sleep() 使用serialize序列化时候调用。
__wakeup() 使用unserialize反序列化的时候调用。
__call() 调用一个不存在的方法的时候调用。
__callStatic()调用一个不存在的静态方法是调用。
__toString() 把对象转换成字符串的时候会调用。比如 echo。
__invoke() 当尝试把对象当方法调用时调用。
__set_state() 当使用var_export()函数时候调用。接受一个数组参数。
__clone() 当使用clone复制一个对象时候调用。

7. MySQL存储引擎 MyISAM 和 InnoDB 的区别

MyISAM InnoDB
构成上的区别 每个MyISAM在磁盘上存储成三个文件。第一个文件的名字以表的名字开始,扩展名指出文件类型。 .frm文件存储表定义。 数据文件的扩展名为.MYD (MYData)。 索引文件的扩展名是.MYI (MYIndex)。 基于磁盘的资源是InnoDB表空间数据文件(.frm和它的日志文件(.ibd),InnoDB 表的大小只受限于操作系统文件的大小,一般为 2GB
事务处理上方面 MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持 InnoDB提供事务支持事务,外部键(foreign key)等高级数据库功能
SELECT UPDATE,INSERTDelete操作 如果执行大量的SELECT,MyISAM是更好的选择 1.如果你的数据执行大量的INSERT****UPDATE,出于性能方面的考虑,应该使用InnoDB表 2.DELETE FROM table时,InnoDB不会重新建立表,而是一行一行的删除。 3.LOAD TABLE FROM MASTER操作对InnoDB是不起作用的,解决方法是首先把InnoDB表改成MyISAM表,导入数据后再改成InnoDB表,但是对于使用的额外的InnoDB特性(例如外键)的表不适用
AUTO_INCREMENT类型的字段 在MyISAM表中,可以和其他字段一起建立联合索引 对于AUTO_INCREMENT类型的字段,InnoDB中必须包含只有该字段的索引
表的具体行数 select count() from table,MyISAM只要简单的读出保存好的行数,注意的是,当count()语句包含 where条件时,两种表的操作是一样的 InnoDB 中不保存表的具体行数,也就是说,执行select count(*) from table时,InnoDB要扫描一遍整个表来计算有多少行
表锁 提供行锁(locking on row level),提供与 Oracle 类型一致的不加锁读取(non-locking read in SELECTs),另外,InnoDB表的行锁也不是绝对的,如果在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表, 例如update table set num=1 where name like “%aaa%”

8. 说出一些MySQL优化方法?

1
2
3
4
5
6
7
a. 设计良好的数据库结构,允许部分数据冗余,尽量避免join查询,提高效率。
b. 选择合适的表字段数据类型和存储引擎,适当的添加索引。
c. mysql库主从读写分离。
d. 找规律分表,减少单表中的数据量提高查询速度。
e. 添加缓存机制,比如memcached,apc等。
f. 不经常改动的页面,生成静态页面。
g. 书写高效率的SQL。比如 SELECT * FROM TABEL 改为 SELECT field_1, field_2, field_3 FROM TABLE.

9. 下面$r的结果是:

1
2
3
4
5
6
<?php
$a = in_array('01', array('1')); // true
$a1 = in_array('01', array('1'), true); // false
$b = '01' == 1; // true
$b1 = '02' == 1; // false
$r = $a == $b

A true
B false

答案为A

10. 说下php中empty()和isset()的区别。

Expression gettype() empty() is_null() isset() boolean : if($x)
$x = “”; string TRUE FALSE TRUE FALSE
$x = null; NULL TRUE TRUE FALSE FALSE
var $x; NULL TRUE TRUE FALSE FALSE
$x is undefined NULL TRUE TRUE FALSE FALSE
$x = array(); array TRUE FALSE TRUE FALSE
$x = array(‘a’, ‘b’); array FALSE FALSE TRUE TRUE
$x = false; boolean TRUE FALSE TRUE FALSE
$x = true; boolean FALSE FALSE TRUE TRUE
$x = 1; integer FALSE FALSE TRUE TRUE
$x = 42; integer FALSE FALSE TRUE TRUE
$x = 0; integer TRUE FALSE TRUE FALSE
$x = -1; integer FALSE FALSE TRUE TRUE
$x = “1”; string FALSE FALSE TRUE TRUE
$x = “0”; string TRUE FALSE TRUE FALSE
$x = “-1”; string FALSE FALSE TRUE TRUE
$x = “php”; string FALSE FALSE TRUE TRUE
$x = “true”; string FALSE FALSE TRUE TRUE
$x = “false”; string FALSE FALSE TRUE TRUE

引用:PHP 类型比较表

isset 用于检测变量是否被设置,使用 isset() 测试一个被设置成 NULL 的变量,将返回 FALSE
empty 如果 var 是非空或非零的值,则 empty() 返回 FALSE。换句话说,""、0、"0"、NULL、FALSE、array()、var $var; 以及没有任何属性的对象都将被认为是空的,如果 var 为空,则返回 TRUE

如果变量为 0 ,则empty()会返回TRUEisset()会返回TRUE
如果变量为空字符串,则empty()会返回TRUE,isset()会返回TRUE
如果变量未定义,则empty()会返回TRUEisset()会返回FLASE

注意:isset() 只能用于变量,因为传递任何其它参数都将造成解析错误。若想检测常量是否已设置,可使用 defined() 函数。
当要 判断一个变量是否已经声明的时候 可以使用 isset 函数;
当要 判断一个变量是否已经赋予数据且不为空 可以用 empty函数;
当要 判断 一个变量 存在且不为空 先 isset 函数 再用 empty 函数;

11. cookie和session的区别、cookie禁用后session还可以用吗?

工作流程:

以下以PHP为例:

  1. 你第一次访问网站时,
  2. 服务端脚本中开启了Sessionsession_start();
  3. 服务器会生成一个不重复的 SESSIONID 的文件session_id();,比如在/var/lib/php/session目录
  4. 并将返回(Response)如下的HTTP头 Set-Cookie:PHPSESSIONID=xxxxxxx
  5. 客户端接收到Set-Cookie的头,将PHPSESSIONID写入cookie
  6. 当你第二次访问页面时,所有Cookie会附带的请求头(Request)发送给服务器端
  7. 服务器识别PHPSESSIONID这个cookie,然后去session目录查找对应session文件,
  8. 找到这个session文件后,检查是否过期,如果没有过期,去读取Session文件中的配置;如果已经过期,清空其中的配置

区别:

1、cookie就是服务器发放给客户端的一些标识,保存在客户端,让客户端每次请求的时候带上,以区分不同的用户;

2、session是服务器存放在自己那里的用户相关的数据,用每次用户带来的cookie去提取出来,恢复一个之前访问的历史或者相关环境。

3、cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗 考虑到安全应当使用session。

4、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能考虑到减轻服务器性能方面,应当使用COOKIE。

5、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie

参考:

12. 说出常用的10个数组方法

in_array(判断数组中是否有某个元素)
var_dump(in_array(0, array(false, 1))) //true

implode(将数组按照一定规律分解)

json_encode(将数组转化成json)

sort(排序,有很多排序的函数这里就说一个)

array_push(将一个活多个单元压入数组的末尾)

array_merge(合并数组)

array_key_exists(检查键名是否存在于数组中)

array_unique(去除数组中重复的值,只能对一位数组起作用)

array_shift(移除数组中第一个单元)

13. 说出平时常用的操作字符串的方法,并解决具体问题

substr(截取字符串)

strlen(获取字符串长度)

strpos(查找字符串首次出现的位置)

str_replace(字符串替换)

explode(字符串拆分转数组)
implode(数组拼接转字符串)

strtoupper(将所有字母变成大写)

strtolower

ucfirst(将字符串的首字母变成大写)

ucwords(将字符串中每个单词的首字母变成大写)

strrev(反转字符串,其实不是很常用)

substr_replace(替换字符串的子串,注意与str_replace的区别)

strip_tags(去除html和php标记,可以选择保留想要的标签)

trim(去除空格)

14. 正则表达式

贪婪模式与非贪婪模式

默认情况下,正则表达式会采用贪婪模式,使用?或U修饰符可以实现非贪婪模式。
比如a后面有多个b,”abbbbbbbb”。默认/a.+/则会匹配到最后一个b,

1
2
3
4
5
6
7
8
9
<?php
$pattern1 = '/a.+/';
$pattern2 = '/a.+?/';
$subject = 'abbbbbbbbb';
$matches = array();
var_dump(preg_match($pattern1, $subject,$matches));
var_dump($matches);
var_dump(preg_match($pattern2, $subject,$matches));
var_dump($matches);

运行结果:

1
2
3
4
5
6
7
8
9
10
int(1)
array(1) {
[0]=>
string(10) "abbbbbbbbb"
}
int(1)
array(1) {
[0]=>
string(2) "ab"
}

preg_match和preg_match_all区别

用法都是相同的:func($pattern, $subject, &$matches, $flags, $offset)
返回值:正确匹配返回1,否则返回0
不同:preg_match会使用$pattern对subject进行一次匹配,subject有多个子串也满足$pattern,matches也只会返回第一个子组的所有匹配结果,
preg_match_all则会执行全局正则表达式匹配。

1
2
3
4
5
6
7
<?php
$pattern = "|<[^>]+>(.*)</[^>]+>|U";
$subject = "<b>example: </b><div align=left>this is a test</div>";
preg_match($pattern, $subject, $matches);
var_dump($matches);
preg_match_all($pattern, $subject, $matches);
var_dump($matches);

运行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
array(2) {//第一组
[0]=>
string(16) "<b>example: </b>"
[1]=>
string(9) "example: "
}

array(2) {
[0]=>
array(2) {//全局完全匹配
[0]=>
string(16) "<b>example: </b>"
[1]=>
string(36) "<div align=left>this is a test</div>"
}
[1]=>
array(2) {
[0]=>
string(9) "example: "//匹配的子组
[1]=>
string(14) "this is a test"//匹配的子组
}
}

常用正则表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
网址(URL)	[a-zA-z]+://[^\s]*
IP地址(IP Address) ((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)
电子邮件(Email) \w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
QQ号码 [1-9]\d{4,}
HTML标记(包含内容或自闭合) <(.*)(.*)>.*<\/\1>|<(.*) \/>
密码(由数字/大写字母/小写字母/标点符号组成,四种都必有,8位以上) (?=^.{8,}$)(?=.*\d)(?=.*\W+)(?=.*[A-Z])(?=.*[a-z])(?!.*\n).*$
日期(年-月-日) (\d{4}|\d{2})-((1[0-2])|(0?[1-9]))-(([12][0-9])|(3[01])|(0?[1-9]))
日期(月/日/年) ((1[0-2])|(0?[1-9]))/(([12][0-9])|(3[01])|(0?[1-9]))/(\d{4}|\d{2})
时间(小时:分钟, 24小时制) ((1|0?)[0-9]|2[0-3]):([0-5][0-9])
汉字(字符) [\u4e00-\u9fa5]
中文及全角标点符号(字符) [\u3000-\u301e\ufe10-\ufe19\ufe30-\ufe44\ufe50-\ufe6b\uff01-\uffee]
中国大陆固定电话号码 (\d{4}-|\d{3}-)?(\d{8}|\d{7})
中国大陆手机号码 1\d{10}
中国大陆邮政编码 [1-9]\d{5}
中国大陆身份证号(15位或18位) \d{15}(\d\d[0-9xX])?
非负整数(正整数或零) \d+
正整数 [0-9]*[1-9][0-9]*
负整数 -[0-9]*[1-9][0-9]*
整数 -?\d+
小数 (-?\d+)(\.\d+)?
不包含abc的单词 \b((?!abc)\w)+\b

参考

15. php自动加载方法

尝试加载未定义的类

__autoload方法

PHP7.2.0以后会丢弃

1
2
3
4
5
6
$db = new DB();
function __autoload($className)
{
echo $className;
exit();
}

spl_autoload_register

小的项目用autoload自动加载还可以,一个项目中只能用一个autoload方法。大的项目就需要使用spl_autoload_register指定函数进行自动加载的操作了。spl_autoload_register — 注册给定的函数作为 __autoload 的实现
普通方法

1
2
3
4
5
6
7
function load1($className)
{
echo 1;
require $className . '.php';
}
spl_autoload_register('load1'); //将load1函数注册到自动加载队列中。
$db = new DB(); //找不到DB类,就会自动去调用刚注册的load1函数了

类的静态方法

1
2
3
4
5
6
7
8
9
10
11
class autoloading{
//必须是静态方法,不然报错
public static function load($className)
{
require $className . '.php';
}
}
//2种方法都可以
spl_autoload_register(array('autoloading','load'));
spl_autoload_register('autoloading::load');
$db = new DB(); //会自动找到

参考