石家庄php面试题,PHP面试题

';

print_r($arr);

类和对象

题1 接口与抽象类的区别是什么?

抽象类:

抽象类是不能被实例化的类,只能作为其他类的父类来使用,抽象类是通过关键字abstract来声明

抽象类与普通类类似,都包含成员变量和成员方法,两者的区别在于,抽象类中至少包含一个抽象方法

抽象方法没有方法体,该方法天生就是要被子类重写的

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

子类继承抽象类使用extends

接口:

接口是通过interface关键字来声明,接口中的成员常量和方法都是public的,方法可以不写关键字public

接口中的方法也是没有方法体的,接口中的方法也是天生要被子类实现的

接口能实现多继承

子类实现接口使用implements

题2 以下代码会输出什么

class Dog {

public $age;

public function __construct($age) {

$this->age = $age;

}

}

function test($dog) {

$dog->age = 10;

}

$dog = new Dog(100);

test($dog);

echo $dog->age;

题3 以下代码会输出什么

class Dog {

public $age;

public function __construct($age) {

$this->age = $age;

}

}

function test($dog) {

$dog = new Dog(10);

}

$dog = new Dog(100);

test($dog);

echo $dog->age;

题4 以下代码会输出什么

class Dog {

public $age;

public function __construct($age) {

$this->age = $age;

}

}

function test($dog) {

$dog = null;

}

$dog = new Dog(100);

test($dog);

echo $dog->age;

题5 以下代码会输出什么

class Dog {

public $age;

public function __construct($age) {

$this->age = $age;

}

}

function test(&$dog) {

$dog = new Dog(10);

}

$dog = new Dog(100);

test($dog);

echo $dog->age;

错误和异常

缓存与静态化

时间日期

题1 知道一天的日期,求任意一天叮得日期

题2 用php打印出前一天的时间格式

文件

题1 写一个函数,算出两个文件的相对路径

题2 写一个函数,能够遍历一个文件夹下的所有文件和子文件夹

}

$dir = 'D:practise/test';

题3 删除某目录下的子目录及文件

分析:需要使用到的目录函数包括is_dir()、opendir()、readdir()、rmdir()、closedir();需要用到的文件函数包括is_file()、unlink(),使用递归算法

function deldir($dir) {

if(is_dir($dir)) {

$handle = opendir($dir);

while (false !== ($file = readdir($handle))) {

if($file == '.' || $file == '..'){

continue;

}

if(is_dir($dir.'/'.$file)) {

deldir($dir.'/'.$file);

} else {

unlink($dir.'/'.$file);

}

}

closedir($handle);

rmdir($dir);

} elseif(is_file($dir)) {

unlink($dir);

} else {

return 'error dir';

}

return 'del complete';

}

题4 php中Web上传文件的原理是什么,如何限制上传文件的大小?

分析:

通过form表单使用POST方法上传,可以使用户上传文本和二进制文件

客户端html部分如下

服务端通过$\_FILES接收通过HTTP上传到服务器的文件,上传的内容存储在$_FILES'xx'中,然后再通过move_uploaded_file,将上传的文件移动到新位置:

if(! empty($_FILES)) {

if(is_uploaded_file($_FILES['userfile']['tmp_name'])) {

if($_FILES['userfile']['error'] == UPLOAD_ERR_OK) {

$upload_dir = './upload';

$tmp_name = $_FILES['userfile']['tmp_name'];

$name = $_FILES['userfile']['name'];

if(move_uploaded_file($tmp_name, $upload_dir.'/'.$name)) {

echo 'success.';

} else {

echo 'error';

}

}

}

}

有多个配置可以限制上传文件的大小,在php.ini中:

post_max_size:(php 5.5.12)默认3M

upload_max_filesize:(php 5.5.12)默认64M

max_execution_time:必要的情况下还需要修改该配置,设置了脚本被解析器中止之前允许的最大执行时间,单位秒。(php 5.5.12)默认120

memory_limit:(php 5.5.12)默认128M

Cookie和Session

题1 禁用COOKIE 后 SEESION 还能用吗?

分析:在默认情况下(PHP>=4.3.0),php.ini中session.use_only_cookies的值为1,也就是说在不更改任何配置的情况下,禁用了浏览器的 Cookie 功能,是没有办法使用 Session 的,因为默认情况下,Session_ID 保存在 Cookie 中。如果希望在禁用了 Cookie 之后仍然可以使用 Session,至少需要更改php.ini中的以下几个配置:session.use_cookies改为0、session.use_only_cookies改为0、·session.use_trans_id·改为1(表示Session_ID通过url的参数进行传递)。使用url传递Session_ID相比使用Cookie传递Session_ID来说非常不安全,一是完全暴露Session_ID,二是容易遭到Session固定攻击。

