Maison >développement back-end >tutoriel php >PHP面试总结,php面试_PHP教程
从8月15号来到北京一直到今天,一月有余。来的这段时间一直准备笔试面试,大大小小的公司,乱七八糟面了10多家,近期才安顿下来。面试的这段时间感觉自己成长了不少。初来到这个陌生的城市一脸茫然,不会乘地铁、不会有挤公交、不会恰如其分的生活。。。
面试是进入职场的第一道坎,因为我本身学校太一般的问题在面试中遇到了各种不爽,和那些高学历的相比自己真是信心大跌。我面试的方向是php开发工程师,主要做网站后台、APP接口等。我所面试的公司、试题、心得都在我的个人网站上,感兴趣的可以看看:
PHP中几个输出函数echo,print(),print_r(),sprintf(),var_dump()的区别
1:echo:是语句不是函数,没有返回值,可输出多个变量值,不需要圆括号。不能输出数组和对象,只能打印简单类型(如int,string)。
2:print:是语句不是函数,有返回值 1 ,只能输出一个变量,不需要圆括号。不能输出数组和对象,只能打印简单类型(如int,string)。
3:print_r:是函数,可以打印复合类型,例如:stirng、int、float、array、object等,
输出array时会用结构表示,而且可以通过print_r($str,true)来使print_r不输出而返回print_r处理后的值
4:printf:是函数,把文字格式化以后输出(参看C语言)
5:sprintf:是函数,跟printf相似,但不打印,而是返回格式化后的文字(该函数把格式化的字符串写写入一个变量中,而不是输出来),其 他的与printf一样。
例如: $str = "Hello"; $number = 123;
$txt = sprintf("%s world. Day number %u",$str,$number); //输出: Hello world. Day number 123
6:var_dump():函数,输出变量的内容、类型或字符串的内容、类型、长度。常用来调试。
写个函数来解决多线程同时读写一个文件的问题。
<span> 1</span> <?<span>php </span><span> 2</span> <span>$fp</span> = <span>fopen</span>("/tmp/lock.txt","w+"<span>); </span><span> 3</span> <span>if</span>(<span>flock</span>(<span>$fp</span>, LOCK_EX)){<span>//</span><span> 进行排它型锁定</span> <span> 4</span> <span>fwrite</span>(<span>$fp</span>,"Write something here\n"<span>); </span><span> 5</span> <span>flock</span>(<span>$fp</span>, LOCK_UN);<span>//</span><span> 释放锁定</span> <span> 6</span> }<span>else</span><span>{ </span><span> 7</span> <span>echo</span> "Couldn't lock the file !"<span>; </span><span> 8</span> <span> } </span><span> 9</span> <span>fclose</span>(<span>$fp</span><span>); </span><span>10</span> ?>
禁掉cookie的session使用方案,设置session过期的方法,对应函数:
通过 url 传值,把session id附加到url上(缺点:整个站点中不能有纯静态页面,因为纯静态页面session id 将无法继续传到下一页面) 通过隐藏表单,把session id 放到表单的隐藏文本框中同表单一块提交过去(缺点:不适用标签这种直接跳转的非表单的情况) 直接配置php.ini文件,将php.ini文件里的session.use_trans_sid= 0设为1,(好像在win上不支持) 用文件、数据库等形式保存Session ID,在跨页过程中手动调用<span> 1</span> 第一种 <span>setcookie</span><span>() 直接用setcookie设置session id的生命周期。 </span><span> 2</span> <span> 3</span> <span>$lifetime</span>=60; <span>//</span><span>保存1分钟 </span> <span> 4</span> <span>session_start</span><span>(); </span><span> 5</span> <span>setcookie</span>(<span>session_name</span>(), <span>session_id</span>(), <span>time</span>()+<span>$lifetime</span>, "/"<span>); </span><span> 6</span> 第二种 <span>session_set_cookie_params</span><span>() </span><span> 7</span> <span>$lifetime</span>=60;<span>//</span><span>保存1分钟</span> <span> 8</span> <span>session_set_cookie_params</span>(<span>$lifetime</span><span>); </span><span> 9</span> <span>session_start</span><span>(); </span><span>10</span> <span>session_regenerate_id</span>(<span>true</span><span>); </span><span>11</span> 其中session_regenerate_id();方法用于改变当前session_id的值,并保留session中数组的值。参数默认为 <span>false</span>,如果设置为true则改变session_id的值,并清空当前session数组。
json格式数据有哪些特点
JSON 一种轻量级的数据交换格式。它基于ECMAScript的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C、C++、C#、Java、JavaScript、Perl、 Python等)。这些特性使JSON成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成(网络传输速率)。
JSON的结构基于下面两点
1. "名称/值"对的集合 不同语言中,它被理解为对象(object),记录(record),结构(struct),字典(dictionary),哈希表(hash table),键列表(keyed list)等PHP 如何获取客户端的IP地址,
用$_SERVER获取的IP地址有什么问题?
$_SERVER['REMOTE_ADDR'] ; 通过全局数组来获得
getenv('REMOTE_ADDR') ; 通过环境变量来获得
当客户机使用代理的时候获取不到真实的IP地址
写一个函数,可以遍历文件夹下的所有文件和文件夹。
<span> 1</span> <span>function</span> get_dir_info(<span>$path</span><span>){ </span><span> 2</span> <span>$handle</span> = <span>opendir</span>(<span>$path</span>);<span>//</span><span>打开目录返回句柄</span> <span> 3</span> <span>while</span>((<span>$content</span> = <span>readdir</span>(<span>$handle</span>))!== <span>false</span><span>){ </span><span> 4</span> <span>$new_dir</span> = <span>$path</span> . DIRECTORY_SEPARATOR . <span>$content</span><span>; </span><span> 5</span> <span>if</span>(<span>$content</span> == '..' || <span>$content</span> == '.'<span>){ </span><span> 6</span> <span>continue</span><span>; </span><span> 7</span> <span> } </span><span> 8</span> <span>if</span>(<span>is_dir</span>(<span>$new_dir</span><span>)){ </span><span> 9</span> <span>echo</span> "<br>目录:".<span>$new_dir</span> . '<br>'<span>; </span><span>10</span> get_dir_info(<span>$new_dir</span><span>); </span><span>11</span> }<span>else</span><span>{ </span><span>12</span> <span>echo</span> "文件:".<span>$path</span>.':'.<span>$content</span> .'<br>'<span>; </span><span>13</span> <span> } </span><span>14</span> <span> } </span><span>15</span> <span> } </span><span>16</span> get_dir_info(<span>$dir</span>);
有mail.log的一个文档,内容为若干邮件地址,用’\n’分隔换行。挑选sina.com的地址(包括从文件读取、过滤到列印出来)。
思路1:用正则表达式(比较慢,效率地,不推荐用)
思路2:cat mail.log | grep sina.com
PHP缓存技术有哪些? tp是局部还是完全缓存?
1. 全页面静态化缓存,也就是将页面全部生成html静态页面,用户访问时直接访问的静态页面,而不会去走php服务器解析的流程
一群猴子排成一圈,按1,2,…,n依次编号。然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数,再数到第m只,在把它踢出去…,如此不停 的进行下去,直到最后只剩下一只猴子为止,那只猴子就叫做大王。要求编程模拟此过程,输入m、n, 输出最后那个大王的编号。
<span> 1</span> <<span>?php </span><span> 2</span> <span>function</span> fuhuan(<span>$allnum</span>, <span>$ti</span><span>){ </span><span> 3</span> <span>$arr</span> = <span>array</span><span>(); </span><span> 4</span> <span>for</span>(<span>$i</span> = 0; <span>$i</span> < <span>$allnum</span>; <span>$i</span>++<span>){ </span><span> 5</span> <span>$arr</span>[<span>$i</span>] = <span>$i</span><span>; </span><span> 6</span> <span> } </span><span> 7</span> <span> 8</span> <span>$nums</span> = 1<span>; </span><span> 9</span> <span>while</span>(<span>count</span>(<span>$arr</span>) > 1<span>){ </span><span>10</span> <span>foreach</span> (<span>$arr</span> <span>as</span> <span>$key</span> => <span>$value</span><span>) { </span><span>11</span> <span>if</span>(<span>$nums</span> == <span>$ti</span><span>){ </span><span>12</span> <span>unset</span>(<span>$arr</span>[<span>$key</span><span>]); </span><span>13</span> <span>$nums</span> = 1<span>; </span><span>14</span> }<span>else</span><span>{ </span><span>15</span> <span>$nums</span>++<span>; </span><span>16</span> <span> } </span><span>17</span> <span> } </span><span>18</span> <span> } </span><span>19</span> <span>$new_arr</span> = <span>array_values</span>(<span>$arr</span><span>); </span><span>20</span> <span>var_dump</span>(<span>$new_arr</span>[0] + 1<span>); </span><span>21</span> <span> } </span><span>22</span> fuhuan(10,10);
isset() 、empty()与is_null的区别
1、当变量未定义时,is_null()和“参数本身”是不允许作为参数判断的,会报Notice警告错误;
2、empty,isset首先都会检查变量是否存在,然后对变量值进行检测。而is_null 和 “参数本身”只是直接检查变量值,是否为null,因此如果变量未定义就会出现错误!
3、isset():仅当null和未定义,返回false;
4、empty():""、0、"0"、NULL、FALSE、array(),未定义,均返回false;
5、is_null():仅判断是否为null,未定义 报警告;
6、变量本身作为参数,与empty()一致,但接受未定义变量时,报警告;
求两个文件的相对路径
<span> 1</span> getpath('/a/b/c/d/e.php', '/a/d/12/34/c.php'<span>); </span><span> 2</span> <span> 3</span> <span>function</span> getpath(<span>$a</span>, <span>$b</span><span>){ </span><span> 4</span> <span>$aarr</span> = <span>explode</span>('/', <span>$a</span><span>); </span><span> 5</span> <span>$barr</span> = <span>explode</span>('/', <span>$b</span><span>); </span><span> 6</span> <span>$count</span> = <span>count</span>(<span>$barr</span>) - 2<span>; </span><span> 7</span> <span>$pathinfo</span> = ''<span>; </span><span> 8</span> <span>for</span>(<span>$i</span> = 1; <span>$i</span> <= <span>$count</span>; <span>$i</span>++<span>){ </span><span> 9</span> <span>if</span>(<span>$aarr</span>[<span>$i</span>] == <span>$barr</span>[<span>$i</span><span>]){ </span><span>10</span> <span>$pathinfo</span> .= '../'<span>; </span><span>11</span> }<span>else</span><span>{ </span><span>12</span> <span>$pathinfo</span> .= <span>$barr</span>[<span>$i</span>] . '/'<span>; </span><span>13</span> <span> } </span><span>14</span> <span> } </span><span>15</span> <span>echo</span> <span>$pathinfo</span><span>; </span><span>16</span> }
MVC的优缺点 1、 MVC的优点
问题:程序需要定制;每次请求都进行数据库读写开销不小,另外数据库是一个单点,可以做数据库的hash来解 决这个问题。
2:使用 memcached来保存session, 这种方式跟数据库类似,内存存取性能比数据库好很多。
问题:程序需要定制,增加 了工作量;存入memcached中的数据都需要序列化,效率较低,断电或者重启电脑容易丢失数据;
3: 通过加密的cookie,在A服务器上登录,在用户的浏览器上添加加密的cookie,当用户访问B服务器时,检查有无Session,如果没有,就检验 Cookie是否有效,Cookie有效的话就在B服务器上重建session。简单,高效, 服务器的压力减小了,因为session数据不存在服务器磁盘上。根本就不会出现session读取不到的问题。
问题:网络请求占用很多。每次请求时,客户端都要通过cookie发送session数据给服务器,session中数据不能太多,浏览器对cookie 的大
小存在限制。不适合高访问量的情况,因为高访问量的情况下。
正则表达式
匹配中文字符的正则表达式: [\u4e00-\u9fa5]
匹配双字节字符(包括汉字在内):[^\x00-\xff]
匹配空行的正则表达式:\n[\s| ]*\r
匹配HTML标记的正则表达式:/.*|/
匹配首尾空格的正则表达式:(^\s*)|(\s*$)
匹配Email地址的正则表达式:\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
匹配网址URL的正则表达式:^[a-zA-z]+://(\\w+(-\\w+)*)(\\.(\\w+(-\\w+)*))*(\\?\\S*)?$
匹配帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
匹配国内电话号码:(\d{3}-|\d{4}-)?(\d{8}|\d{7})?
匹配腾讯QQ号:^[1-9]*[1-9][0-9]*$
core文件是什么,有什么用?
<span> core是unix系统的内核。当你的程序出现内存越界的时候,操作系统会中止你的进程,并将当前内存状态倒出到core文件中,以便进一步分析。程序员可以通过core文件来找出问题所在。它记录了程序挂掉时详细的状态描述。</span>
<span><strong>什么是core dump</strong> Core的意思是内存, Dump的意思是扔出来, 堆出来。开发和使用Unix程序时, 有时程序莫名其妙的down了, 却没有任何的提示(有时候会提示core dumped). 这时候可以查看一下有没有形如core.进程号的文件生成, 这个文件便是操作系统把程序down掉时的内存内容扔出来生成的,它可以做为调试程序的参考. core dump又叫核心转储, 当程序运行过程中发生异常, 程序异常退出时, 由操作系统把程序当前的内存状况存储在一个core文件中, 叫core dump。如何使用core文件 gdb -c core文件路径 [应用程序的路径],进去后输入where回车, 就可以显示程序在哪一行当掉的, 在哪个函数中.</span>
<span><strong>为什么没有core文件生成呢?</strong> core文件的生成跟你当前系统的环境设置有关系, 可以用下面的语句设置一下, 然后再运行程序便成生成core文件.</span>
<span><strong>ulimit -c unlimited</strong> core文件生成的位置一般于运行程序的路径相同, 文件名一般为core.进程号</span>
不用core文件,程序出了问题产生信号是否知道?答:内核向进程发信号嘛。
共享内存除了文件映射还有什么方式?
共享内存对象映射。
二者有什么区别:
答:内存映射文件是由一个文件到一块内存的映射,使应用程序可以通过内存指针对磁盘上的文件进行访问,其过程就如同对加载了文件的内存的访问,因此内存文件映射非常适合于用来管理大文件。
请解释下列10个shell命令的用途
cat:把一个或多个文件内容显示到标准输出
chmod:改变文件属性
chgrp:改变用户分组
grep:在文件内进行搜索
wc:命令的功能为统计指定文件中的字节数、字数、行数, 并将统计结果显示输出。
Linux文件属性有哪些?(共十位)
-rw-r--r--那个是权限符号,总共是- --- --- ---这几个位。
第一个短横处是文件类型识别符:-表示普通文件;c表示字符设备(character);b表示块设备(block);d表示目录 (directory);l表示链接文件(link);后面第一个三个连续的短横是用户权限位(User),第二个三个连续短横是组权限位 (Group),第三个三个连续短横是其他权限位(Other)。每个权限位有三个权限,r(读权限),w(写权限),x(执行权限)。如果每个权限位都 有权限存在,那么满权限的情况就是:-rwxrwxrwx;权限为空的情况就是- --- --- ---。
权限的设定可以用chmod命令,其格式位:chmod ugoa+/-/=rwx filename/directory。例如:
一个文件aaa具有完全空的权限- --- --- ---。
chmod u+rw aaa(给用户权限位设置读写权限,其权限表示为:- rw- --- ---)
chmod g+r aaa(给组设置权限为可读,其权限表示为:- --- r-- ---)
chmod ugo+rw aaa(给用户,组,其它用户或组设置权限为读写,权限表示为:- rw- rw- rw-)
如果aaa具有满权限- rwx rwx rwx。
chmod u-x aaa(去掉用户可执行权限,权限表示为:- rw- rwx rwx)
如果要给aaa赋予制定权限- rwx r-x r-x,命令为:
chmod u=rwx,go=rx aaa
Apache与Nginx的优缺点比较
cgi在2000年或更早的时候用得比较多, 以前web服务器一般只处理静态的请求,web服务器会根据这次请求的内容,然后会fork一个新进程来运行外部c程序 (或perl脚本...), 这个进程会把处理完的数据返回给web服务器,最后web服务器把内容发送给用户,刚才fork的进程也随之退出。 如果下次用户还请求改动态脚本,那么web服务器又再次fork一个新进程,周而复始的进行。
后来出现了一种更高级的方式是, web服务器可以内置perl解释器或php解释器。 也就是说这些解释器做成模块的方式,web服务器会在启动的时候就启动这些解释器。 当有新的动态请求进来时,web服务器就是自己解析这些perl或php脚本,省得重新fork一个进程,效率提高了。
fastcgi的方式是,web服务器收到一个请求时,他不会重新fork一个进程(因为这个进程在web服务器启动时就开启了,而且不会退 出),web服务器直接把内容传递给这个进程(进程间通信,但fastcgi使用了别的方式,tcp方式通信),这个进程收到请求后进行处理,把结果返回 给web服务器,最后自己接着等待下一个请求的到来,而不是退出。
fastcgi跟cgi的区别是:
在web服务器方面 在对数据进行处理的进程方面
cgi fork一个新的进程进行处理 读取参数,处理数据,然后就结束生命期
fastcgi 用tcp方式跟远程机子上的进程或本地进程建立连接 要开启tcp端口,进入循环,等待数据的到来,处理数据
举个例子: 服务端现在有个10万个字单词, 客户每次会发来一个字符串,问以这个字符串为前缀的单词有多少个。 那么可以写一个程序,这个程序会建一棵trie树,然后每次用户请求过来时可以直接到这个trie去查找。 但是如果以cgi的方式的话,这次请求结束后这课trie也就没了,等下次再启动该进程时,又要新建一棵trie树,这样的效率就太低下了。 而用fastcgi的方式的话,这课trie树在进程启动时建立,以后就可以直接在trie树上查询指定的前缀了。
select, poll和epoll的区别 select
select最早于1983年出现在4.2BSD中,它通过一个select()系统调用来监视多个文件描述符的数组,当select()返回后,该数组中就绪的文件描述符便会被内核修改标志位,使得进程可以获得这些文件描述符从而进行后续的读写操作。
select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点,事实上从现在看来,这也是它所剩不多的优点之一。
select的一个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,不过可以通过修改宏定义甚至重新编译内核的方式提升这一限制。
另外,select()所维护的存储大量文件描述符的数据结构,随着文件描述符数量的增大,其复制的开销也线性增长。同时,由于网络响应时间的延迟 使得大量TCP连接处于非活跃状态,但调用select()会对所有socket进行一次线性扫描,所以这也浪费了一定的开销。
poll在1986年诞生于System V Release 3,它和select在本质上没有多大差别,但是poll没有最大文件描述符数量的限制。
poll和select同样存在一个缺点就是,包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。
另外,select()和poll()将就绪的文件描述符告诉进程后,如果进程没有对其进行IO操作,那么下次调用select()和poll() 的时候将再次报告这些文件描述符,所以它们一般不会丢失就绪的消息,这种方式称为水平触发(Level Triggered)。
直到Linux2.6才出现了由内核直接支持的实现方法,那就是epoll,它几乎具备了之前所说的一切优点,被公认为Linux2.6下性能最好的多路I/O就绪通知方法。
epoll可以同时支持水平触发和边缘触发(Edge Triggered,只告诉进程哪些文件描述符刚刚变为就绪状态,它只说一遍,如果我们没有采取行动,那么它将不会再次告知,这种方式称为边缘触发),理论上边缘触发的性能要更高一些,但是代码实现相当复杂。
epoll同样只告知那些就绪的文件描述符,而且当我们调用epoll_wait()获得就绪文件描述符时,返回的不是实际的描述符,而是一个代表 就绪描述符数量的值,你只需要去epoll指定的一个数组中依次取得相应数量的文件描述符即可,这里也使用了内存映射(mmap)技术,这样便彻底省掉了 这些文件描述符在系统调用时复制的开销。
另一个本质的改进在于epoll采用基于事件的就绪通知方式。在select/poll中,进程只有在调用一定的方法后,内核才对所有监视的文件描 述符进行扫描,而epoll事先通过epoll_ctl()来注册一个文件描述符,一旦基于某个文件描述符就绪时,内核会采用类似callback的回调 机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。
Memcache和Redis区别