PHP 面试题整理 1

PHP 

这里是最近我去面试被问到的一些面试问题,我根据自己的记忆给大家整理下。好多题是先给大家结构,后面我在给大家出解释,不错 因为我要先弄清楚原因 .。整理时间(2017.9.11)

(1) 请指出下面代码的输出结果

<?php
    $a='hello';
    $b=&$a;
    unset($b);
    $b='world';
    echo $a;

结果:hello

(2) PHP抽象类和接口的概念 面试题会有选择题选出相关描述错误的

下面这些是需要知道的一些正确的概念:
抽象类:
1.定义一些方法,子类必须完全实现这个抽象中所有的方法,否则子类中还存在抽象方法,那么子类还是抽象类,还是不能实例化类;
2.不能从抽象类创建对象(不能实例化),它的意义在于被扩展
3.抽象类通常(抽象类可以没有抽象方法,但有抽象方法的类一定要声明为抽象类)具有抽象方法,方法中没有大括号。 即抽象方法,不能够含有函数体
4.某个类只要至少含有一个抽象方法,就必须声明为抽象类
5.在抽象类里面可以有不是抽象的方法和成员属性,但只要有一个方法是抽象的方法,这个类就必须声明为抽象类,使用“abstract”修饰
6、继承抽象类的子类,实现抽象方法的,必须跟该抽象方法具有相同或者更低的访问级别
7、一个抽象类继承另一个抽象类时,抽象方法不需要声明为抽象的

abstract class Demo{  
    var $test;  
    // 强制要求子类定义这些方法
    abstract function fun1();  
    abstract function fun2();

    // 普通方法(非抽象方法) 不强制子类定义
    public function printOut() {
        print $this->getValue() . "\n";
    }
    // 静态的普通方法 外部可以直接访问 Demo::bar();
    static  public function bar()
    {
         echo "test\n";
    }
}  

接口:
接口中一种特殊的抽象类, 抽象类又是一种特殊的类

1、 接口和抽象类是一样的作用
2、因为在PHP是单继承的, 如果使用抽象类,子类实现完抽象类就不能再去继承其它的类了。
3、 如果即想实现一些规范, 又想继承一个其他类。就要使用接口
4、 接口和抽象类的对比

  1. 作用相同,都不能创建对象, 都需要子类去实现
  2. 接口的声明和抽象类不一样
  3. 接口被实现的方式不一样
  4. 接口中的所有方法必须是抽象方法,只能声明抽象方法(不用使用abstract修饰)
  5. 接口中的成员属性,只能声明常量,不能声明变量
  6. 接口中的成员访问权限 都必须是public, 而抽象类中最低的权限protected
  7. 使用一个类去实现接口, 不是使用extends关键字, 而是使用implements这个词
  8. 如果子类是重写父接口中抽象方法,则使用implements, 用类实现接口,
    用抽象类实现部分接口接口功能 implements 。

    接口来用继承接口 extends

interface  A{
//这里定义接口常量,跟类常量完全一样  注意:接口中的成员属性 不能声明变量
const  P1 = 1;
const  P2 = 2;
....
//这里定义接口方法,且只能是“抽象”方法(无需使用abstract) 注意没有{}
function  f1();
function  f2($p1, $p2);
......
}

接口的使用分2种:
1,其他接口“继承”(extends)现有某个(或几个)接口——其实跟类的继承概念完全一样。
2,其他类,“实现”(implements)现有某个(或几个)接口——其实本质也是继承,只是被称为“实现”。

//1、接口继承接口
interface  B  extends  A {
//这里是接口B的成员定义。。。。
    function  f3();
    function  f4();
}

//这里注意 如果让子类可以创建对象。则必须实现接口中的全部抽象方法 咱们拿类B1实现接口B
class  B1  implements  B{
    // 这里有f1(),f2() 因为B继承了A
    function  f1(){
        ..
    }
    function  f2(){
        ...
    }
    function  f3(){
        ...
    }
    function  f4(){
        ...
    }
}

// 普通类继承接口
class   C  implements  A{  //这里,称为“C实现了接口A”
    function  f1(){
        ..
    }
    function  f2(){
        ..
    }
}