题2 如何设置session的过期时间

分析:如果没有设定Session的生存周期,保存Session_ID的Cookie是保存在内存中的,关闭浏览器后该ID自动注销。如果客户端没有禁用Cookie,Cookie在启动Session时扮演的是存储Session_ID和Session生命周期的角色,可以手动设置Session的生存期:

$lifetime = 24 * 3600;

set_cookie(session_name(), session_id(), time() + $lifetime, '/');

也可以使用 session_set_cookie_params()函数设置Session的生存期。

Session过期后,PHP会对其进行回收,因此Session并不是随着浏览器的关闭而消失。

如果浏览器禁用了Cookie,那么Session的生命周期会随着浏览器进程的结束而结束,即只要关闭了浏览器,再次请求页面就要重新注册Session。

题3 请介绍Session的原理

分析:由于HTTP协议的无状态特性,协议本身并不支持服务器端保存客户端的状态信息,为了让服务器端和客户端保持联系,引入了Session的概念,用其来保持客户端的状态信息。Session通过一个成为PHPSESSID(可以更改名称)的Cookie和服务器端联系。Session通过Session_ID判断用户。

当使用了session_start()函数,用户第一次访问站点时,PHP会为用户创建一个session ID,这就是该用户的唯一标识,每一个访问的用户都会得到一个自己唯一的session ID。session ID会存放在响应头(Response)里的cookie中,之后发送给客户端,于是客户端就有了该用户在这个站点的session ID。当用户第二次访问该站点时,浏览器会带着本地存放的cookie(里面存有上次得到的session ID)随着请求(Request)一起发送到服务器,服务端接到请求后会检测是否有session ID,如果有就会找到响应的session文件,把其中的信息读取出来;如果没有就重新创建一个Session_ID。

题4 如何注销Session

分析:Session的注销分为4个步骤:

1.开启Session,所有有关Session的操作都需要先开启Session(除非在php.ini中设置session.auto_start为1,默认为0)

session_start();

2.删除所有的session变量,即把session数组清空

$_SESSION = array();

3.如果是基于Cookie的Session,则需要把保存Session_ID的Cookie删除

if(isset($_COOKIE[session_name()])) {

setcookie(session_name(), '', time() - 1, '/');

}

4.彻底销毁Session

session_destroy();

题5 简述Session的回收机制

分析:如果用户退出网站时没有主动注销帐号,那么Session的回收将是被动的。php.ini中和Session回收有关的配置有:

session.gc_maxlifetime:表示 Session 文件的过期时间,默认为 1440 秒即 24分钟

session.gc_probability:默认值为1

session.gc_divisor:默认值为1000

后面两个配置代表 session_start() 函数每调用 1000 次触发一次 Session 文件的全部扫描,把过期的 Session 文件删除。过期的 Session 文件的判断标准是:文件的修改时间和当前时间相差是否大于 session.gc_maxlifetime。当用户每进行一个操作哪怕是一个刷新页面的动作时,都会修改 Session 文件的修改时间。对于设置分级目录存储的Session,php不会自动回收,需要自己实现回收机制。

题6 session共享问题解决方案

分析:可以将Session入库(普通数据库、内存表),或者使用内存存储系统例如Redis来存储Session,达到服务器间Session的共享。通过session_save_handler()函数实现。

题7 大型网站中Session方面应注意什么

分析:大型网站有很多衡量标准,访问量是其中一个。对于大访问量的网站,如果Session按照默认的设置存储,会影响系统性能。默认情况下,Session由文件的形式保存在指定的目录下,如果同一个目录下文件数超过10000,文件的定位将会非常耗时,可以通过修改php.ini中session.save_path将Session文件存储在多级目录下;也可以保存在数据库中;最好的方式是保存在key-value形式的内存数据库中,例如Redis。

另一个方面,大型网站一般有多台服务器,要做好Session的同步。如果是使用数据库或者NoSQL来存储Session,Session的同步会比较容易。如果是文件形式保存Session文件,可以使用NFS或者FastDFS等文件系统存储Session文件。

题8 Session和Cookie的联系和区别

分析:

如果不修改php的配置,则Session是基于Cookie的:Session的唯一标识Session_ID保存在Cookie中,通过Cookie中的Session_ID来维持服务器端和客户端之间的状态。

可以通过设置保存Session_ID的Cookie的过期时间来设置Session的生存周期。

Cookie通过文件或者数据库的形式保存客户端,Session通过文件、数据库等形式保存在服务器端。

