二、填空题 1. ______函数能返回脚本里任意行中调用的函数的名称。该函数同时还经常被用在调试中,用来判断错误是如何发生的。
debug_backtrace()。
[解析] debug_backtrace()的作用:返回在特定位置调用过的函数名组成的数组,经常被用于调试。
2. 面向对象的主要特征有______、______、______、______。
抽象、继承、封装、多态。
[解析] 1)抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。抽象包括两个方面,一是过程抽象,二是数据抽象。 2)继承:继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和实例变量,并且子类可以修改或增加新的方法使之更适合特殊的需要。 3)封装:封装是指将客观事物抽象成类,每个类对自身的数据和方法实行保护。类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的信息进行隐藏。 4)多态:多态是指允许不同类的对象对同一消息做出响应。多态包括参数化多态和包含多态。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好地解决了应用程序函数同名问题。
3. 打开php.ini中的safe_mode,会影响的函数有______、______、______、______、______、______。
fopen()、mkdir()、rmdir()、set_time_limit()、mysql_connect()、mail()。
[解析] PHP的safa_mode提供了一个基本安全的共享环境,在一个有多个用户账户存在的PHP开发的Web服务器上。当安全模式打开的时候,部分函数将被完全地禁止,而还有部分函数的功能将会受到限制。下面重点给出其中的一部分: 1)fopen()、mkdir()、rmdir()检查被操作的目录是否与正在执行的脚本有相同的UID。 2)创建新文件(只能在属于当前用户的目录下创建文件)。 3)dl()函数在安全模式下被禁用。 4)set_time_limit()在安全模式下不起作用。 5)mysql服务器所用的用户名必须与调用mysql_connect()的文件的拥有者用户名相同。 6)mail()在安全模式下,第5个参数被屏蔽。
4. session的运行机制是______。
服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
[解析] Session是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。 当程序需要为某个客户端的请求创建一个Session的时候,服务器首先检查这个客户端的请求里是否已包含了一个Session标识SessionID,如果已包含一个SessionID,则说明已经为此客户端创建Session,服务器就按照SessionID把这个Session检索出来使用,如果客户端请求不包含SessionID,那么为此客户端创建一个Session并且生成一个与此Session相关联的SessionID,SessionID的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个SessionID将被在本次响应中返回给客户端保存。
5. MySQL的事务是______。
事务是作为一个单元的一组有序的数据库操作。如果组中的所有操作都成功,.则认为事务成功,即使只有一个操作失败,事务也不成功。如果所有操作完成,事务则提交,那么其修改将作用于所有其他数据库进程。如果一个操作失败,则事务将回滚,该事务所有操作的影响都将取消。
三、简答题 1. mysql_fetch_row()和mysql_fetch_array()有什么区别?
mysql_fetch_row()把数据库的一列存储在一个以零为基数的阵列中,第一栏在阵列的索引0,第二栏在索引1,如此类推。mysql_fetch_assoc()把数据库的一列存储在一个关联阵列中,阵列的索引就是栏位名称,例如,数据库查询送回“first_name”“last_name”“email”三个栏位,阵列的索引便是“first_name”“last_name”和“email”。mysql_fetch_array()可以同时送回mysql_fetch_row()和mysql_fetch_assoc()的值。
2. 详细描述PHP处理Web上传文件的流程。如何限制上传文件的大小不能超过某个数值?
首先用户在浏览器端选择上传的文件,提交后,通过post方式上传到Apache服务器由PHP引擎处理,判断文件是否能够上传到PHP配置文件中指定的临时目录,之后获取文件后缀名判断文件是否是允许上传的文件格式,没有问题后再通过$_FILES["file"]["size"]得到上传文件的数值大小,判断其是否小于设置的值,如果没问题,则按照随机数+时间的方式生成文件的名字+后缀。最后将文件从临时目录转移至Apache服务器目录。 也可以在PHP配置文件通过file_upload_max设置其值限制上传文件大小。
3. Memcache对item的过期时间有什么限制?
Memcache的item过期时间最长可以为30天,Memcache把传入的过期时间解释成时间点后,当到了这个时间点,Memcache就把item设置为失效状态。当使用Memcache存储数据时,设置一个值为永久时间或一段时间,如果Memcache分配的内存使用完毕,则首先会替换掉已失效的数据,其次是最近少使用的数据。
4. 什么是函数返回值?
在PHP中,函数可以返回一个值或多个值,返回值是通过return语句来实现的。return语句会使程序在return处停止,并返回指定的变量。最常用的就是函数返回一个值情况,而且这种情况比较简单,因此,这里重点介绍返回多个值的情况。 如果一个函数需要返回多个值,那么可以通过以下两种方式实现。 1)返回数组:通过返回一个数组可以达到返回多个值的目的。 示例代码如下: <?php function results($string) { $result=array(); $result[]=strtoupper($string); //把所有字符转换为大写 $result[]=strtolower($string); //把所有字符转换为小写 $result[]=ucwords($string); //把所有单词的首字母换成大写 return $result; } $multi_result=results('hello world'); print_r($multi_result); ?> 程序的运行结果为 Array ( [0]=>HELLO WORLD [1]=>hello world [2]=>Hello World ) 2)引用:可以给函数传递引用参数,此时在函数内部对引用变量值的修改对实参也可见。通过这种方法也可以实现把函数内部对引用变量的值的修改返回给调用者,从而实现了返回多个值的目的,示例代码如下: <?php function test(&$a,&$b) { $a*=10; $b*=10; return $a+$b; } $a=10; $b=12; $c=test($a,$b); //注意这里没有&了 //显示修改后的值 echo $a; //输出100通过引用返回 echo $b; //输出120通过引用返回 echo $c; //输出220通过函数返回 ?>
5. 触发器分为事前触发和事后触发,二者有什么区别?语句级触发和行级触发有什么区别?
事前触发发生在事件发生之前验证一些条件或进行一些准备工作;事后触发发生在事件发生之后,做收尾工作,保证事务的完整性。而事前触发可以获得之前和新的字段值。语句级触发器可以在语句执行之前或之后执行,而行级触发在触发器所影响的每一行触发一次。
四、编程题 1. 假设有一条绳子,上面有红、白、蓝三种颜色的旗子,起初绳子上的旗子颜色并没有顺序,现在希望将之分类,并排列为蓝、白、红的顺序,要如何移动才能让次数最少?注意只能在绳子上进行这个动作,而且一次只能调换两个旗子。示意图如下图所示。
在一条绳子上移动,也就意味着在程序中只能使用一个阵列,不能使用辅助存储。问题的解法很简单,从绳子开头进行,遇到蓝色往前移,遇到白色留在中间,遇到红色往后移。如果要让移动次数最少,那么还需要一些技巧。 算法的主要思路为用三个下标b、w、r分别指向不同的旗子。其中b指向的从0开始连续排列的蓝色旗子的最后面的第一个非蓝色旗子,r指向的从最后一个序号开始连续排列的红色旗子的第一非红色旗子。例如,bbrwbbrr,那么b指向的就是序号为2的红色旗子,r指向的就是序号为倒数第3的蓝色旗子。 w作为可移动的指针来指引旗子的移动,当w指向的旗子是白色旗子的时候,w继续向前移动;当w指向的旗子是蓝色的时候,就需要把b所指的旗子和w所指的蓝色旗子交互;同理当w指的旗子是红色的时候,就需要w所指的红色旗子和r所指的旗子交换。 实现代码如下: <?php header("Content-type:text/html;charset=utf-8"); define("BLUE",'b'); define("WHITE",'w'); define("RED",'r'); function SWAP($x,$y,&$color){ $temp=$color[$x]; $color[$x]=$color[$y]; $color[$y]=$temp; } $color=array('r','b','r','w','r','r','w','b','b','r'); $wFlag=0; $bFlag=0; $rFlag=count($color)-1; echo"棋子开始的排序:"; for($i=0;$i<count($color);$i++) echo $color[$i]; echo "<br>"; while($wFlag<=$rFlag){ if($color[$wFlag]==WHITE) $wFlag++; else if($color[$wFlag]==BLUE){ SWAP($bFlag,$wFlag,$color); $bFlag++; $wFlag++; } else{ while($wFlag<$rFlag && $color[$rFlag]==RED) $rFlag--; SWAP($rFlag,$wFlag,$color); $rFlag--; } } echo"排序后的棋子:"; for($i=0;$i<count($color);$i++) echo $color[$i]; echo "<br>"; ?> 程序的运行结果为 棋子开始的排序:rbrwrrwbbr 排序后的棋子:bbbwwrrrrr
2. 请用PHP编程,实现一个简单的异常类。
<?php class MyException extends Exception{ public function errmsg(){ $msg="exception occur"; return $msg; } } function GetNum($num) { if($num>10) { throw new MyException("Exception ocur"); } return true; } try{ GetNum(100); echo"this is end line"."\n"; }catch(MyException $e){ echo "Exception msg:".$e->errmsg(); } ?> 程序的运行结果为 Exception msg:Exception ocur 上述代码抛出了一个异常,通过自定义的异常类来捕获。主要步骤如下: 1)自定义的异常类继承了超类Exception,这样就具有了超类的属性和方法。 2)创建异常函数errmsg(),返回错误信息。 3)传递不合法的变量,执行try代码块,抛出异常。 4)catch代码块捕获异常,并显示错误信息。
3. 请用PHP编程实现连接本地的redis操作,并对变量a进行赋值和取值,并删除变量a。
<?php $Redis=new Redis(); $Redis->connect('127.0.0.1',6378); //连接redis $res=$Redis->set('a',"bbbb"); //对a赋值 $a=$Redis->get('a'); //对a取值 $res=$Redis->delete('a'); //删除a ?>
4. 一个数组里,除了三个数是唯一出现的,其余的数都出现偶数次,找出这三个数中的任意一个。比如数组序列为[1,2,4,5,6,4,2],只有1,5,6这三个数字是唯一出现的,数字2与4均出现了偶数次(2次),只需要输出数字1,5,6中的任意一个就行。
根据题目描述可以得到如下几个有用的信息: 1)数组中元素个数一定是奇数个。 2)由于只有三个数字出现过一次,显然这三个数字不相同,因此,这三个数对应的二进制数也不可能完全相同。 由此可知,必定能找到二进制数中的某一个bit来区分这三个数(这一个bit的取值或者为0,或者为1),当通过这一个bit的值对数组进行分组的时候,这三个数一定可以被分到两个子数组中,并且其中一个子数组中分配了两个数字,而另一个子数组分配了一个数字,而其他出现两次的数字肯定是成对出现在子数组中的。此时只需要重点关注哪个子数组中分配了这三个数中的其中一个,就可以很容易地找出这个数字了。当数组被分成两个子数组时,这一个bit的值为1的数被分到一个子数组subArray1,这一个bit的值为0的数被分到另外一个子数组subArray0。 1)如果subArray1中元素个数为奇数个,那么对subArray1中的所有数字进行异或操作;由于a^a=0,a^0=a,出现两次的数字通过异或操作得到的结果为0,然后与只出现一次的数字执行异或操作,得到的结果就是只出现一次的数字。 2)如果subArray0中元素个数为奇数个,那么对subArray0中所有元素进行异或操作得到的结果就是其中一个只出现一次的数字。 为了实现上面的思路,必须先找到能区分这三个数字的bit位,根据以上的分析给出本算法的实现思路: 以32位平台为例,一个int类型的数字占用32位空间,从右向左使用每一位对数组进行分组,分组的过程中,计算这个bit值为0的数字异或的结果result0,出现的次数count0;这个bit值为1的所有数字异或的结果result1,出现的次数count1。 如果count0是奇数且result1!=0,那么说明这三个数中的其中一个被分配到这一bit为0的子数组中,因此,这个子数组中所有数字异或的值result0一定是出现一次的数字。(如果result1==0,说明这一个bit不能用来区分这三个数字,此时这三个数字都被分配到子数组subArray0中,因此,result1!=0就可以确定这一个bit可以被用来区分这三个数字的。) 同理,如果count1是奇数且result0!=0,那么result1就是其中一个出现1次的数。 以[6,3,4,5,9,4,3]为例,出现1次的数字为6(110),5(101),9(1001),从右向左第一位就可以区分这三个数字,用这个bit位可以把数字分成两个子数组subArray0=[6,4,4]和subArray1=[3,5,9,3]。subArray1中所有元素异或的值不等于0,说明出现1次的数字一定在subArray1中出现了,而subArray0中元素个数为奇数个,说明出现1次的数字,其中只有一个被分配到subArray0中了,所以,subArray0中所有元素异或的结果一定就是这个出现1次的数字6。实现代码如下: <?php define("PLATFORM",32); function isOne($n,$i) { return $n&(1<<$i); } function findSingle($arr,$size) { for($i=0;$i<PLATFORM;$i++) { $result1=$result0=$count1=$count0=0; for($i=0;$j<$size;$j++) { if(isOne($arr[$j],$i)){ $result1^=$arr[$j]; //第i位为1的值异或操作 $count1++; //第i位为1的数字个数 }else{ $result0^=$arr[$j]; //第i位为0的值异或操作 $count0++; //第i位为0的值的个数 } } /* **bit值为1的子数组元素个数为奇数,且出现1次的数字被分配到bit值为 **0的子数组说明只有一个出现1次的数字被分配到bit值为1的子数组中, **异或结果就是这个出现1次的数字 */ if($count1%2==1 && $result0!=0) { return $result1; } //只有一个出现1次的数字被分配到bit值为0的子数组中 if($count0%2==1 && $result1!=0) { return $result0; } } //没有找到 return-1; } $arr=array(6,3,4,5,9,4,3); printf("%d",findSingle($arr,count($arr))); ?> 程序的运行结果为 6 算法性能分析:这个方法使用了两层循环,总共循环执行的次数为32*N(N为数组的长度),因此,算法的时间复杂度为O(n)。