多实现:
class  C1  implements  A1, A2, A3{.....}  //假设A1,A2,A3是3个接口 即继承,又实现:
class  C2  extends  C1  implements  B1, B2 {....}//假设B1,B2是3个接口

(3) 在PHP面向对象开发中,final修饰符相关概念

如果父类中的方法被声明为final,则子类无法覆盖该方法; 如果一个类被声明为final,则不能被继承。
1、以final打头的类不能被继承
2、以final开头的成员方法不能被重载。
3、final也可以配合private protected public 关键词一起修饰成员或者方法,作用是相加效果。
4、final不成修饰成员属性(类中常量不是用这个关键字不和Java一样哦)
5、final只能修饰类和方法

<?php
    <?php
    echo'<meta charset ="utf-8">';
    class Person{
        var $name;
        var $age;
        var $sex;
        function __construct($name="",$age=0,$sex="男"){
            $this->name = $name;
            $this->age = $age;
            $this->sex = $sex;
        }
        final function gogo(){
            echo 'gogoggogogogogogogogo<br />';
        }
        function eat(){
            echo'<br />吃吃吃吃吃冲刺吃<br />';
        }
    }
    class Student extends Person{
        var $school;
        //Fatal error: Cannot override final method Person::gogo()
        // function gogo(){
        //  echo'<hr />';
        //  //Person::gogo();parent::gogo();仅仅是调用不是重载
        //  //它的作用是重载时将父类相对应的方法的内用拿来,然后进行添加功能和修改
        //  Person::gogo();
        //  echo'<br />学习学习学习<br />';
        // }
    }
    $p1 = new Student("闯",23,"男超人");
        echo $p1->name;
    $p1->eat();
        //可以调用访问
        $p1->gogo();

结果:
闯
吃吃吃吃吃冲刺吃
gogoggogogogogogogogo

(4)对一组数据(84,47,25,15,21)排序,数据的排列次序在排序的过程中的变化为 (1)84 47 25 15 21 (2)15 47 25 84 21 (3)15 21 25 84 47 (4)15 21 25 47 84则采用的排序是__

A.选择 B.冒泡 C.快速 D.插入 答案解析
简单选择排序的基本思想是:每一趟在n-i+1(i=1,2,3,…,n-1)个记录中选取关键字最小的记录作为有序序列中的第i个记录。它的具体实现过程为: 1>将整个记录序列划分为有序区域和无序区域,有序区域位于最左端,无序区域位于右端,初始状态有序区域为空,无序区域含有待排序的所有n个记录。 2>设置一个整型变量index,用于记录在一趟的比较过程中,当前关键字值最小的记录位置。开始将它设定为当前无序区域的第一个位置,即假设这个位置的关键字最小,然后用它与无序区域中其他记录进行比较,若发现有比它的关键字还小的记录,就将index改为这个新的最小记录位置,随后再用a[index].key与后面的记录进行比较,并根据比较结果,随时修改index的值,一趟结束后index中保留的就是本趟选择的关键字最小的记录位置。 3>将index位置的记录交换到无序区域的第一个位置,使得有序区域扩展了一个记录,而无序区域减少了一个记录。 不断重复2>、3>,直到无序区域剩下一个记录为止。此时所有的记录已经按关键字从小到大的顺序排列就位。

(5) find -newer file1 ! file2 命令的意思是?

(6)下面代码的运行结果:

$num ='24linux'+6;
echo $num;

答案:30

(7)下面代码的运行结果:

$a = 'PHPlinux';
$b = 'PHPLinux';
$c = strstr($a,'L');
$d = stristr($b,'l');
echo $c.' is '.$d;

结果:is Linux

(8)详细描述session设计原理,如何把session保存到指定的存储,比如redis,memcache,mysql

稍后解答

(9)mysql索引分为那几种?如何理解mysql聚簇索引?

http://blog.csdn.net/bigtree_3721/article/details/51335479

http://www.cnblogs.com/zhengyanqiu/p/4989955.html


(10)php-fpm有几种生成子进程的方式?列举常用调优配置参数及调优策略

1、 首先我们关注下 PHP-FPM 的运行方式:

  • static :表示在 php-fpm 运行时直接 forkpm.max_chindren 个子进程。
  • dynamic:表示,运行时 forkstart_servers 个进程,随着负载的情况,动态的调整,最多不超过 max_children 个进程。