题9 服务器端设置了cookie的过期时间,然后修改本地时间小于cookie过期时间,cookie会不会被删除

分析:

会。因为Cookie的过期时间依赖于客户端时钟的标准。

题10 如何设置Cookie的过期时间,关闭浏览器Cookie会消失吗

分析:

通过setcookie()函数的第三个参数expire设置Cookie的过期时间,单位为秒,例如

setcookie('username', 'dee', time() + 24 * 3600, '/');

这段代码表示name为username的Cookie,会在24小时后过期。

如果要删除某个Cookie,同样使用setcookie()函数,例如

setcookie('user', '', time() - 1, '/');

只需要把Cookie的过期时间改为小于当前的一个时间即可。

HTTP协议

题1 HTTP状态码

题2 get请求和post请求的区别

算法

题1 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

分析:可以用递归和递推两种方法实现。

① 递归

如果台阶只有 1 级,则只有 1种跳法,如果台阶有2级,则有2种跳法(一次1级跳2次或一次2级)。把n级台阶时的跳法设为f(n),如果第一次只跳1级,则后面的n-1级的跳法为f(n-1),如果第一次跳2级,则后面n-2级的跳法为f(n-2)。当n > 2时,n级台阶的跳法为f(n) = f(n-1) + f(n-2),这就是一个斐波那契数列的问题

② 递推

题2 用一段代码实现无限级分类

分析:此题考察递归算法。

1, 'title' => '北京市', 'pid' => 0],

['id' => 2, 'title' => '朝阳区', 'pid' => 1],

['id' => 3, 'title' => '海淀区', 'pid' => 1],

['id' => 4, 'title' => '江西省', 'pid' => 0],

['id' => 5, 'title' => '九江市', 'pid' => 4],

['id' => 6, 'title' => '浔阳区', 'pid' => 5],

['id' => 7, 'title' => '庐山区', 'pid' => 5],

['id' => 8, 'title' => '南昌市', 'pid' => 4],

['id' => 9, 'title' => '河北省', 'pid' => 0],

['id' => 10, 'title' => '保定市', 'pid' => 9],

['id' => 11, 'title' => '石家庄市', 'pid' => 9],

['id' => 12, 'title' => '江苏省', 'pid' => 0],

['id' => 13, 'title' => '浙江省', 'pid' => 0],

];

echo ''; print_r(level_layer($data));

题3 一群猴子排成一圈,按 1,2,...,n 依次编号。然后从第 1 只开始数,数到第 m 只,把它踢出圈,从它后面再开始数,再数到第 m 只,在把它踢出去...,如此不停的进行下去,直到最后只剩下一只猴子为止,那只猴子就叫做大王。要求编程模拟此过程,输入 m、n,输出最后那个大王的编号。

分析:这是一个“约瑟夫环”问题,可以使用循环队列、循环链表等多种方法来解决,这里使用循环链表。

number = $number;

$this->name = $name;

}

}

// 初始化链表,添加元素

function init(&$first, $n) {

$current = null;

for($i = 0; $i < $n; $i++) {

$monkey = new Monkey($i + 1);

if($i == 0) {

$first = $monkey;

$first->next = $monkey; // 只有一个元素时

$current = $first;

} else {

$current->next = $monkey;

$monkey->next = $first; // $monkey 是变化的

$current = $current->next;

}

}

}

// 显示链表

function showList($first) {

$current = $first;

while($current->next != $first) {

echo '猴子的编号是:',$current->number,'

';

$current = $current->next;

}

echo '猴子的编号是:',$current->number,'

';

}

// 删除元素

function delElement($first, $m, $start = 1) {

$tail = $first; // 指向尾部节点的引用,在first节点之前

while($tail->next != $first) {

$tail = $tail->next; // 把tail节点设置在first节点之前

}

// 从第几个元素开始数

for($i = 0; $i < $start - 1; $i++) {

$tail = $tail->next;

$first = $first->next;

}

while($tail != $first) { //当$tail==$first则说明只有最后一个元素

for($i = 0; $i < $m - 1; $i++) {

$tail = $tail->next;

$first = $first->next;

}

echo '

删除编号 '.$first->number,' 的元素';

// 跳过被删除的节点(first指向的节点)

$first = $first->next;

$tail->next = $first;

}

echo '

最后剩下的编号是: '.$tail->number;

}

$n = 4; // 元素的个数(猴子的数量)

$m = 3; // 每次数几个元素

$start = 1; // 从第几个元素开始数

$first = null; // 链表头部节点的引用

init($first, $n);

showList($first);

delElement($first, $m, $start);

