PHP 面试题 PHP部分(一)
1、双引号和单引号的区别?
-
双引号解释变量,单引号不解释变量;
-
双引号里插入单引号,其中单引号里如果有变量的话,变量解释;
-
双引号解释转义字符,单引号不解释转义字符,但是解释'\和\\;
-
单引号的效率比双引号要高(因为双引号要先遍历一遍,判断里面有没有变量,然后再进行操作,而单引号则不需要判断);
-
双引号的变量名后面必须要有一个非数字、字母、下划线的特殊字符,或者用讲变量括起来,否则会将变量名后面的部分当做一个整体,引起语法错误。
2、HTTP中POST、GET、PUT、DELETE方式的区别?
(1)表单中get和post提交方式的区别
- get是把参数数据队列加到提交表单的action属性所指的url中,值和表单内各个字段一一对应,从url中可以看到;post是通过HTTPPOST机制,将表单内各个字段与其内容放在HTML的head中一起传送到action属性所指的url地址,用户看不到这个过程
- 对于get方式,服务器端用Request.QueryString获取变量的值,对于post方式,服务器端用Request.Form获取提交的数据
- get传送的数据量较小(受浏览器和服务器限制,不同的浏览器限制长度不一样),post传送的数据量较大,一般被默认不受限制,但在理论上,IIS4中最大量为80kb,IIS5中为1000k,get安全性非常低,post安全性较高
(2)post、get、put、delete方式的区别
-
GET请求会向数据库发索取数据的请求,从而来获取信息,该请求就像数据库的select操作一样,只是用来查询一下数据,不会修改、增加数据,不会影响资源的内容,即该请求不会产生副作用。无论进行多少次操作,结果都是一样的。
-
PUT请求是向服务器端发送数据的,从而改变信息,该请求就像数据库的update操作一样,用来修改数据的内容,但是不会增加数据的种类等,也就是说无论进行多少次PUT操作,其结果并没有不同。
-
POST请求同PUT请求类似,都是向服务器端发送数据的,但是该请求会改变数据的种类等资源,就像数据库的insert操作一样,会创建新的内容。几乎目前所有的提交操作都是用POST请求的。
-
DELETE请求顾名思义,就是用来删除某一个资源的,该请求就像数据库的delete操作。
(3)get和post的区别
-
get提交的参数在url中可见,相对于post安全性低;
-
get传输的数量小(受浏览器和服务器限制,不用浏览器url最大长度不同),post传值大小可以在php.ini中进行设置;
-
get一般用于从服务器获取数据,post一般用于向服务器提交数据;
-
get的执行效率比post高。
3、echo、print_r()、print、var_dump()之间的区别
(1)echo与print区别
-
echo、print为结构语言,echo()、print()为函数;
-
echo 输出一个以上的字符串(中间以逗号隔开),print 只能输出一个字符串;
-
echo 没有返回值,print有返回值;
-
echo 效率比print高。
(2)echo、print、print_r()、var_dump()区别
- echo 语言结构,输出一个或多个字符串,中间以逗号隔开,没有返回值,不能作为表达式的一部分使用;
- print也是php的一个关键字,有返回值 只能打印出简单类型变量的值(如int,string),如果字符串显示成功则返回true,否则返回false;
- print_r() 可以打印出复杂类型变量的值(如数组、对象)以列表的形式显示,并以array、object开头,但print_r输出布尔值false和NULL的结果没有意义,因为都是打印"\n",因此var_dump()函数更适合调试;
- var_dump() 判断一个变量的类型和长度,并输出变量的数值
4、谈谈mvc的认识
由模型(model)、视图(view)、控制器(controller)完成的应用程序,由模型发出要实现的功能到控制器,控制器接收组织功能传递给视
优点:①可以实现代码的重用性,避免产生代码冗余;②M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式
5、HTTP状态码
常见的HTTP状态码:
- 200 - 请求成功
- 203 - 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本
- 204 - 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
- 205 - 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域
- 206 - 部分内容。服务器成功处理了部分GET请求
- 301 - 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
- 302 - 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
- 305 - 使用代理。所请求的资源必须通过代理访问
- 401 - 请求要求用户的身份认证
- 403 - 服务器理解请求客户端的请求,但是拒绝执行此请求
- 404 - 请求的资源(网页等)不存在
- 503 - 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
- 505 - 服务器不支持请求的HTTP协议的版本,无法完成处理
HTTP状态码分类:
- 1** - 信息,服务器收到的请求,需要请求者继续执行操作
- 2** - 成功,操作被成功接收并处理
- 3** - 重定向,需要进一步的操作以完成请求
- 4** - 客户端错误,请求包含语法错误或者无法完成请求
- 5** - 服务器错误,服务器在处理请求的过程 中发生了错误
6、常用的超全局变量
-
$_GET ----->get传送方式
-
$_POST ----->post传送方式
-
$_REQUEST ----->可以接收到get和post两种方式的值
-
$_FILE ----->上传文件使用
-
$GLOBALS ----->所有的变量都放在里面
-
$_SERVER ----->系统环境变量
-
$_SESSION ----->会话控制的时候会用到
-
$_COOKIE ----->会话控制的时候会用到
-
$_ENV ------->PHP解析所在服务器环境的有关信息
7、php5的魔术变量与魔术方法?
(1)魔术方法
-
__construct() :实例化对象时自动调用。
-
__destruct() :销毁对象或脚本执行结束时自动调用。
-
__call() :调用对象不存在得方法时执行此函数。
-
__get() :获取对象不存在的属性时执行此函数。
-
__set() :设置对象不存在的属性时执行此函数。
-
__isset() : 测对象的某个属性是否存在时执行此函数。
-
__unset() :销毁对象的某个属性时执行此函数。
-
__toString() :将对象当作字符串输出时执行此函数。
-
__clone() :克隆对象时执行此函数。
-
__autoload() :实例化对象时,当类不存在时,执行此函数自动加载类。
-
__sleep() :serialize之前被调用,可以指定要序列化的对象属性。
-
__wakeup :unserialize之前被调用,可以执行对象的初始化工作。
-
__set_state() :调用var_export时,被调用。用__set_state的返回值做为var_export的返回值。
-
__invoke() :将对象当作函数来使用时执行此方法,通常不推荐这样做。
(2)魔术常量
-
__line__ :文件中的当前行号。
-
__file__ :文件的完整路径和文件名。
-
__dir__ :文件所在的目录。
-
__function__ :函数名称(php 4.3.0新加)。自php5起本常量返回该函数被定义时的名字(区分大小写)。
-
__class__ :类的名字(php 4.3.0新加)。自 PHP 5 起本常量返回该类被定义时的名字(区分大小写)。
-
__namespace__ :当前命名空间的名称(区分大小写)。此常量是在编译时定义的(PHP 5.3.0 新增)。
-
__trait__ :Trait 的名字(PHP 5.4.0 新加)。自 PHP 5.4 起此常量返回 trait 被定义时的名字(区分大小写)。Trait 名包括其被声明的作用区域(例如 Foo\Bar)。
-
__method__ :类的方法名(PHP 5.0.0 新加)。返回该方法被定义时的名字(区分大小写)。
8、如何获取客户端的ip(要求取得一个int)和服务器ip的代码
客户端:$_SERVER["REMOTE_ADDR"];或者getenv('REMOTE_ADDR')
ip2long进行转换
服务器端:$_SERVER["SERVER_ADDR"];
或者gethostbyname('www.baidu.com')
9、<?php echo count(strlen(“http://php.net”));?>的执行结果
输出 1
讲解:count(var)是用来统计数组或对象的元素个数的。当var是null或者空数组时,结果为0。如果var是普通变量,则返回1。正常情况下返回var中的元素或属性个数。
10、使用list()函数需要注意什么?
list()是一个语法结构。List($array)是用来快速把数组中的元素赋给一些变量。使用时要注意,$array必须为一个索引数组,并且索引值从0开始。
用法:
$arr = array('23','1','30','12','5');
list($a,,$b) = $arr;
echo '$a:'.$a.';$b:'.$b;
输出结果:$a:23;$b:30
11、说明php中传值与传引用的区别,并说明什么时候传引用?
传值
是把实参的值赋值给行参
那么对行参的修改,不会影响实参的值
传地址
是传值的一种特殊方式,只是他传递的是地址,不是普通的如int
那么传地址以后,实参和行参都指向同一个对象
传引用
真正的以地址的方式传递参数
传递以后,行参和实参都是同一个对象,只是他们名字不同而已
对行参的修改将影响实参的值
$a = "123";
$b = &$a;//引用赋值(在源变量前加&符号)
echo $a."-".$b; // 输出:123-123
echo "<br/>";
$b = "456465"; // 输出:456465-456465
echo $a."-".$b;
// 结论 :
// PHP 传引用时 形参 发声改变的时候 实参也发生改变;
传值,就是仅将对象的值传递给目标对象,就相当于copy;系统将为目标对象重新开辟一个完全相同的内存空间。
传引用,就是将对象在内存中的地址传递给目标对象,就相当于使目标对象和原始对象对应同一个内存存储空间。此时,如果对目标对象进行修改,内存中的数据也会改变。
对象默认是传引用 对于较大是的数据,传引用比较好,这样可以节省内存的开销
12、如何命令下运行PHP脚本(两种方式),如何向PHP脚本传递参数?
(1)运行PHP脚本
方法一:先进入php安装目录,执行 php 路径/文件名.php。
例:php my_script.php php -f "my_script.php"
方法二:php -r “php脚本”;(不需要加php的开始符和结束符)。
例:php -r "print_r(get_defined_constants());"
(2)向php脚本传递参数:
方法一:使用$argv or $argc参数接收
php脚本:
<?php
echo "接收到{$argc}个参数";
print_r($argv);
执行:
[root@DELL113 lee]# /usr/local/php/bin/php test.php
接收到1个参数Array
(
[0] => test.php
)
[root@DELL113 lee]# /usr/local/php/bin/php test.php a b c d
接收到5个参数Array
(
[0] => test.php
[1] => a
[2] => b
[3] => c
[4] => d
)
方法二:使用getopt函数
php脚本:
<?php
$param_arr = getopt('a:b:');
print_r($param_arr);
执行:
[root@DELL113 lee]# /usr/local/php/bin/php test.php -a 345
Array
(
[a] => 345
)
[root@DELL113 lee]# /usr/local/php/bin/php test.php -a 345 -b 12q3
Array
(
[a] => 345
[b] => 12q3
)
[root@DELL113 lee]# /usr/local/php/bin/php test.php -a 345 -b 12q3 -e 3322ff
Array
(
[a] => 345
[b] => 12q3
)
13、isset、empty、is_null的区别
isset : 判断变量是否定义或者是否为空,变量存在返回ture,否则返回false
empty:判断变量的值是否为空,能转换为false("",0,"0",NULL,FALSE)的都是空,为空返回true,反之返回false。
is_null:检测传入的值(值、变量、表达式)是否为null,当参数满足下面三种情况时,is_null()将返回TRUE,其它的情况就是FALSE
-
被赋值为NULL,如:$var = null;
-
还没有赋值,如:$var;
-
未定义,相当于unset(),将一个变量unset()后,不就是没有定义吗
$num = 520;unset($num);
14、函数内部 static 和 global 关键字的作用
static 是静态变量,在局部函数中存在且只初始化一次,使用过后再次使用会使用上次执行的结果; 作为计数,程序内部缓存,单例模式中都有用到。
global 关键字,引用全局变量,wordpress中大量用到,如面向过程开发。
static 静态方法,是类的成员方法,但不需要实例化类可直接使用
$GLOBAL 在函数内使用具有全局作用域的变量,如$GLOBAL['a']
continue
continue
是用来用在循环结构中,控制程序放弃本次循环continue语句之后的代码并转而进行下一次循环。continue本身并不跳出循环结构,只是放弃这一次循环。如果在非循环结构中(例如if语句中,switch语句中)使用continue,程序将会出错。
break
break是被用在上面所提的各种循环和switch语句中的。他的作用是跳出当前的语法结构,执行下面的语句。break语句可以带一个参数n,表示跳出循环的层数,如果要跳出多重循环的话,可以用n来表示跳出的层数,如果不带参数默认是跳出本重循环。
return
return
语句是用来结束一段代码,并返回一个参数的。可以从一个函数里调用,也可以从一个include()或者require()语句包含的文件里来调用,也可以是在主程序里调用,如果是在函数里调用程序将会马上结束运行并返回参数,如果是include()或者require()语句包含的文件中被调用,程序执行将会马上返回到调用该文件的程序,而返回值将作为include()或者require()的返回值。而如果是在主程序中调用,那么主程序将会马上停止执行
exit
exit是用来结束程序执行的。可以用在任何地方,本身没有跳出循环的含义。exit可以带一个参数,如果参数是字符串,PHP将会直接把字符串输出,如果参数是integer整形(范围是0-254),那个参数将会被作为结束状态使用。
die
die()是exit()函数的别名,都是中止脚本执行函。该函数只接受一个参数,可以是一个程序返回的数值或是一个字符串,也可以不输入参数,结果没有返回值。
die() 与exit()使用细微差别:
(1)当传递的值为0时,意味着提前终止脚本的执行,通常用exit()这个名字。
echo "1111";
exit(0);
echo "2222";
//22222不会被输出,因为程序运行到exit(0)时,脚本已经被提前终止,“马上断气”。
(2)当程序出错时,可以给它传递一个字符串,它会原样输出在系统终端上,通常使用die()这个名字。
$fp=fopen("./readme.txt","r") or die("不能打开该文件");
//这种情况下,如果fopen函数被调用返回布尔值false时,die()将立即终止脚本,并马上打印
//传递给它的字符串,“死前还能说一两句话”。
什么是面向对象?主要特征是什么?几大原则是什么?
面向对象是程序的一种设计模式,它利于提高程序的重用性,使程序机构更加清晰。
三大特性是:封装、继承、多态
所谓封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
封装是面向对象的特征之一,是对象和类概念的主要特性。 简单的说,一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。
所谓继承,是指可以让某个类型的对象获得另一个类型的对象的属性的方法,它支持按级分类的概念。
继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。 通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。继承概念的实现方式有二类:实现继承与接口继承。实现继承是指直接使用基类的属性和方法而无需额外编码的能力;接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;
所谓多态,就是指一个类实例的相同方法在不同情形有不同表现形式。
多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。
五大基本原则:单一职责原则;开放封闭原则;替换原则; 依赖原则; 接口分离原则。
单一职责原则SRP(Single Responsibility Principle)
是指一个类的功能要单一,不能包罗万象。如同一个人一样,分配的工作不能太多,否则一天到晚虽然忙忙碌碌的,但效率却高不起来。
开放封闭原则OCP(Open-Close Principle)
一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的。比如:一个网络模块,原来只服务端功能,而现在要加入客户端功能,
那么应当在不用修改服务端功能代码的前提下,就能够增加客户端功能的实现代码,这要求在设计之初,就应当将服务端和客户端分开,公共部分抽象出来。
替换原则(the Liskov Substitution Principle LSP)
子类应当可以替换父类并出现在父类能够出现的任何地方。比如:公司搞年度晚会,所有员工可以参加抽奖,那么不管是老员工还是新员工,
也不管是总部员工还是外派员工,都应当可以参加抽奖,否则这公司就不和谐了。
依赖原则(the Dependency Inversion Principle DIP) 具体依赖抽象,上层依赖下层。
假设B是较A低的模块,但B需要使用到A的功能,这个时候,B不应当直接使用A中的具体类: 而应当由B定义一抽象接口,并由A来实现这个抽象接口,B只使用这个抽象接口:这样就达到
了依赖倒置的目的,B也解除了对A的依赖,反过来是A依赖于B定义的抽象接口。通过上层模块难以避免依赖下层模块,假如B也直接依赖A的实现,那么就可能造成循环依赖。一个常见的问题就是编译A模块时需要直接包含到B模块的cpp文件,而编译B时同样要直接包含到A的cpp文件。
接口分离原则(the Interface Segregation Principle ISP)
模块间要通过抽象接口隔离开,而不是通过具体的类强耦合起来
什么是静态路由,其特点是什么?什么是动态路由,其特点是什么?
参考答案:
静态路由是由系统管理员设计与构建的路由表规定的路由。适用于网关数量有限的场 合,且网络拓朴结构不经常变化的网络。其缺点是不能动态地适用网络状况的变化,当 网络状况变化后必须由网络管理员修改路由表。
动态路由是由路由选择协议而动态构建的,路由协议之间通过交换各自所拥有的路由信 息实时更新路由表的内容。动态路由可以自动学习网络的拓朴结构,并更新路由表。其 缺点是路由广播更新信息将占据大量的网络带宽。