一、选择题 5. 有如下代码,程序的输出结果为______
<?php
class A{
public static $num=0;
public function__construct(){
self::$num++;
}
}
new A();
new A();
new A();
echo A::$num;
?>
A B C D
D
[解析] 本题中,当实例化类A时,只会触发__construct()的语句,而不触发public static$num=0。同时,由于$num是static类型的值,newA()实例化了3次,$num的值会被执行++操作3次,$num的值为3,选项D正确。 所以,本题的答案为D。
6. 以下程序的运行结果为______
<?php
$str="LAMP";
$str1="LAMPBrother";
$strc=strcmp($str;$str1);
switch($strc){
case 1:
echo "str>str1";
break;
case-'7':
echo"str<str1";
break;
case ():
echo "str=str1";
break;
default:
echo "str<>str1";
}
?>
A.str>str1 B.str<str1 C.str=str1 D.str<>str1
A B C D
B
[解析] strcmp($str1,$str2)函数的功能是比较两个字符串的大小,如果$str1==$str2,则返回0;如果$str1>$str2,则返回值大于0,具体值为1乘上两个字符串相比不相同的字符个数;如果$str1<$str2,则返回值小于0,具体值为-1乘上两个字符串相比不相同的字符个数。 本题中,$str="LAMP",$str1="LAMPBrother",两个字符串不相同的字符有7个,且$str<$str2,所以,返回值为负数,即(-1*7)=-7。在switch语句的各类case语句中,匹配到“-7”,选项B正确。 所以,本题的答案为B。
7. 以下代码的输出是______
$somevar=15;
function addit(){
GLOBAL $somevar;
$somevar++;
echo "somevar is $somevar";
}
addit();
A.somevar is 15 B.somevar is 16 C.somevar is 1 D.somevar is $ somevar
A B C D
B
[解析] 在函数体内通过GLOBAL引用了全局变量somevar,它的初始值为15,当执行自增操作后结果变为16,而使用双引号会把引号内的变量替换为它的值,因此输出为somevar is 16。 所以,本题的答案为B。
二、填空题 1. getdate()函数返回的是______。
一个数组。
[解析] getdate()函数返回指定时间的时间戳或当前时间的时间格式,它返回的是一个数组。该数组中包含的内容有秒、分、小时、一个月中的第几天、一周中的某一天、月、年、一年中的某一天、星期几的名称、月份的名称、自Unix纪元以来经过的秒数等。
2. 程序echo strtotime("November 11,1952");在Windows系统上输出的是______。
-540892800。
[解析] strtotime()是将时间转换成时间戳,但是时间戳是以1970年1月1日00:00:00时间点开始进行计算的,而题目中的代码是将1952年11月11日转换成时间戳,但该时间点并不在时间戳范围内,不能转换成时间戳,所以结果输出为-540892800。
3. 有一个数组,里面有重复的元素,使用______函数可以打印出不重复的元素。
array_unique()
[解析] 可以使用array_unique()函数打印出不重复的元素,array_unique()数的作用是移除数组中重复的值,并返回数组结果。 实现代码如下: <?php $arr=array(1,2,3,2,4,2,3,1); print_r(array_unique($arr)); ?> 程序的运行结果为Array([0]=>1[1]=>2[2]=>3[4]=>4)。
4. 可以用来开启档案以便读/写的函数是______。
fopen()。
[解析] fopen()函数可以用来开启档案以便读、写。
5. 要配置PHP环境,只需修改______文件。
php.ini。
[解析] php.ini是PHP环境配置文件,httpd.conf是Apache配置文件,php.exe是PHP运行文件。
三、简答题 1. 组合与继承的区别是什么?
组合和继承是面向对象中两种代码复用的方式。组合是指在新类里面引用原有类的对象,重复利用已有类的功能。继承是面向对象的主要特性之一,它允许设计人员根据其他类的实现来定义一个类的实现。组合和继承都允许在新的类中设置子对象(subobject),只是组合是显式的,而继承则是隐式的。组合和继承存在着对应关系:组合中的整体类和继承中的子类对应,组合中的局部类和继承中的父类对应。
二者的区别在哪里呢?首先分析一个实例。Car表示汽车对象,Vehicle表示交通工具对象,Tire表示轮胎对象。三者的类关系如下图所示。
从上图中可以看出,Car是Vehicle的一种,因此是一种继承关系(又被称为is-a关系);而Car包含了多个Tire,因此是一种组合关系(又被称为has-a关系)。其实现方式如下:
继 承
组 合
class Verhicle { } class Car extends Verhicle{ }
class Tire{ } class Car extends Verhicle{ $t=new Tire(); }
2. 请简单介绍什么是视图。
视图是从数据库的基本表中选取出来的数据组成的逻辑窗口,它不同于基本表,是一个虚表,在数据库中,存放的只是视图的定义而已,而不存放视图包含的数据项,这些项目仍然存放在原来的基本表结构中。 视图的作用非常多,主要有以下几点:首先,可以简化数据查询语句;其次,可以使用户从多角度看待同一数据;再次,通过引入视图,可以提高数据的安全性;最后,视图提供了一定程度的逻辑独立性等。 通过引入视图机制,用户可以将注意力集中在其关心的数据上而非全部数据,这样就大大提高了用户效率与用户满意度,而且如果这些数据来源于多个基本表结构,或者数据不仅来自于基本表结构,还有一部分数据来源于其他视图,并且搜索条件又比较复杂,那么需要编写的查询语句就会比较烦琐,此时定义视图就可以使数据的查询语句变得简单可行。定义视图可以将表与表之间的复杂操作连接和搜索条件对用户不可见,用户只需要简单地对一个视图进行查询即可,所以增加了数据的安全性,但是不能提高查询的效率。
3. Memcache和Memcached有什么区别?
Memcache是一个自由开放的高性能内存对象缓存系统,可用于加速动态web应用程序,减轻数据库负载。Memcache是这个软件项目的一般叫法,但项目的主程序文件叫Memcached.exe,在服务端主要靠这个守护进程管理HashTable。因为这个进程名可以把这个软件系统叫Memcached。 PHP对该软件存在两个pecl扩展,分别是Memcache和Memcached。 它们的区别如下: 1)Memcache扩展是完全在PHP框架内开发的,而Memcached扩展是使用libMemcached开发的,在方法上Memcached的方法比Memcache多,但是用法方式都差不多。 2)Memcached因为使用了libMemcached所以只支持OO接口,而Memcache是OO和非OO两套接口并存的。 3)Memcached是支持Binary Protocol的,而Memcache不支持,所以Memcached的性能更高。
4. utf8编码需要注意哪些问题?
网站存在十几种不同的编码,如果编码不同,那么网页内容显示就会出现乱码。如果网站的编码为utf-8,那么相关的文件和数据库都必须使用utf-8编码,否则网页就会出现乱码。 具体需要注意utf8编码的文件有: 1)数据库需要用utf8编码,包括创建的数据库和表都必须使用utf8编码。 2)PHP代码连接数据库的时候,也必须指定所使用的编码为utf-8。 3)网站中所有文件都使用utf-8编码,在php文件中指定头部编码为utf-8,即header("content-type:text/html;charset=utf-8"),html文件也需要指定utf-8编码,即utf-8 header("content-type:text/html;charset=utf-8")。
5. 什么是单例模式?
单例模式是在应用程序中最多只能拥有一个该类的实例存在,一旦创建就会一直在内存中。 由于单例模式的设定,所以它常应用于数据库类设计,可以保证只连接一次数据库。 单例类的特点如下: 1)单例类不能直接实例化创建,只能由类本身实例化。因此,构造函数必须标记为private,从而防止类被实例化。 2)需要保证一个能访问到的实例公开的静态方法和一个私有静态成员变量来保存类实例。 3)类中通常需要有一个空的私有clone()方法防止别人对单例类进行实例复制。 示例代码如下: <?php class Database { private static $instance; private function__construct() { //to do } private function__clone() { //to do } public static function getInstance() { if(!(self::$instance instanceof self)){ self::$instance=new self(); } return self::$instance; } } $a=Database::getInstance(); $b=Database::getlnstance(); print_r($a===$b); ?>
四、编程题 在数据库test中的一个表student,字段是name、class、score,分别代表姓名、所在班级、分数。(请写出符合要求的SQL语句)1. 每个班级中的学生按照成绩降序排序。
select*from student order by score desc;
2. 查出每个班的及格人数和不及格人数,格式为class、及格人数。
及格人数:select class,count(name)as'及格人数'from student s where score>=60 group by class; 不及格人数:select class,count(name)as'不及格人数'from student s where score<60 group by class;
3. 用PHP写入连接数据库("localhost","msuser","mspass")、执行以上SQL、显示结果、关闭数据库的过程。
<?php $conn=mysql_connect('localhost','root','root'); mysql_select_db('test'); //每个班级中的学生按照成绩降序排序 $sql="select*from student order by score desc"; //查出每个班的及格人数和不及格人数,格式为class、及格人数 $sql="select class,count(name)as'num'from student where score>=60 group by class"; $result=mysql_query($sql); //查询不及格人数 $sql2="select class,count(name)as'num'from student where score<60 group by class"; $result2=mysql_query($sql2); mysql_close(); ?>
4. 已知随机数生成函数rand7()能产生的随机数是整数1~7的均匀分布,如何构造rand10()函数,使其产生的随机数是整数1~10的均匀分布。
<?php ∥产生的随机数是整数1~7的均匀分布 function rand7() { return rand()%7+1; } //产生的随机数是整数1~10的均匀分布 function rand10() { $x=0; do { $x=(rand7()-1)*7+rand7(); }while($x>40); return $x%10+1; } for($i=0;$i!=10;++$i) printf("%d",rand10()); printf("\n"); ?> 程序的运行结果为 6 10 8 1 8 6 3 8 10 7
[解析] 要保证rand10()产生的随机数是整数1~10的均匀分布,可以构造一个1~10*n的均匀分布的随机整数区间(n为任何正整数)。假设x是这个1~10*n区间上的一个随机数,那么x%10+1就是均匀分布在1~10区间上的整数。 根据题意,rand7()函数返回1~7的随机数,那么rand7()-1则得到一个离散整数集合,该集合为{0,1,2,3,4,5,6},集合中每个整数的出现概率都为1/7。那么(rand7()-1)*7得到另一个离散整数集合A,该集合元素为7的整数倍,即A={0,7,14,21,28,35,42},其中,每个整数的出现概率也都为1/7。而由于rand7()得到的集合B={1,2,3,4,5,6,7},其中每个整数出现的概率也为1/7。显然集合A与集合B中任何两个元素和组合可以与1~49之间的一个整数一一对应,即1~49之间的任何一个数,可以唯一地确定A和B中两个元素的一种组合方式,这个结论反过来也成立。由于集合A和集合B中元素可以看成是独立事件,根据独立事件的概率公式P(AB)=P(A)P(B),得到每个组合的概率是1/7*1/7=1/49。因此,(rand7()-1)*7+rand7()生成的整数均匀分布在1~49之间,而且,每个数的概率都是1/49。 所以,(rand7()-1)*7+rand7()可以构造出均匀分布在1~49的随机数,为了将49种组合映射为1~10之间的10种随机数,就需要进行截断,即将41~49这样的随机数剔除掉,得到的数1~40仍然是均匀分布在1~40的,这是因为每个数都可以看成一个独立事件。由1~40区间上的一个随机数x,可以得到x%10+1就是均匀分布在1~10区间上的整数。
5. 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。显然这个概率与金币的数量以及模拟的次数有关系,模拟的次数越多,越能接近真实值。
6. 已知三个升序整数数组a[1]、b[m]和c[n],在三个数组中各找一个元素,使得组成的三元组距离最小。三元组距离的定义是,假设a[i]、b[j]和c[k]是一个三元组,那么距离为Distance=max(|a[i]-b[j]|,|a[i]-c[k]|,|b[j]-c[k]|),请设计一个求最小三元组距离的最优算法。
function maxNum($a,$b,$c){ $max=$a<$b?Sb:$a; $max=$max<$c?$c:$max; return$max; } function minNum($a,$b,$c){ $min=$a<$b?$a:$b; $min=$min<$c?$min:$c; return$min; } function getMinDistance($a,$aLen,$b,$bLen,$c,$cLen){ $curDist=0; $min=0; $minDist=max($a); $i=0;//数组a的下标 $j=0;//数组b的下标 $k=0;//数组c的下标 while(1){ $curDist=maxNum(abs($a[$i]-$b[$j]),abs($a[$i]-$c[$k]),abs($b[$j]-$c[$k])); if($curDist<$minDist) $minDist=$curDist; //找出当前遍历到三个数组中的最小值 $min=minNum($a[$i],$b[$j],$c[$k]); if($min==$a[$i]){ if(++$i>=$aLen) break; } else if($min==$b[$j]){ if(++$j>=$bLen) break; } else{ if(++$k>=$cLen) break; } } return $minDist; } 采用这种算法最多只需要对三个数组分别遍历一遍,因此,时间复杂度为O(1+m+n)。
[解析] 假设当前遍历到这三个数组中的元素分别为ai 、bi 、ci ,并且ai <=bi <=ci ,此时它们的距离肯定为Di =ci -ai ,那么可以分如下三种情况讨论: 1)如果接下来求ai 、bi 、ci+1 的距离,由于ci+1 >=ci ,此时它们的距离必定为Di+1 =ci+1 -ai ,显然Di+1 >=Di ,因此,Di+1 不可能为最小距离。 2)如果接下来求ai 、bi+1 、ci 的距离,由于bi+1 >=bi ,如果bi+1 <=ci ,此时它们的距离仍然为Di+1 =ci -ai ;如果bi+1 >ci ,那么此时它们的距离为Di+1 =bi+1 -ai ,显然Di+1 >=Di ,因此,Di+1 不可能为最小距离。 3)如果接下来求ai+1 、bi 、ci 的距离,如果ai+1 <ci -|ci -ai |,此时它们的距离Di+1 =max(ci -ai+1 ,ci =bi ),显然Di+1 <Di ,因此,Di+1 有可能是最小距离。 综上所述,在求最小距离的时候只需要考虑第3种情况即可。具体实现思路为,从三个数组的第一个元素开始,首先求出它们的距离minDist,接着找出这三个数中最小数所在的数组,只对这个数组的下标往后移一个位置,接着求三个数组中当前遍历元素的距离,如果比minDist小,则把当前距离赋值给minDist,以此类推,直到遍历完其中一个数组为止。 例如,给定数组$a=[3,4,5,7,15];$b=[10,12,14,16,17];$c=[20,21,23,24,37,30]; 1)从三个数组中找出第一个元素3、10、20,显然它们的距离为20-3=17。 2)由于3最小,因此,数组a往后移一个位置,求4、10、20的距离为16,由于16<17,因此,当前数组的最小距离为16。 3)同理,对数组a后移一个位置,依次类推,直到遍历到15的时候,当前遍历到三个数组中的值分别为15、10、20,最小距离为10。 4)由于10最小,因此,数组b往后移动一个位置遍历12,此时三个数组遍历到的数字分别为15、12、20,距离为8,当前最小距离是8。 5)由于12最小,数组b往后移动一个位置为14,依然是三个数中最小值,往后移动一个位置为16,当前的最小距离变为5,由于15是数组a的最后一个数字,因此,遍历结束,求得最小距离为5。