题4 写一段php代码实现冒泡排序

解答:

function bubble($array) {

$count = count($array);

for($i = 0; $i < $count - 1; $i++) {

for($j = 0; $j < $count - 1 - $i; $j++) {

// 递减

if($array[$j] < $array[$j + 1]) {

$tmp = $array[$j];

$array[$j] = $array[$j + 1];

$array[$j + 1] = $tmp;

}

}

}

return $array;

}

题5 写一段php代码实现快速排序

/*快速排序*/

function quick_sort($array) {

// 递归到只有一个元素

if(count($array) <= 1) {

return $array;

}

$key = $array[0];

$left_arr = [];

$right_arr = [];

// 左边数组的元素都比右边数组的元素小

for($i = 1; $i < count($array); $i++) {

if($array[$i] <= $key) {

$left_arr[] = $array[$i];

} else {

$right_arr[] = $array[$i];

}

}

// 递归对左右两个数组分别进行排序

$left_arr = quick_sort($left_arr);

$right_arr = quick_sort($right_arr);

// 合并结果

return array_merge($left_arr, array($key), $right_arr);

}

$arr = [10, 21, 1, 3, 89, 27, 75, 45, 91, 200, 451, 37, 2];

var_dump(quick_sort($arr));

题6 写一段php代码实现二分查找

$array[$middle]) {

$start = $middle + 1;

}

}

return false;

}

题7 换硬币问题:如果有100元,可以使用1元、2元、5元、10元4种面额的零钱来兑换,有多少种兑换方法?

题8 鸡兔同笼问题

正则表达式

题1 请写一个函数验证电子邮件的格式是否正确

设计模式

题1 请用单态设计模式方法设计类满足如下需求,使用php代码编写类实现在每次对数据库连接的访问中都只能获取唯一的一个数据库连接,具体连接数据库的详细代码忽略,请写出主要逻辑代码。

MySQL

题1 where和having的区别

题2 内连接、左连接、右连接的区别

题3 mysql优化常见的方案

题4 explain的用法

题5 索引的种类和用法

题6 mysql的存储引擎Innodb和MyISAM的区别

题7

一个足球网站有一张新闻表news,字段包括新闻编号id、新闻分类cid、标题title、点击量click,现在需要对 news 表按照 cid (分类id)进行过分组,按照每组新闻的数量进行排序,同时取出每组点击量(click)最多的两篇新闻。

分析:

创建表