2、相关说明:
一般推荐用 static。 动态适合小内存机器,灵活分配进程,省内存。缺点:动态创建回收进程对服务器资源也是一种消耗

静态适用于大内存机器(建议>=2G)
优点是不用动态的判断负载情况,提升性能;
缺点是多占用些系统内存资源。

3、PHP-FPM 子进程最优数量:
首先如何设置,取决于你的代码

  • 如果代码是 CPU 计算密集型的,pm.max_chindren 不能超过 CPU 的内核数 (能并发执行的 php-fpm 进程不会超过 cpu 个数)

  • 如果不是,那么将 pm.max_chindren 的值大于 CPU 的内核数,是非常明智的。

国外技术大拿给出这么个公式1、dynamic 方式: 在 N + 20% 和 M / m 之间
2、static方式:M / (m * 1.2)

  • N 是 CPU 内核数量。
  • M 是 PHP 能利用的内存大小。(由于大家一般Nginx、MySQL都在一台机器上,于是预留一半给它们,即M数为总内存/2)
  • m 是每个 PHP-FPM 子进程平均使用的内存数量。(一般php-fpm进程占用20~30m左右的内存就按30m算)

注意:上面是参考,最优值建议配合压力测试得出

3、进行配置参数:
要设置php进程数量。需要在php-fpm.conf文件中修改。

php-fpm重要优化参数介绍

pm = dynamic

pm参数指定了进程管理方式,有两种可供选择:static或dynamic,从字面意思不难理解,为静态或动态方式。如果是静态方式,那么在php-fpm启动的时候就创建了指定数目的进程,在运行过程中不会再有变化(并不是真的就永远不变);而动态的则在运行过程中动态调整,当然并不是无限制的创建新进程,受pm.max_spare_servers参数影响;

pm.max_children = 24

static模式下创建的子进程数或dynamic模式下同一时刻允许最大的php-fpm子进程数量

pm.start_servers = 16

动态方式下的起始php-fpm进程数量

pm.min_spare_servers = 12

动态方式下服务器空闲时最小php-fpm进程数量

pm.max_spare_servers = 24

动态方式下服务器空闲时最大php-fpm进程数量

下面这里是/usr/local/php/etc/php-fpm.conf文件各项配置解析 供大家以后当做手册用。

pid = run/php-fpm.pid
#pid设置,默认在安装目录中的var/run/php-fpm.pid,建议开启

error_log = log/php-fpm.log
#错误日志,默认在安装目录中的var/log/php-fpm.log

log_level = notice
#错误级别. 可用级别为: alert(必须立即处理), error(错误情况), warning(警告情况), notice(一般重要信息), debug(调试信息). 默认: notice.

emergency_restart_threshold = 60
emergency_restart_interval = 60s
#表示在emergency_restart_interval所设值内出现SIGSEGV或者SIGBUS错误的php-cgi进程数如果超过 emergency_restart_threshold个,php-fpm就会优雅重启。这两个选项一般保持默认值。

process_control_timeout = 0
#设置子进程接受主进程复用信号的超时时间. 可用单位: s(秒), m(分), h(小时), 或者 d(天) 默认单位: s(秒). 默认值: 0.

daemonize = yes
#后台执行fpm,默认值为yes,如果为了调试可以改为no。在FPM中,可以使用不同的设置来运行多个进程池。 这些设置可以针对每个进程池单独设置。

listen = 127.0.0.1:9000
#fpm监听端口,即nginx中php处理的地址,一般默认值即可。可用格式为: ‘ip:port’, ‘port’, ‘/path/to/unix/socket’. 每个进程池都需要设置.

listen.backlog = -1
#backlog数,-1表示无限制,由操作系统决定,此行注释掉就行。backlog含义参考:

http://www.3gyou.cc/?p=41

listen.allowed_clients = 127.0.0.1
#允许访问FastCGI进程的IP,设置any为不限制IP,如果要设置其他主机的nginx也能访问这台FPM进程,listen处要设置成本地可被访问的IP。默认值是any。每个地址是用逗号分隔. 如果没有设置或者为空,则允许任何服务器请求连接

listen.owner = www
listen.group = www
listen.mode = 0666
#unix socket设置选项,如果使用tcp方式访问,这里注释即可。

