一、选择题 4. 下列代码的输出结果是______
<?php
class A{
public function__construct(){
echo"Class A...<br/>";
}
}
class B extends A{
public function__construct(){
echo"Class B...<br/>";
}
}
new B();
?>
A.Class B... B.Class A...Class B... C.Class B...Class A... D.Class A...
A B C D
A
[解析] 在PHP中,如果子类定义__construct,则会覆盖父类的__construct,如果没有定义__construct,则会使用父类的,可以在子类的__construct中显式调用父类的构造函数,方法如下:parent::__construct();。本题中,由于只实例化了子类的对象,因此只会调用子类的构造函数。选项A正确。 所以,本题的答案为A。
二、填空题 1. ______函数能返回脚本里任意行中调用的函数的名称。该函数同时还经常被用在调试中,用来判断错误是如何发生的。
debug_backtrace()
[解析] debug_backtrace()的作用:返回在特定位置调用过的函数名组成的数组,经常被用于调试。
2. 程序echo strtotime("November 11,1952");在Windows系统上输出的是______。
-540892800
[解析] strtotime()是将时间转换成时间戳,但是时间戳是以1970年1月1日00:00:00时间点开始进行计算的,而题目中的代码是将1952年11月11日转换成时间戳,但该时间点并不在时间戳范围内,不能转换成时间戳,所以结果输出为-540892800。
3. 更改mysq1的表字段名的标准语法为______。
alter table表名change原名新名新类型[first|after]
[解析] 修改表字段名:alter table表名CHANGE原字段名新字段名类型: 修改字段类型:alter table表名MODIFY字段名类型: 增加一个字段:alter table表名add COLUMN字段名类型NOT NULL(或DEFAULTNULL);新增一个字段默认不为空(或默认为空); 删除一个字段:alter table表名DROP COLUMN字段名;
4. session的运行机制是______。
服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息
[解析] Session是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。 当程序需要为某个客户端的请求创建一个Session的时候,服务器首先检查这个客户端的请求里是否已包含了一个Session标识SessionID,如果已包含一个SessionID,则说明已经为此客户端创建Session,服务器就按照SessionID把这个Session检索出来使用,如果客户端请求不包含SessionID,那么为此客户端创建一个Session并且生成一个与此Session相关联的SessionID,SessionID的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个SessionID将被在本次响应中返回给客户端保存。
5. Memcache最大能存储的单个item为多大?______。
1MB
[解析] Memcache存储的单个最大数据为1MB,如果数据大于1MB,那么可以考虑将数据进行拆分存储到不同的key中。
三、简答题 1. 文件上传需要注意哪些细节?怎么把文件保存到指定目录?怎么避免上传文件重名问题?
文件上传需要注意以下几点: 1)确保php.ini中已经开启了文件上传功能。 2)如果对文件上传的大小有限制,那么需在php.ini中修改允许上传的最大值,默认是2MB。 3)在上传图片的表单中,form标签需要加上enctype="multipart/form-data"。 4)表单上传图片时,method必须使用post。 5)表单使用file类型,并且有name属性值,后台才能获取。 6)必须保证上传文件的大小不会超出限制,文件类型符合上传要求,上传文件的存储路径不存在问题。 7)需要使用$_FILES接收上传文件信息。其中$_FILES是一个二维数组,一维是上传空间的name,二维对应了文件名、文件类型、上传到临时目录下的临时文件名、文件大小、是否有错误等信息。如果是批量上传,那么二维数组下标是数组而不是字符串。 文件上传后是放置在服务器端的临时路径下的,需要使用move_uploaded_file()函数将上传后的文件保存到指定目录。 为了避免上传图片重名,可以使用时间戳加随机数的方式给文件重新命名。
2. 什么是数据库三级封锁协议?
众所周知,基本的封锁类型有两种:排它锁(X锁)和共享锁(S锁)。所谓X锁是事务T对数据A加上X锁时,只允许事务T读取和修改数据A。所谓S锁是事务T对数据A加上S锁时,其他事务只能再对数据A加S锁,而不能加X锁,直到T释放A上的S锁。若事务T对数据对象A加了S锁,则T就可以对A进行读取,但不能进行更新(S锁因此又称为读锁),在T释放A上的S锁以前,其他事务可以再对A加S锁,但不能加X锁,从而可以读取A,但不能更新A。 在运用X锁和S锁对数据对象加锁时,还需要约定一些规则,例如,何时申请X锁或S锁、持锁时间、何时释放等,称这些规则为封锁协议(Locking Protocol)。对封锁方式规定不同的规则,就形成了各种不同的封锁协议。一般使用三级封锁协议,也称为三级加锁协议。该协议是为了保证正确地调度事务的并发操作。三级加锁协议是事务在对数据库对象加锁、解锁时必须遵守的一种规则。下面分别介绍这三级封锁协议。 一级封锁协议:事务T在修改数据R之前必须先对其加X锁,直到事务结束才释放。事务结束包括正常结束(COMMIT)和非正常结束(ROLLBACK)。一级封锁协议可以防止丢失修改,并保证事务T是可恢复的。使用一级封锁协议可以解决丢失修改问题。在一级封锁协议中,如果仅仅是读数据不对其进行修改,是不需要加锁的,它不能保证可重复读和不读“脏”数据。 二级封锁协议:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,读完后方可释放S锁。二级封锁协议除防止了丢失修改,还可以进一步防止读“脏”数据。但在二级封锁协议中,由于读完数据后即可释放S锁,所以它不能保证可重复读。 三级封锁协议:一级封锁协议加上事务T在读取数据R之前必须先对其加S锁,直到事务结束才释放。三级封锁协议除防止了丢失修改和不读“脏”数据外,还进一步防止了不可重复读。
3. smarty的工作原理是什么?如何对smarty进行二次开发?
1)PHP程序运行时,初始化smarty模版引擎(创建对象,设置属性)。 2)加载smarty模板文件(.html或.tpl文件),并对其编译,生成编译文件放置在编译目录下。 3)执行编译文件,并做模板替换,生成静态文件。若开启静态缓存,则会将静态缓存文件缓存到cache目录下。 4)最后输出结果到浏览器。 做smarty的二次开发:可以通过自定义变量调解器、函数等插件方式来实现辅助开发,还有重写smarty的一些方法可以扩展开发。
4. 面向对象的特征是什么?
面向对象的主要特征有抽象、继承、封装和多态。 1)抽象:抽象就是忽略一个主体中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用部分细节。抽象包括两个方面,一是过程抽象,二是数据抽象。 2)继承:继承是一种联结类的层次模型,并且允许和鼓励类的重用,它提供了一种明确表述共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类继承。新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。派生类可以从它的基类那里继承方法和实例变量,并且子类可以修改或增加新的方法使之更适合特殊的需要。 3)封装:封装是指将客观事物抽象成类,每个类对自身的数据和方法实行保护。类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的信息进行隐藏。 4)多态:多态是指允许不同类的对象对同一消息做出响应。多态包括参数化多态和包含多态。多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好地解决了应用程序函数同名问题。
5. 5名海盗抢得了窖藏的100枚金币,并打算瓜分这些战利品。这是一些讲民主的海盗(当然是他们自己特有的民主),他们的习惯是按下面的方式进行分配:最厉害的一名海盗提出分配方案,然后所有的海盗(包括提出方案者本人)就此方案进行表决。如果50%或更多的海盗赞同此方案,此方案就获得通过并据此分配战利品。否则提出方案的海盗将被扔到海里,然后下一名最厉害的海盗又重复上述过程。
所有的海盗都乐于看到他们的一位同伙被扔进海里,不过,如果让他们选择的话,他们还是宁可得一笔现金。他们当然也不愿意自己被扔到海里。所有的海盗都是有理性的,而且知道其他的海盗也是有理性的。此外,没有两名海盗是同等厉害的——这些海盗按照完全由上到下的等级排好了座次,并且每个人都清楚自己和其他所有人的等级。这些金块不能再分,也不允许几名海盗共有金块,因为任何海盗都不相信他的同伙会遵守关于共享金块的安排。这是一伙每人都只为自己打算的海盗。
最凶的一名海盗应当提出什么样的分配方案才能使他获得最多的金子呢?
如果轮到第四个海盗分配:100,0; 轮到第三个:99,0,1; 轮到第二个:99,0,1,0; 轮到第一个:98,0,1,0,1,这就是第一个海盗的最佳方案。 可以从后往前推测每次最优的方案,从而确定第一种方案就是最好的。 1)当只剩两个海盗分金时,因为只要有50%或以上的支持率则方案通过,所以第四个海盗和第五个海盗分金时,无论第五个海盗是否支持自己,第四个海盗都可以给自己分配100枚金币。 2)当只剩三个海盗分金时,第三个海盗分金的方案,除了自己的支持外,还需要一个海盗的支持,否则方案不通过。所以,如果第三个海盗想要拿最多金币,最好的方案就是让第五个海盗得到金币来支持他,因为第四个海盗可以通过否定第三个海盗的方案实现自己的利益最大化。所以,第三个海盗得99枚金币,而第五个海盗得1枚金币的方案是最好的方案。 3)当只剩下四个海盗分金时,第二个海盗的方案,只需要一个海盗支持他即可通过方案。由2)的分析知道,要第四个海盗支持自己是最有利的,所以可以得到最好的方案是第二个海盗得99枚金币,第四个海盗得1枚金币的方案。 最初的情况,5个海盗分金,第一个海盗必须要其余2名海盗支持自己,他才有可能得到最多的金币。通过3)的分析知道,分配给第三个海盗和第五个海盗1枚金币,让他们支持自己是最优的方案。
四、编程题 1. 写一个函数,算出两个文件的相对路径。例如,$a=∨a/b/c/d/e.php\;,$b=∨a/b/12/34/c.php\;,计算出$b相对于$a的相对路径应该是../../c/d。
示例代码如下:
function getRelativepath($a,$b){
$returnpath=array(dirname($b));
for($n=1,$len=count($arrB);$n<$len;$n++){
if($arrA[$n]!=$arrB[$n]){
break;
}
}
if($len-$n>0){
$returnpath=array_merge($returnpath,array_fill(1,$len-$n,"\...\"));
}
$returnpath=array_merge($returnpath,array_slice($arrA,$n));
}
$a="∨a/b/c/d/e.php\";
$b="∨a/b/12/34/c.php\";
echo getRelativepath($a,$b);
2. 10个房间里放着随机数量的金币。每个房间只能进入一次,并只能在一个房间中拿金币。一个人采取如下策略:前4个房间只看不拿。随后的房间只要看到比前4个房间都多的金币数,就拿;否则就拿最后一个房间的金币。编程计算这种策略拿到最多金币的概率。
<?php /* **函数功能:把数组a看成房间,总共n个房间, ** 判断用指定的策略是否能拿到最多金币 **返回值:如果能拿到返回1,否则返回0 */ function getMaxNum($a,$n) { //随机生成10个房间里金币的个数 for($i=0;$i<$n;$i++) { $a[$i]=rand()%10+1;//生成1~10的随机数 } //找出前四个房间中最多的金币个数 $max4=0; for($i=0;$i<4;$i++) { if($a[$i]>$max4)$max4=$a[Si]; } for($i=4;$i<$n-1;$i++) { if($a[$i]>$max4)//能拿到最多的金币 return 1; } return 0;//不能拿到最多的金币 } $a=array(); $monitorCount=1000; $success=0; for($i=0;$i<$monitorCount;$i++) { if(getMaxNum($a,10))$success++; } printf("%f\n",$success/$monitorCount); ?> 程序的运行结果为 0.421 运行结果与金币个数的选择以及模拟的次数都有关系,而且由于是个随机问题,因此同样的程序每次的运行结果也会不同。
[解析] 这道题是要求一个概率的问题,由于10个房间里放的金币的数量是随机的,因此,在编程实现的时候首先需要生成10个随机数来模拟10个房间里金币的数量。然后判断通过这种策略是否能拿到最多的金币。如果仅仅通过一次模拟来求拿到最多金币的概率显然是不准确的,那么就需要进行多次模拟,通过记录模拟的次数m,拿到最多金币的次数n,从而可以计算出拿到最多金币的概率n/m。显然这个概率与金币的数量以及模拟的次数有关系,模拟的次数越多,越能接近真实值。
3. 设计一个算法,判断给定的一个数n是否是某个数的平方,不能使用开方运算。例如,16就满足条件,因为它是4的平方;而15则不满足条件,因为不存在一个数使得其平方值为15。
通过对平方数进行分析发现有如下规律: (n+1)^2=n^2+2n+1=(n-1)^2+(2*(n-1)+1)+2*n+1=…=1+(2*1+1)+(2*2+1)+…+(2*n+1)。 通过上式可以发现,这些项构成了一个公差为2的等差数列的和。由此可以得到如下的解决方法:对n依次减1,3,5,7,…,如果相减后的值大于0,则继续减下一项;如果相减的后的值等于0,则说明n是某个数的平方;如果相减后的值小于0,则说明n不是某个数的平方。根据这个思路,代码实现如下: function isPower($n) { if($n<=0) { printf("%d不是自然数\n",n); return false; } $minus=1; while($n>0) { $n=$n-$minus; //n是某个数的平方 if($n==0) return true; //n不是某个数的平方 else if($n<0) return false; //每次减数都加2 else $minus+=2; } return false; }
有一个MySQL数据库表payment记录用户购买订单,表结构如下: TABLE payment( id int unsigned AUTO_INCREMENT, user id int unsigned comment '用户id', quantity smallint unsigned comment'本次购买产品数量', pay_time timestamp comment'购买时间', PRIMARY KEY(id) ) 用户每访问成功付款一笔订单(从进入到离开),就会向这个表增加一条记录,记录用户的ID(user_id),以及购买的产品数量。比如:“208,2”,表示208这个用户购买2个产品。4. 请写出一个SQL语句挑出用户(id=100)最近购买的10条订单。
select*from payment where user_id=100 order by pay_time desc limit 10;
5. 请写出一个SQL语句挑出用户(id=100)最近购买的第10~20条订单(共10个)。
select*from payment where user_id=100 order by pay_time desc limit 10,10;
6. 请写出一个SQL语句挑出购买产品数最多的10个用户(user_id)和对应购买的产品总数。
select user_id,sum(quantity) from payment group by user_id order by sum(quantity) desc limit 10;