CREATE TABLE `news` (

`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '新闻编号',

`cid` int(11) NOT NULL COMMENT '分类编号 例如 1 世界足球新闻 2 英超新闻 3 西甲新闻',

`title` varchar(25) NOT NULL COMMENT '新闻标题',

`click` int(11) NOT NULL DEFAULT '0' COMMENT '点击量',

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=13 DEFAULT CHARSET=utf8;

表数据

INSERT INTO `news` VALUES ('1', '1', '法国2-0力克德国进决赛', '1888');

INSERT INTO `news` VALUES ('2', '2', '传曼联1亿英镑报价博格巴', '201');

INSERT INTO `news` VALUES ('3', '3', '队报:巴萨接近签法国国脚', '150');

INSERT INTO `news` VALUES ('4', '1', '克罗斯:德国队表现最好的一场', '100');

INSERT INTO `news` VALUES ('5', '1', '决赛对阵:法国vs葡萄牙', '205');

INSERT INTO `news` VALUES ('6', '1', '格列兹曼6场6球仅次普拉蒂尼', '211');

INSERT INTO `news` VALUES ('7', '1', '阿森纳法国双星赛后安慰厄齐尔', '188');

INSERT INTO `news` VALUES ('8', '2', '回声报:利物浦要求艾比交易中加入回购条款', '11');

INSERT INTO `news` VALUES ('9', '3', '普约尔:没有比巴萨更适合梅西的地方', '225');

INSERT INTO `news` VALUES ('10', '3', '皇家贝蒂斯有意狼堡前锋多斯特', '13');

INSERT INTO `news` VALUES ('11', '3', '哈维:我觉得梅西不会想离开巴萨的', '1000');

INSERT INTO `news` VALUES ('12', '2', '传温格已将西迪贝看作重点目标', '1200');

此题的需求是 1.按新闻分类分组 2.按照新闻分类下新闻数量给分好的组排序 3.排好序的分组还需要取出该组分类下点击量最多的两篇新闻

需求1 可以使用group by来进行分组

需求2 可以使用count()+group by,取出每组分类下新闻的数量

以上2个需求可以用一条sql完成

select *, count(*) as num from news group by cid order by num desc;

查询结果

可以看到已经按照数量num进行了排序

需求3 可以cid+click进行排序,这个需求可以用一条sql完成,用子查询实现

select a.* from news a

where (

select count(*) from news b where a.cid = b.cid and b.click > a.click

) < 2

order by cid, click desc;

查询结果

此时每个cid下点击量最多的两篇文章已经查询出来了,只不过查询的结果没有按照每个分类下新闻数量的多少来排序

只需要最后一步,把两个sql语句进行左(右)连接即可

select * from (

select a.* from news a

where (

select count(*) from news b where a.cid = b.cid and b.click > a.click

) < 2

order by cid, click desc

) tablea RIGHT JOIN (

select cid, count(*) as num from news group by cid order by num desc

) tableb on tablea.cid = tableb.cid

order by tableb.num desc, click desc;

查询结果:

题8 一张表有id,sortid,title,如何按照sortid进行分组,按照sortid数量进行排序,输出结果。

分析:此题和题6类似。

表结构

CREATE TABLE `test` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`title` varchar(25) NOT NULL,

`sortid` int(11) NOT NULL DEFAULT '0',

PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;

创建数据

INSERT INTO `test` VALUES ('1', 'title1', '106');

INSERT INTO `test` VALUES ('2', 'title2', '78');

INSERT INTO `test` VALUES ('3', 'title3', '56');

INSERT INTO `test` VALUES ('4', 'title4', '78');

INSERT INTO `test` VALUES ('5', 'title5', '78');

INSERT INTO `test` VALUES ('6', 'title6', '12');

INSERT INTO `test` VALUES ('7', 'title7', '56');

分三步创建sql

-- step 1

select a.* from test a

where (

select count(*) from test b where b.sortid > a.sortid

) < (select count(*) from test)

order by sortid;

-- step2

SELECT *, count(*) AS num, GROUP_CONCAT(id) AS ids FROM test GROUP BY sortid ORDER BY num;

-- final

select * from (

select a.* from test a

where (

select count(*) from test b where b.sortid > a.sortid

) < (select count(*) from test)

order by sortid

) tablea LEFT JOIN (

SELECT *, count(*) AS num, GROUP_CONCAT(id) AS ids FROM test GROUP BY sortid ORDER BY num

) tableb

on tablea.sortid = tableb.sortid

order by tableb.num asc;

此题没有要求列出每个分组的前N条数据,那就把每个分组下所有的数据都列出来,查询结果如下:

题9

有如下表及数据

name

subject

score

张三

数学

90

张三

语文

50

张三

地理

40

李四

语文

55

李四

政治

45

王五

政治

30

要求:查询出2门及2门以上不及格者的平均成绩

解析:

先查出所有人的平均分(AVG(score)),再找出每个人2门及2门以上不及格的数量(SUM(score<60)),最后筛选出数量大于等于2的人的信息(Having num>=2)

SELECT name, AVG(score) AS avg, SUM(score < 60) AS num

FROM result

GROUP BY name

HAVING num >= 2;

查询结果:

方法2:

SELECT `name`, AVG(score) AS avg FROM result WHERE `name` in (

SELECT name FROM result GROUP BY name HAVING SUM(score<60) >= 2

)

GROUP BY `name`;

查询结果:

方法3:复杂很多

SELECT tablea.name, tablea.avg, tableb.num FROM (

SELECT *,AVG(score) AS avg FROM result GROUP BY name

) tablea RIGHT JOIN (

SELECT *, COUNT(*) AS num FROM (

SELECT * FROM result WHERE score < 60

) a

GROUP BY a.name HAVING num >= 2

) tableb on tablea.name = tableb.name;

查询结果:

题10

有两张表:

表A

id

num

a

5

b

10

c

15

d

10

表B

id

num

b

5

c

15

d

20

e

99

要求查询出以下效果:

id

sum(num)

a

5

b

15

c

30

d

30

e

99

分析:

先使用UNION ALL将两张表联合起来,再使用SUM()+GROUP BY

SELECT id, SUM(num) FROM (

SELECT * FROM A

UNION ALL

SELECT * B

) AS tmp

GROUP BY tmp.id

;

题11 优化MySQL数据库的方法

综合/解决方案

题1 对于大流量的网站,可以采用哪些方法来解决访问量问题

安全

NoSQL

题1 为什么不能使用Memcached存储Session

题2 Redis相比Memcached有哪些优势

题3 Redis有哪些优点

题4 如何使用Redis存储Session

题5 Redis如何与MySQL同步

Linux

题1 查看系统负载有哪些命令

Node.js

JavaScript / jQuery

HTML / CSS

SVN / Git

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值