user = www
group = www
#启动进程的帐户和组

pm = dynamic #对于专用服务器,pm可以设置为static。
#如何控制子进程,选项有static和dynamic。如果选择static,则由pm.max_children指定固定的子进程数。如果选择dynamic,则由下开参数决定:
pm.max_children #,子进程最大数
pm.start_servers #,启动时的进程数
pm.min_spare_servers #,保证空闲进程数最小值,如果空闲进程小于此值,则创建新的子进程
pm.max_spare_servers #,保证空闲进程数最大值,如果空闲进程大于此值,此进行清理

pm.max_requests = 1000
#设置每个子进程重生之前服务的请求数. 对于可能存在内存泄漏的第三方模块来说是非常有用的. 如果设置为 ’0′ 则一直接受请求. 等同于 PHP_FCGI_MAX_REQUESTS 环境变量. 默认值: 0.

pm.status_path = /status
#FPM状态页面的网址. 如果没有设置, 则无法访问状态页面. 默认值: none. munin监控会使用到

ping.path = /ping
#FPM监控页面的ping网址. 如果没有设置, 则无法访问ping页面. 该页面用于外部检测FPM是否存活并且可以响应请求. 请注意必须以斜线开头 (/)。

ping.response = pong
#用于定义ping请求的返回相应. 返回为 HTTP 200 的 text/plain 格式文本. 默认值: pong.

request_terminate_timeout = 0
#设置单个请求的超时中止时间. 该选项可能会对php.ini设置中的’max_execution_time’因为某些特殊原因没有中止运行的脚本有用. 设置为 ’0′ 表示 ‘Off’.当经常出现502错误时可以尝试更改此选项。

request_slowlog_timeout = 10s
#当一个请求该设置的超时时间后,就会将对应的PHP调用堆栈信息完整写入到慢日志中. 设置为 ’0′ 表示 ‘Off’

slowlog = log/$pool.log.slow
#慢请求的记录日志,配合request_slowlog_timeout使用

rlimit_files = 1024
#设置文件打开描述符的rlimit限制. 默认值: 系统定义值默认可打开句柄是1024,可使用 ulimit -n查看,ulimit -n 2048修改。

rlimit_core = 0
#设置核心rlimit最大限制值. 可用值: ‘unlimited’ 、0或者正整数. 默认值: 系统定义值.

chroot =
#启动时的Chroot目录. 所定义的目录需要是绝对路径. 如果没有设置, 则chroot不被使用.

chdir =
#设置启动目录,启动时会自动Chdir到该目录. 所定义的目录需要是绝对路径. 默认值: 当前目录,或者/目录(chroot时)

catch_workers_output = yes
#重定向运行过程中的stdout和stderr到主要的错误日志文件中. 如果没有设置, stdout 和 stderr 将会根据FastCGI的规则被重定向到 /dev/null . 默认值: 空.

(11)mysql explain 后得的的结构,type列都有那些值,以及其含义

http://blog.csdn.net/xifeijian/article/details/19773795

(12)linux添加环境变量,当前会话生效,当前用户生效,所有系统用户生效,3种级别的实现方式有那些?

(13)linux服务器ssh如何配置免密码登陆?

(14)查看操作系统端口是否被占用的方式有那些?


(15)什么是符号链接,什么是硬链接?符号链接和硬链接区别?


(16)array+array 和array_merge()区别?

主要区别是两个或者多个数组中如果出现相同键名,键名分为字符串或者数字,需要注意

1)键名为数字时,array_merge()不会覆盖掉原来的值会追加到原有的数组后面,
但+合并数组则会把最先出现的值作为最终结果返回,而把后面的数组拥有相同键名的那些值“抛弃”掉(不是覆盖)

$a = array('a','b'); 
$b = array('c', 'd'); 
$c = $a + $b; 
var_dump($c); 
var_dump(array_merge($a, $b)); 

结果:

array(2) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "b"
}
------------
array(4) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "b"
  [2]=>
  string(1) "c"
  [3]=>
  string(1) "d"
}

需要注意的是数组键形式 '数字' 等价于 数字

$a = array('a', 'b'); 
$b = array('0' => 'c', 1 => 'b'); 
$c = $a + $b; 
var_dump($c); 
var_dump(array_merge($a, $b)); 

