一、选择题8. 下面这段代码的输出是______
<?php
Class my_class{
var $my_var;
function_my_class($value){
$this->my_var=$value
}
}
$a=new my_class(10);
echo $a->my_car;
?>
A B C D
C
[解析] 如果在PHP5.3以前的版本执行这部分代码,那么会没有任何东西,答案是D,但在PHP5.3以后的版本中执行这部分代码会报错,答案会是C。实例化my_class类,传10进去给该类并不能被_my_class($value)获取到该值,因为_my_class()是一个函数,不等价于构造函数,所以最终执行$a->my_car时$my_var未定义,会报错。选项C正确。
所以,本题的答案为C。
二、填空题1. 从队列数组队头删除数据可以使用函数______。
2. 有字符串“1,2,3”,可以按逗号拆分为字符串数组的PHP函数是______,将数组元素接成字符串的函数是______。用PHP写出一个正则表达式,过滤网页上的所有js脚本______。
explode(),implode(),/<script[^>]*?>.*?<∨script>/si。
[解析] explode()函数可以对字符串按逗号拆分成数组。可以使用implode()函数将数组拼接成字符串。因为网页中的js脚本代码以script></script>包裹,所以可以对匹配包含这些字符的代码进行过滤,即过滤js脚本,正则匹配格式为/<script[^>]*?>.*?<∨script>/si。
3. 一个函数的参数不能是对变量的引用,除非在php.ini中把______设为on。
allow_call_time_pass_reference。
[解析] 主要通过在php.ini配置文件里对allow_call_time_pass_reference进行启用,在函数调用时强制参数按照引用传递。对于该方法,目前已经不推荐使用,推荐在函数定义时显式地指定哪些参数需要使用引用传递。
4. $a=abs(-50);则$a的值为______。
50。
[解析] 因为abs()函数返回的是一个数的绝对值,所以如果是正数,那么返回它本身,如果是负数,那么返回负数的绝对值,即-50的绝对值是50。
5. PHP转换json为数组的函数为______。
三、简答题1. 什么是虚拟内存?
虚拟内存简称虚存,是计算机系统内存管理的一种技术。它是相对于物理内存而言的,可以理解为“假的”内存。它使得应用程序认为它拥有连续可用的内存(一个连续完整的地址空间),允许程序员编写并运行比实际系统拥有的内存大得多的程序,这使得许多大型软件项目能够在具有有限内存资源的系统上实现。而实际上,它通常被分割成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。相比实存,虚存有以下好处:
1)扩大了地址空间。无论段式虚存,还是页式虚存,或是段页式虚存,寻址空间都比实存大。
2)内存保护。每个进程运行在各自的虚拟内存地址空间,互相不能干扰对方。另外,虚存还对特定的内存地址提供写保护,可以防止代码或数据被恶意篡改。
3)公平分配内存。采用了虚存之后,每个进程都相当于有同样大小的虚存空间。
4)当进程需要通信时,可采用虚存共享的方式实现。
不过,使用虚存也是有代价的,主要表现在以下几个方面:
1)虚存的管理需要建立很多数据结构,这些数据结构要占用额外的内存。
2)虚拟地址到物理地址的转换,增加了指令的执行时间。
3)页面的换入换出需要磁盘I/O,这是很耗时间的。
4)如果一页中只有一部分数据,会浪费内存。
2. 虚拟地址、逻辑地址、线性地址、物理地址有什么区别?
虚拟地址是指由程序产生的由段选择符和段内偏移地址组成的地址。这两部分组成的地址并没有直接访问物理内存,而是要通过分段地址的变换处理后才会对应到相应的物理内存地址。
逻辑地址指由程序产生的段内偏移地址。有时直接把逻辑地址当成虚拟地址,两者并没有明确的界限。
线性地址是指虚拟地址到物理地址变换之间的中间层,是处理器可寻址的内存空间(称为线性地址空间)中的地址。程序代码会产生逻辑地址,或者说是段中的偏移地址,加上相应段基址就生成了一个线性地址。如果启用了分页机制,那么线性地址可以再经过变换产生物理地址。若是没有采用分页机制,那么线性地址就是物理地址。物理地址是指现在CPU外部地址总线上的寻址物理内存的地址信号,是地址变换的最终结果。
虚拟地址到物理地址的转化方法是与体系结构相关的,一般有分段与分页两种方式。以x86 CPU为例,分段、分页都是支持的。内存管理单元负责从虚拟地址到物理地址的转化。逻辑地址是段标识+段内偏移量的形式,MMU通过查询段表,可以把逻辑地址转化为线性地址。如果CPU没有开启分页功能,那么线性地址就是物理地址;如果CPU开启了分页功能,MMU还需要查询页表来将线性地址转化为物理地址,即逻辑地址(段表)→线性地址(页表)→物理地址。
映射是一种多对一的关系,即不同的逻辑地址可以映射到同一个线性地址上;不同的线性地址也可以映射到同一个物理地址上。而且,同一个线性地址在发生换页以后,也可能被重新装载到另外一个物理地址上,所以这种多对一的映射关系也会随时间发生变化。
3. 接口、抽象类二者有何相同和不同的地方?
1)接口是帮助PHP实现功能意义上的多继承,用interface来声明,其方法没有方法体,使用implements关键词来实现接口。
接口中只能包含抽象方法和类常量,不可以包含成员属性。
2)抽象类是一种不能被实例化的类,只能作父类,用abstract来定义,抽象类和普通类可以没有区别,类中可以包含成员属性、类常量和方法。
子类得用extends来继承,而且只能是单继承。
两者的相同点是都不可以被实例化,都是需要被继承才可以使用。
两者的最大区别是接口可以实现多继承,而抽象类只能是单继承。
接口中不能包含成员属性,而抽象类中可以有成员属性。
接口中的抽象方法必须是public或者无访问修饰词,接口中的抽象方法不能用abstract来修饰。
抽象类中的方法可以是普通方法,也可以是抽象方法,如果是抽象方法,那么一定要使用abstract来修饰。
4. MVC的概念是什么?各层主要做什么工作?
MVC是一种软件设计模式,实现了前后端分离,保证前端人员和后端人员各司其职。MVC分别对应的是模型层、视图层和控制层。控制层从模型层中取数据操作,然后把数据放到视图层显示。用户也可以通过视图层向逻辑层反馈,逻辑层处理后反馈结果。
MVC分别指的是:
M指的是模型层(Model),主要向数据库进行操作,包括增、删、改、查的功能。获取数据库数据返回给逻辑层。
V指的是视图层(View),主要用于显示逻辑层返回的数据显示,用户主要通过视图层实现前后端数据交互。
C指的是逻辑层(Controller),主要负责从模型层取数据和分配数据到模板中,并且显示模板的作用,也可以处理视图层的反馈和返回结果。
5. smarty的工作原理是什么?如何对smarty进行二次开发?
1)PHP程序运行时,初始化smarty模版引擎(创建对象,设置属性)。
2)加载smarty模板文件(.html或.tpl文件),并对其编译,生成编译文件放置在编译目录下。
3)执行编译文件,并做模板替换,生成静态文件。若开启静态缓存,则会将静态缓存文件缓存到cache目录下。
4)最后输出结果到浏览器。
做smarty的二次开发:可以通过自定义变量调解器、函数等插件方式来实现辅助开发,还有重写smarty的一些方法可以扩展开发。
四、编程题1. 要求开发一款扑克游戏,请编写一套洗牌算法,而公平的洗牌是将洗好的牌存储在一个整型数组里。
定义一个洗牌函数,函数内用$tmp数组存储1~54表示54张牌。然后对这54张牌进行循环,每次循环时,通过随机函数随机从0到剩余牌数中生成一个数返回做索引,从$tmp数组中取出这个索引对应的牌,存到洗牌后的数组$cards。取出这张牌后同时要删除该牌在$tmp数组内的位置,最后还要通过array_values()函数对$tmp数组的值重新排序,保证数组从0到当前剩余的牌数中可以根据随机生成的索引取出剩余的牌。最后得到洗好的牌都存在数组$cards中。
实现代码如下:
<?php
$card_num=54;
function wash_card($card_num){
$cards=$tmp=array();
for($i=0:$i<$card_num;$++){
$tmp[$i]=$i;
}
for($i=0:$i<$card_num;$i++){
$index=rand(0,$card_num-$i-1);
$cards[$i]=$tmp[$index];
unset($tmp[$index]);
$tmp=array_values($tmp);
}
return $cards;
}
print_t(wash_card($card_num));
?>
因为洗牌的结果是随机不唯一的,所以在这里不再罗列运行结果。
2. 请写出一个正则表达式用于提取一个网页中的所有链接。
实现代码如下:
<?php
$urls=file_get_contents("http://www.baidu.com");
preg_match_all('/<as+href=["|"]?([^>"']+)["|']?s*[^>]*>([^>]+)</a>/i',$urls,$arr);
print_r($arr);
?>
3. 如何通过PHP程序防止外部页面提交表单?编写一段代码。
可以通过uniqid()函数生成一个随机的数,以微秒计的当前时间,它一定是一个唯一的ID值。然后通过Session存储这个ID值,将ID值存放在表单中,提交表单时一起提交到服务端,服务端使用$_POST方法接收参数,确保表单是post方法提交过来的,并且验证表单提交过来的ID值和Session存储的ID值是否一致,如果一致,那么说明是内部访问传递过来的,允许做对应的操作,如果不一致,那么说明是外部页面传递过来的,则拒绝访问操作。
实现代码如下:
<?php
session_start();
if(isset($_POST['user'])&&!empty($_POST['user'])){
if($_POST['check']==$_SESSION['check']){
echo'内部访问';
}else{
echo'外部访问';
}
}
$token=md5(uniqid(rand(),true));
$_SESSION['check']=$token;
?>
<form method="post"action="">
<input type="text"name="user">
<input type="text"name="check"value="<?=$token;?>"><input type="submit">
</form>
程序的运行结果为
内部访问
4. 坐标轴上从左到右依次的点为a[0]、a[1]、a[2]、…、a[n-1],设一根木棒的长度为L,求L最多能覆盖坐标轴的几个点?
本题求满足a[j]-a[i]≤L和a[j+1]-a[i]>L这两个条件的j与i之间所包含的点个数的最大值,即j-i+1最大,这样题目就简单多了,方法也很简单:直接从左到右扫描,使用两个索引i和j,i从位置0开始,j从位置1开始,如果a[j]-a[i]≤L,则j++前进,并记录中间经过的点的个数,如果a[j]-a[i]>L,则j--回退,覆盖点个数-1,回到刚好满足条件的时候,将满足条件的最大值与前面找出的最大值比较,记录下当前的最大值,然后执行i++、j++,直到求出最大的点个数。
有两点需要注意,如下:
1)这里可能不存在i和j,使得a[j]-a[i]刚好等于L的情况发生,所以,判断条件不能为a[j]-a[i]==L。
2)可能存在不同的覆盖点但覆盖的长度相同的情况发生,此时只选取第一次覆盖的点。
实现代码如下:
<?php
function maxCover($a,$n,$L)
{
$count=2;
$maxCount=1;
//最长覆盖的点数
$start;
//覆盖坐标的起始位置
$i=0;
$j=1;
while($i<$n&&$j<$n)
{
while(($j<$n)&&($a[$j]-$a[$i]<=$L))
{
$j++;
$count++;
}
$j--;
$count--;
if($count>$maxCount)
{
$start=$i;
$maxCount=$count;
}
$i++;
$j++;
}
printf("覆盖的坐标点:");
for($i=$start;$i<$start+$maxCount;$i++)
{
printf("%d",$a[$i]);
}
echo"<br>";
return $maxCount;
}
$a=array(1,3,7,8,10,11,12,13,15,16,17,19,25);
printf("最长覆盖点数:%d",maxCover($a,13,8));
?>
程序的运行结果为
覆盖的坐标点:7 8 10 11 12 13 15
最长覆盖点数:7
算法性能分析:这个算法的时间复杂度为O(n),其中,n为数组的长度。