//结果和上面一样

2)键名为字符时,+仍然把最先出现的值作为最终结果返回,而把后面的数组拥有相同键名的那些值“抛弃”掉,
但array_merge()此时会覆盖掉前面相同键名的值

$a = array('a'=>'a1', 'b'=>'b1','c'=>'c1'); 
$b = array('a'=>'a2', 'b'=>'b2','d'=>'d1'); 
$c = $a + $b; 
var_dump($c); 
var_dump(array_merge($a, $b)); 

结果:

array(4) {
  ["a"]=>
  string(2) "a1"
  ["b"]=>
  string(2) "b1"
  ["c"]=>
  string(2) "c1"
  ["d"]=>
  string(2) "d1"
}
array(4) {
  ["a"]=>
  string(2) "a2"
  ["b"]=>
  string(2) "b2"
  ["c"]=>
  string(2) "c1"
  ["d"]=>
  string(2) "d1"
}

(16)PHP缓存技术,如何实现页面静态化?

全页面静态化缓存

也就是将页面全部生成html静态页面,用户访问时直接访问的静态页面,而不会去走php服务器解析的流程。此种方式,在CMS系统中比较常见,比如dedecms;

一种比较常用的实现方式是用输出缓存:

流程:
Ob_start()
要运行的代码
$content = Ob_get_contents();
将缓存内容写入html文件
Ob_end_clean();

//在需要静态化页面的action里面写入
//action方法
ob_start();
$static_file ='./home/Tpl/default/Index/s.html';//静态页面
$path = './IndexAction.class.php';
$php_file = basename($path);//当前动态页面

if (!file_exists($static_file) || ((filemtime($static_file)+1800) < time()) || //缓存固定时间
filemtime($php_file) > filemtime($static_file)) //判断源文件已修改
{
    //下面这部分就是你自己action里面的逻辑
    $user = M('user');
    $tupian = M('tupianshangchuan');
    $tupian = $tupian->select();
    $list = $user->where('email="'.Session::get('email').'"')->select();
    $this->assign('tupian',$tupian);
    $this->assign('list',$list);
    $this->display(s_index);
    $c = ob_get_contents();
    file_put_contents($static_file, $c);
}else{
    $this->display('s');
}
//OK完活了

(17)数据库做了读写分离,怎么保证数据的一致性


(18)描述TCP的工作原理


(19)描述HTTP的工作原理


(20)PHP socket编程

请看文章:http://blog.csdn.net/hguisu/article/details/7448528(这里给大家一个传送门,本人没有这方面经验,就不献丑了

(21)什么是 CGI?什么是 FastCGI?php-fpm,FastCGI,Nginx 之间是什么关系?

CGI,通用网关接口,用于WEB服务器和应用程序间的交互,定义输入输出规范,用户的请求通过WEB服务器转发给FastCGI进程,FastCGI进程再调用应用程序进行处理,如php解析器,应用程序的处理结果如html返回给FastCGI,FastCGI返回给Nginx 进行输出。假设这里WEB服务器是Nginx,应用程序是 PHP,而 php-fpm 是管理 FastCGI 的,这也就是 php-fpm,FastCGI,和 Nginx 之间的关系。

FastCGI 用来提高 cgi 程序性能,启动一个master,再启动多个 worker,不需要每次解析 php.ini. 而 php-fpm 实现了 FastCGI 协议,是 FastCGI 的进程管理器,支持平滑重启,可以启动的时候预先生成多个进程。

(22)ajax 中如何执行跨域访问?同子域的情况如何处理?不同子域的情况如何处理?

file

跨域的存在是因为浏览器的同源策略,一个源表示协议,端口,域名都相同,否则就形成了跨域。

①jsonp,非官方协议,简单实用

通过JavaScript的callback方式调用,jQuery封装了jsonp方式的请求。

callback({“result”:0,”msg”:”ok”,”data”:{xxx}})

只能支持GET

②服务器响应头

header(“Access-Control-Allow-Origin:*”);

/星号表示所有的域都可以接受,/

header(“Access-Control-Allow-Methods:GET,POST”);

nginx也可以配置在nginx配置里

file

③iframe实现跨域