php易混淆知识点

一、define(“constant”,  “hello world”);和const constant = “hello world”;的区别?

(0).使用const使得代码简单易读,const本身就是一个语言结构,而define是一个函数。另外const在编译时要比define快很多。

(1).const用于类成员(或者接口成员)变量的定义,一经定义,不可修改。php5.3以上支持类外通过const定义常量,并且在使用命名空间时只能用这个来定义常量. define不可用于类成员变量的定义,可用于全局常量。

比如:
one.php
<?php
namespace test;
const AA= 'AA'; 
define('BB','BB');
?>
two.php
<?php
include_once('one.php');
echo \test\AA; //正确
echo \test\ BB;//错误


const DEFINES='tt';
define('DEFINES','ccdec');

?>

file1.php

<?php
const DEFINES = 1;
define('DEFINES','ccc');
echo DEFINES;  
?>

结果://Notice: Constant DEFINES already defined 输出为1,但最后的值以第一个定义的为准
说明在命名空间之外const与define定义常量的作用是一样的

(2).const可在类中使用,define不能。

(3).const不能在条件语句中定义常量。

例如: 

if (...){ 

  const FOO = 'BAR';  // 无效的invalid 

}  

if (...) { 

  define('FOO', 'BAR'); // 有效的valid 

}

(4).const采用一个普通的常量名称,define可以采用表达式作为名称。 

 const  FOO = 'BAR';  

 for ($i = 0; $i < 32; ++$i) { 

  define('BIT_' . $i, 1 << $i); 

} 

(5).const只能接受静态的标量,而define可以采用任何表达式。

例如: 

const BIT_5 = 1 << 5;  // 无效的invalid  

define('BIT_5', 1 << 5); // 有效的valid

(6).const定义的常量时大小写敏感的,而define可通过第三个参数(为true表示大小写不敏感)来指定大小写是否敏感。

例如:

define('FOO', 'BAR', true);  

echo FOO; // BAR 

echo foo; // BAR

二:php中int的范围?32位系统和64位系统是否有区别?为什么?php数据入库前清理,注意php intval与mysql的int取值范围不同。

php中int的范围

整型值可以使用十进制,十六进制,八进制或二进制表示,前面可以加上可选的符号(- 或者 +)。

二进制表达的 integer 自 PHP 5.4.0 起可用。

要使用八进制表达,数字前必须加上 0(零)。要使用十六进制表达,数字前必须加上 0x。要使用二进制表达,数字前必须加上 0b

注意:

整型数的字长和平台有关,尽管通常最大值是大约二十亿(32 位有符号)。64 位平台下的最大值通常是大约 9E18。PHP 不支持无符号整数。Integer 值的字长可以用常量 PHP_INT_SIZE来表示,自 PHP 4.4.0 和 PHP 5.0.5后,最大值可以用常量 PHP_INT_MAX 来表示。

所谓32位处理器就是一次只能处理32位,也就是4个字节的数据,而64位处理器一次就能处理64位,即8个字节的数据。
学过计算机组成原理的都知道32处理器具有32根数据线,一个存取周期可以通过这32根数据线读取32bit的数据(每根传输1bit),也就是4字节,同理在64位处理器在一个存取周期能够处理8字节数据。
unsigned int在64位系统中使用8个字节表示,表示的数值范围0~2^64-1,也就是说64位系统较32位系统能够表示更大的数值,unsigned int在64位系统中占用8个字节的好处:一是方便存取,二是能够表示更大数值范围。

1.64bit CPU拥有更大的寻址能力,最大支持到16GB内存,而32bit只支持4G内存 
2.64位CPU一次可提取64位数据,比32位提高了一倍,理论上性能会提升1倍。但这是建立在64bit操作系统,64bit软件的基础上的。
名词解释:什么是64位处理器 
之所以叫做“64位处理器”,是因为电脑内部都是实行2进制运算,处理器(CPU)一次处理数据的能力也是2的倍数。8位处理器、16位处理器、32位处理器和64位处理器,其计数都是2的倍数。一次处理的数据越大,该电脑处理信息的能力越来越大;因此64位处理在先天就比32位处理器具有快速的能力。那为什么不用更高级的128位处理器呢?因为位数越高,处理器芯片的设计也就越复杂,目前的技术水平暂时无法制造这么复杂的芯片。

参考:http://bbs.csdn.net/topics/390191926

整数溢出

如果给定的一个数超出了 integer 的范围,将会被解释为 float。同样如果执行的运算结果超出了 integer 范围,也会返回 float

Example #3 32 位系统下的整数溢出
<?php
$large_number = 2147483647;
var_dump($large_number);                     // int(2147483647)

$large_number = 2147483648;
var_dump($large_number);                     // float(2147483648)

$million = 1000000;
$large_number =  50000 * $million;
var_dump($large_number);                     // float(50000000000)
?>
Example #4 64 位系统下的整数溢出
<?php
$large_number = 9223372036854775807;
var_dump($large_number);                     // int(9223372036854775807)

$large_number = 9223372036854775808;
var_dump($large_number);                     // float(9.2233720368548E+18)

$million = 1000000;
$large_number =  50000000000000 * $million;
var_dump($large_number);                     // float(5.0E+19)
?>

PHP 中没有整除的运算符。1/2 产生出 float 0.5。值可以舍弃小数部分强制转换为 integer,或者使用 round() 函数可以更好地进行四舍五入。

<?php
var_dump(25/7);         // float(3.5714285714286) 
var_dump((int) (25/7)); // int(3)
var_dump(round(25/7));  // float(4) 
?>

浮点型转换

当从浮点数转换成整数时,将向下取整。

如果浮点数超出了整数范围(32 位平台下通常为 +/- 2.15e+9 = 2^31,64 位平台下通常为 +/- 9.22e+18 = 2^63),则结果为未定义,因为没有足够的精度给出一个确切的整数结果。在此情况下没有警告,甚至没有任何通知!

 

32位、64位对api的影响:Andriod、iOS、JavaScript等

常见操作系统:

Android:只有32位

iOS:只有32位

Linux server(CentOS、Ubuntu、RedHat等):64位(大部分公司服务器使用)、32位(已淘汰)

Windows PC:64位,32位

常见软件:

Android app:java或c++。如果用java,os无关,则int是64位。如果用c++,待验证。

iOS app:object c,os有关。int是32位。

php:os有关。编译安装与server相同,int为64位或32位。

mysql:os无关。int为64位。

32位浏览器(chrome、firefox)中的JavaScript:约9千万亿,待定,未找到权威文档

64位浏览器(waterfox)中的JavaScript:约9千万亿,待定,未找到权威文档

var a = 9000000000000001;alert(a -1 + 1);

对api程序开发的影响:

通过php开发api提供json给app、浏览器js引擎使用时,由于php的web server是64位的,而Android、iOS、浏览器js的int范围不一致。

32位int大概为21亿,比如网盘的用户总容量为5GiB,php接口返回数据如下:

{

    "capacity" : 5368709120, //容量53亿Byte,即5GiB,超过了21亿

    "used_space" : 1073741824

}

结果:Android Java app正常,iOS app无法处理数据,浏览器JavaScript正常。

所以需要使用string,而不是int,iOS拿到之后再做大整数相除即可。即:

{

    "capacity" : "5368709120",

    "used_space" : "1073741824"

}

PHP 中的整数是 C 语言的中的long 类型,是有符号的,最大值是 2^31 。在 64 位平台上,long可以达到 2^63.

这样的话,有些PHP 函数输出的结果在各个平台上就会不一致了。

php -r "echo ip2long('255.255.255.255');" 在64位平台下是: 4294967295, 在32位平台下是 -1。还有比如 filesize 在 文件 大于 2G的时候,在不同的平台下结果就不一致了。

解决这个问题很简单,sprintf("%u", filesize($file)). 把结果转换为 一个字符串。为什么结果会一样呢:无符号数 4294967295 的补码 和 有符号数 -1 的补码 是一样的。类似,返回值为int 最后结果可能大于 2^31 的函数,都要用这样的方法处理。

注意,返回的虽然是一个字符串,但是,当进行四则运算的时候,PHP会自动装换。如果 数大于 2^31 会转换为 int 如果大于 了,就转换为double。

参考:32位和64位系统区别及int字节数  http://blog.csdn.net/zhongzhiwei/article/details/8678885

php数据入库前清理,注意php intval与mysql的int取值范围不同

php intval的取值范围与mysql的int类型一样吗? 
查了一下,不一样…… 
http://php.net/manual/en/function.intval.php
http://dev.mysql.com/doc/refman/5.1/zh/column-types.html#numeric-types
php intval的取值范围:与操作系统相关,32位系统上为-2147483648到2147483647,64位系统上为-9223372036854775808到9223372036854775807。 
mysql int取值范围:与操作系统无关,为-2147483648到2147483647,无符号为0到4294967295。 
mysql bigint取值范围:与操作系统无关,为-9223372036854775808到9223372036854775807,无符号为0到18446744073709551615。

三、php下intval()和(int)转换使用与区别

int intval ( mixed $var [, int $base ] )

没啥区别,一般用(int),另外还有 float, string, array等
intval()而言,如果参数是字符串,则返回字符串中第一个不是数字的字符之前的数字串所代表的整数值。如果字符串第一个是‘-',则从第二个开始算起。如果参数是符点数,则返回他取整之后的值。
当intval()返回的值在一个4字节所能表示的范围之内(-2147483648~2147483647),对于超过这个范围的值将用边界值代替。 

例:intval("A")=0; intval(12.3223)=12; intval("1123Asdfka3243")=1123; 
int(); 
例: 
$a=0.13; 
$b=(int)$a; //$b=0; 

$a=0.99; 
$b=(int)$a; //$b=0; 

$a=1.01; 
$b=(int)$a; //$b=1; 

$a=1.99; 
$b=(int)$a; //$b=1;

 

PHP中intval()等int转换时的意外异常情况解析

$a = 9.45*100;  
var_dump($a);  
var_dump(intval($a));  
  
$a = 945*1.00;  
var_dump($a);  
var_dump(intval($a)); 

运行结果:float(945) int(944) float(945) int(945

原因解释:

这个代码虽然把结果都告诉了,但是很多人还是看不懂,这样就解释不了为什么会有意想不到的转型情况发生。

网上对这个情况讲的都模棱两可不知所云的。我在这里简单的解释下:

9.45这个数字在我们看到的是这样的,但是机器内部却不是这个,而是9.44999999999999999...。所以:

9.449999*100 = 944.9999。这样就可以看懂了吧?intval把尾数直接去掉了,这个叫神马来的呵呵忘了名字了.这样说来,intval和floor()函数差不多咯。呵呵。这个也是我之前没有察觉到的。也没注意到intval会向下舍入。

而 1.00就没有什么1.0099999这样的了,所以945*1.00就会出现一个float的945.那intval去转型自然就不会出现944的情况了。

还有些经典考试题,如:intval((0.1+0.7)*10) 等于7而不是8的。都是这个道理。

参考:http://www.php.net/manual/zh/language.types.float.php#warn.float-precision

四、什么是静态变量?适用的情况是?优点和缺点分别是什么?

静态变量是指用static声明的变量,这种变量与局部变量的区别是,当静态变量离开了它的作用范围后,它的值不会自动消亡,而是继续存在,当下次再用到它的时候,可以保留最近一次的值。

<?php
function add() 
{ 
    static $i=0; 
    $i++; 
    echo $i; 
} 
add(); 
echo " "; 
add(); 
?>

静态变量的好处: 持有对象,对于运行时的常量和需要缓存的数据是很重要的。
坏处:整个应用的生命周期内一直占用资源,例如web应用每一次登录在static map cache中记录一个数据,而不(定期)清除。那么时间一长,这个东西非常大。
对于缓存的数据,如果运行时发生变化需要考虑同步操作带来的并发问题。

1  静态局部变量在静态存储区内分配存储单元。在程序整个运行期间都不释放。而自动变量(即动态局部变量)属于动态存储类别,存储在动态存储区空间(而不是静态存储区空间),函数调用结束后即释放。 
2 为静态局部变量赋初值是在编译时进行值的,即只赋初值一次,在程序运行时它已有初值。以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时 的值。而为自动变量赋初值,不是在编译时进行的,而是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句 
3 如果在定义局部变量时不赋初值的话,对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符(对字符型变量)。而对自动变量来说,如果不赋 初值,则它的值是一个不确定的值。这是由于每次函数调用结束后存储单元已释放,下次调用时又重新另分配存储单元,而所分配的单元中的值是不确定的。 
4 虽然静态局部变量在函数调用结束后仍然存在,但其他函数是不能引用它的,也就是说,在其他函数中它是“不可见”的。

五、include,include_once,require,require_once的区别?

六、dl函数的用途,什么情况下不能使用?如何获得当前进程id?如何获得当前文件include文件列表?当php做为命令行运行时容易超时退出,如何延长运行时间?

六、string get_cfg_var ( string $option ) 与 ini_get() 的区别
get_cfg_var returns the value from php.ini directly,while the ini_get returns   the runtime config value. I have tried it on PHP 5.1.6 

[EDIT by danbrown AT php DOT net: The author of this note means that ini_get() will return values set by ini_set(), .htaccess, a local php.ini file, and other functions at runtime.  Conversely, get_cfg_var() will return strictly the server php.ini.]

 

七、php中getenv()和$_SERVER的区别

  二者的区别在于,getenv不支持IIS的isapi方式运行的php

 

八、获取php运行信息

int getmypid ( void )  返回当前 PHP 进程 ID,或在错误时返回 FALSE 如:查看进程管理器发现对应的映像名称为httpd.exe

int getmygid ( void ) 返回当前 PHP 脚本拥有者的用户组 ID,或在错误时返回 FALSE

int getmyuid ( void ) 返回当前脚本的用户 ID,或在错误时返回 FALSE

string get_current_user ( void ) 返回当前 PHP 脚本所有者名称。

string php_sapi_name ( void ) 返回描述 PHP 所使用的接口类型(the Server API, SAPI)的小写字符串。 例如,CLI 的 PHP 下这个字符串会是 "cli",Apache 下可能会有几个不同的值,取决于具体使用的 SAPI。 以下列出了可能的值。

 

九、php是否支持多线程?

PHP语言本身是不支持多线程的. 总结了一下网上关于PHP模拟多线程的方法, 总的来说, 都是利用了PHP的好伙伴们本身所具有的多线程能力. PHP的好伙伴指的就是LINUX和APACHE啦, LAMP嘛.另外, 既然是模拟的, 就不是真正的多线程. 其实只是多进程. 进程和线程是两个不同的概念. 好了, 以下方法都是从网上找来的.

我们知道php(做为现在的主流开发语言)本身是不支持多线程的, 但是我们的WEB服务器是支持多线程的.也就是说可以同时让多人一起访问. 这也是我在php(做为现在的主流开发语言)中实现多线程的基础.

假设我们现在运行的是a.php(做为现在的主流开发语言)这个文件. 但是我在程序中又请求WEB服务器运行另一个b.php(做为现在的主流开发语言)那么这两个文件将是同时执行的.


1. 利用LINUX操作系统
<?php
for ($i=0;$i<10;$i++) {
  echo $i;
  sleep(5);
}
?>
上面存成test.php, 然后写一段SHELL代码

#!/bin/bash
for i in 1 2 3 4 5 6 7 8 9 10
do
php -q test.php &
done

2. 利用fork子进程(其实同样是利用LINUX操作系统)

<?php
declare(ticks=1);
$bWaitFlag = FALSE; /// 是否等待进程结束
$intNum = 10;      /// 进程总数
$pids = array();    /// 进程PID数组
echo ("Startn");
for($i = 0; $i < $intNum; $i++) {
 $pids[$i] = pcntl_fork();/// 产生子进程,而且从当前行之下开试运行代码,而且不继承父进程的数据信息
 if(!$pids[$i]) {
  // 子进程进程代码段_Start
  $str="";
  sleep(5+$i);
  for ($j=0;$j<$i;$j++) {$str.="*";}
  echo "$i -> " . time() . " $str n";
  exit();
  // 子进程进程代码段_End
 }
}
if ($bWaitFlag)
{
 for($i = 0; $i < $intNum; $i++) {
  pcntl_waitpid($pids[$i], $status, WUNTRACED);
  echo "wait $i -> " . time() . "n";
 }
}
echo ("Endn");
?>

 

3. 利用WEB SERVER, PHP不支持多线程, APACHE可是支持的,  假设我们现在运行的是a.php这个文档. 但是我在程式中又请求WEB服务器运行另一个b.php那么这两个文档将是同时执行的.
<?php
function runThread()()
{
 $fp = fsockopen('localhost', 80, $errno, $errmsg);
 fputs($fp, "GET /a.php?act=brnrn");
 fclose($fp);
}
function a()
{
 $fp = fopen('result_a.log', 'w');
 fputs($fp, 'Set in ' . Date('h:i:s', time()) . (double)microtime() . "rn");
 fclose($fp);
}
function b()
{
 $fp = fopen('result_b.log', 'w');
 fputs($fp, 'Set in ' . Date('h:i:s', time()) . (double)microtime() . "rn");
 fclose($fp);
}
if(!isset($_GET['act'])) $_GET['act'] = 'a';
if($_GET['act'] == 'a')
{
 runThread()();
 a();
}
else if($_GET['act'] == 'b') b();
?>

当然啦,也可以把需要多线程处理的部分交给JAVA去处理, 然后在PHP里调用, 哈哈.

<?php
system('java multiThread().java');
?>

进程和线程的区别  http://www.cnblogs.com/lmule/archive/2010/08/18/1802774.html

 

 

十、php如何管理内存?

PHP的内存管理    http://www.nowamagic.net/librarys/veda/detail/1440

PHP原理之内存管理中难懂的几个点   http://www.laruence.com/2011/11/09/2277.html

深入理解PHP内存管理之谁动了我的内存  http://www.laruence.com/2011/03/04/1894.html

深入理解PHP内存管理之一个低概率Core的分析  http://www.laruence.com/2011/01/27/1854.html

深入探讨PHP中的内存管理问题    http://www.jb51.net/article/28166.htm

 

十、php获取当前文件所在的目录(getcwd和dirname(__FILE__)的区别)

通过dirname(__FILE__)获得当前文件所在的目录.

 <?php
/**
__FILE__ ,
getcwd(),
$_SERVER["REQUEST_URI"],
$_SERVER["SCRIPT_NAME"],
$_SERVER["PHP_SELF"],
$_SERVER["SCRIPT_FILENAME"],

来观察一下这些变量或函数的异同.
假设有一个请求地址为: http://localhost:8080/test.php/age=20
而test.php 的完整路径是: D:/server/www/example/test.php
1) getcwd()
将得到浏览器请求的页面文件所在的目录. 即test.php 文件所在的目录: D:/server/www/example/ ,
如果在test.php 执行了 require 或 include 语句, 比如 inculde(”test_dir/test2.php”),

那么在 test2.php 里 getcwd()函数 返回的也将是 test.php 所在的目录.

与$_SERVER['DOCUMENT_ROOT']的值相同,只是路径分隔符不同,getcwd()为\,$_SERVER['DOCUMENT_ROOT']为/。

2) __FILE__
一个魔术变量, 用它将得到 __FILE__ 变量所在文件的完整路径,
比如: test.php 里 __FILE__ 将得到 D:/server/www/example/test.php ,

test_dir/test2.php 里的 __FILE__ 将得到 D:/server/www/example/test_dir/test2.php


与$_SERVER['SCRIPT_FILENAME']返回的值相同,只是路径分隔符不同,__FILE__返回的路径分隔符是\,$_SERVER['SCRIPT_FILENAME']返回的值的路径分隔符是/


3) $_SERVER["SCRIPT_FILENAME"]
将得到浏览器请求的页面文件的完整路径.
test.php 和 test_dir/test2.php 里用 $_SERVER["SCRIPT_NAME"] 都将得到 D:/server/www/example/test.php.

4) $_SERVER["SCRIPT_NAME"]
将得到浏览器请求的页面文件的文件名,注意: 与 $_SERVER["SCRIPT_NAME"] 不同, 此变量只得到文件名而不包含路径,
在test.php 与 test_dir/test2.php 用$_SERVER["SCRIPT_NAME"] 得到的都将是 test.php.
当然, 在test.php 与 test_dir/test2.php 执行 basename($_SERVER["SCRIPT_FILENAME"]) 与 $_SERVER["SCRIPT_NAME"] 相同.
执行 在test.php 与 test_dir/test2.php 执行 realpath(”test.php”) 得到的结果与 $_SERVER["SCRIPT_FILENAME"] 相同.

5) $_SERVER["PHP_SELF"]
将得到浏览器请求页面的文件名, 并剥掉问号 ? 后的内容, 注意:不包含路径,
比如在客户端里请求 http://localhost:8080/test.php?age=20&name=Tom,
那么test.php 和 test_dir/test2.php 的 $_SERVER["PHP_SELF"] 都将得到 “test.php”。“age=20&name=Tom”被剥掉。
而如果客户端里请求 http://localhost:8080/test.php/age=20&name=Tom,

那么test.php 和 test_dir/test2.php 的 $_SERVER["PHP_SELF"] 都将得到 “test.php/age=20&name=Tom”。

 

$_SERVER['PHP_SELFT']与$_SERVER['SCRIPT_NAME']和$_SERVER['REQUEST_URI']和$_SERVER['QUERY_STRING']的区别:
http://localhost:60/phptour/test/test7.php/a=b
$_SERVER['PHP_SELF']将得到:/phptour/test/test7.php/a=b
$_SERVER['SCRIPT_NAME']将得到:/phptour/test/test7.php
$_SERVER['REQUEST_URI']将得到:/phptour/test/test7.php/a=b
$_SERVER['QUERY_STRING']将得到:''

http://localhost:60/phptour/test/test7.php?a=b
$_SERVER['PHP_SELF']与$_SERVER['SCRIPT_NAME']都将得到:/phptour/test/test7.php
$_SERVER['REQUEST_URI']将得到:/phptour/test/test7.php?a=b
$_SERVER['QUERY_STRING']将得到:a=b
总结:$_SERVER['PHP_SELF']会返回/phptour/test7.php/a=b,会返回文件名/后面的内容
            $_SERVER['SCRIPT_NAME']只会返回/phptour/test.php,不会返回文件名后面的/后面的内容
 

6) $_SERVER["REQUEST_URI"]
将得到浏览器请求页面的文件名, 以及文件名之后的所有内容(注意: 井号 # 之后的内容将被略去),
比如在客户端里请求 http://localhost:8080/test.php?age=20&name=Tom,
那么test.php 和 test_dir/test2.php 的 $_SERVER["REUEST_URI"] 都将得到 “test.php”。“age=20&name=Tom”被剥掉。
而如果客户端里请求 http://localhost:8080/test.php/age=20&name=Tom,
那么test.php 和 test_dir/test2.php 的 $_SERVER["REQUEST_URI"] 都将得到 “test.php/age=20&name=Tom”。
*/

7) $_SERVER["QUERY_STRING"]
将得到查询的字符串(?后面的字符串)

 

//test.php:
echo“test1.php variables<br/>”;
echo“getcwd:“,getcwd(),“<br/>”;
echo“__FILE__:“,__FILE__,“<br/>”;
echo“REQUEST_URI:“,$_SERVER["REQUEST_URI"],“<br/>”;
echo“SCRIPT_NAME:“,$_SERVER["SCRIPT_NAME"],“<br/>”;
echo“PHP_SELF:“,$_SERVER["PHP_SELF"],“<br/>”;
echo“SCRIPT_FILENAME “,$_SERVER["SCRIPT_FILENAME"],“<br/>”;

//把 test2.php 包含进来, 在 test2.php 里输出上面的变量,看有什么不同:
include_once(”test2/test2.php”);

?>

总结:$_SERVER[]返回值中的路径分隔符都是/斜线,__FILE__,getcwd(),返回值的路径分隔符为\反斜线。

 

 十一、自动加载函数__autoload() 和spl_autoload

 php的autoload大致可以使用两种方法:__autoload和spl方法。这两种方法又各有不同的几种使用方法

__autoload的使用方法1:
最经常使用的就是这种方法,根据类名,找出类文件,然后require_one

复制代码 代码如下:

function __autoload($class_name) {
$path = str_replace('_', '/', $class_name);
require_once $path . '.php';
}
// 这里会自动加载Http/File/Interface.php 文件
$a = new Http_File_Interface();


这种方法的好处就是简单易使用。当然也有缺点,缺点就是将类名和文件路径强制做了约定,当修改文件结构的时候,就势必要修改类名。

__autoload的使用方法2(直接映射法)

复制代码 代码如下:

$map = array(
'Http_File_Interface' => 'C:/PHP/HTTP/FILE/Interface.php'
);
function __autoload($class_name) {
if (isset($map[$class_name])) {
require_once $map[$class_name];
}
}
// 这里会自动加载C:/PHP/HTTP/FILE/Interface.php 文件
$a = new Http_File_Interface();


这种方法的好处就是类名和文件路径只是用一个映射来维护,所以当文件结构改变的时候,不需要修改类名,只需要将映射中对应的项修改就好了。

这种方法相较于前面的方法缺点是当文件多了的时候这个映射维护起来非常麻烦,或许这时候你就会考虑使用json或者单独一个文件来进行维护了。或许你会想到使用一个框架来维护或者建立这么一个映射。

spl_autoload

__autoload的最大缺陷是无法有多个autoload方法

好了, 想下下面的这个情景,你的项目引用了别人的一个项目,你的项目中有一个__autoload,别人的项目也有一个__autoload,这样两个__autoload就冲突了。解决的办法就是修改__autoload成为一个,这无疑是非常繁琐的。

因此我们急需使用一个autoload调用堆栈,这样spl的autoload系列函数就出现了。你可以使用spl_autoload_register注册多个自定义的autoload函数

如果你的PHP版本大于5.1的话,你就可以使用spl_autoload

 

 十二、 php中time函数的返回值是?不同时区,同一时刻返回值是否相同?是否还有其它方法获得与time相同的值?

time() 函数返回当前时间的 Unix 时间戳。即自从 Unix 纪元(格林威治时间 1970 年 1 月 1 日 00:00:00)到当前时间的秒数
Unix时间戳(英文为Unix epoch, Unix time, POSIX time 或 Unix timestamp)
是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。
所以time()是不考虑时区的

格林尼治标准时间(GMT):格林尼治标准时间(GMT,旧译“格林威治平均时间”或“格林威治标准时间”)是指位于 伦敦郊区的皇家格林尼治天文台的标准时间,
因为本初子午线被定义在通过那里的经线。理论上来说,格林尼治标准时间的正午是指当太阳横穿格林尼治子午线时 (也就是在格林尼治上空最高点时)的时间。
由于地球在它的椭圆轨道里的运动速度不均匀,这个时刻可能和实际的太阳时相差16分钟。地球每天的自转是有些不 规则的,而且正在缓慢减速。
所以,格林尼治时间已经不再被作为标准时间使用。
因为php是一门运行在服务器上的语言,所以,如果你在你自己的机器上进行测试的话,time()函数将直接读取你机器的时候,
换算成秒数后,再与1970.1.1 00:00:00作差,得出结果。所以,无论你的时区怎样设置,只要你本地机器时间没有变化,
time()函数返回的结果就不会有变化。在PHP5.1以后,你已经不需要使用time()函数了,直接读取$_SERVER['REQUEST_TIME']就可以获取结果。
<?php   echo time(); ?>
一个放在中国, 执行. 一个和在美国,执行.为什么返回的值相差60秒? 也不多, 就100以内.
原因:PHP5要设置时区,你说的问题很简单,服务器时间不准

1》通过getdate()函数获得的数组中键名为0的值和time()值相同。

2》通过gettimeofday()获取键名为sec的值与time()值相同;

3》通过分解microtime()得到的值也可以获得和time()一样的结果。


十三、dl函数的用途,什么情况下不能使用?如何获得当前进程id?如何获得当前文件include文件列表?当php做为命令行运行时容易超时退出,如何延长运行时间?

官方解释:在php脚本里动态加载php模块,执行结果返回true或者false,默认加载extension_dir目录里的扩展(可指定路径),当 PHP 运行在 安全模式 时,(强制)不能使用此函数。

 <?php 
// Example loading an extension based on OS
if (!extension_loaded('sqlite')) {
    if (
strtoupper(substr(PHP_OS03)) === 'WIN') {
        
dl('php_sqlite.dll');
    } else {
        
dl('sqlite.so');
    }
}
// Or, the PHP_SHLIB_SUFFIX constant is available as of PHP 4.3.0
if (!extension_loaded('sqlite')) {
    
$prefix = (PHP_SHLIB_SUFFIX === 'dll') ? 'php_' '';
    
dl($prefix 'sqlite.' PHP_SHLIB_SUFFIX);
}
?>
所谓的隐患就是,php默认开始此函数,并且关闭安全模式,那么用户(攻击者)就可以上传自己编写的恶意模块,并启用他,或者启用php自带但是没被删除只是简单禁用而又有安全隐患的模块。
关闭的方法是:
1,修改php.ini里的enable_dl = On为Off
2,开启安全模式(影响效率,但是安全)
3,加入php.ini的disable_functions里,也可以把其它认为不安全的函数加入,比如 exec,passthru,shell_exec,system,proc_open,popen, curl_exec,curl_multi_exec,parse_ini_file,show_source

dl()动态加载php扩展。安全模式下该函数不可以用。通过getmypid()获得当前进程id。
通过get_included_files()函数获得当前文件include文件列表。php在命令行下执行时,可以通过设置max_execution_time的值来改变运行时间长短。

十四、mysql和mysqli,pdo的区别?mysql_connect和mysql_pconnect的区别?

参考:php中关于mysqli和mysql区别的一些知识点分析 http://www.jb51.net/article/28103.htm

mysql,mysqli和PDO的区别   http://blog.csdn.net/breeze_life/article/details/8964024

 

mysql_connect 与 mysql_pconnect区别 

建立一个pconnect的连接。然后你去mysql下show processlist,看看,然后再建立几个,再去mysql下show processlist。你会发现有很多死连接处于sleep状态。 当这种状态的数量超过了mysql设置的最大连接数,mysql除了root就谁也连不上了。因为mysql总是会为root留一个位置。 这种长连接只有到达my.cnf里面设置的超时时间后才会自动断开,默认好像是8天吧,忘记了。然后你的mysql error日志中会记录一个warnning,翻译过来就是胎死腹中的连接。 所以说实际开发中,如果你的应用属于多用户的,一定不要使用这种连接。 除非是那种单人应用的系统,任何时候都只有一个人连接,那这种长连接方式效率会比短连接更合适。

参考:http://blog.csdn.net/wjc19911118/article/details/7901064

http://hi.baidu.com/shashadu/item/cabf6e790a6a19346cc37c7e

 

十五:如何得到一个字符串中哪个字符出现的次数最多

 

$str=”asdfgfdas323344##$\$fdsdfg*$**$*$**$$443563536254fas”;//任意长度字符串
 
//解法一(最快速的解法,但是基本功要扎实)
$arr=str_split($str);
$arr=array_count_values($arr);
arsort($arr);
print_r($arr);
 
//解法二(对逻辑能力有一定要求)
$arr=str_split($str);
$con=array();
foreach ($arr as $v){
if (!@$con[$v]){
@$con[$v]=1;
}else{
@$con[$v]++;
}
}
arsort($con);
print_r($con);
//解法三
$arr=str_split($str);
$unique=array_unique($arr);
foreach ($unique as $a){
$arr2[$a]=substr_count($str, $a);
}
arsort($arr2);
print_r($arr2);

 十六:什么是php引用函数

参考:http://sumsung753.blog.163.com/blog/static/146364501201102684942358/

 

 十七:mysql_close($conn) 与 unset($conn) 区别

$conn 连接是一个对某个资源的引用

  • mysql_close($connection) closes the non-persistent connection to the MySQL server that's associated with $connection. If $connection isn't specified, the last opened link is used.

    -this function is deprecated , so please use PDO or mysqli.

  • unset($connection) clears the pointer to the result on php's side, but does not do anything to the result it points to.

 unset($connection) will just make the var $connection equal to NULL. If you didn't do the unset, then the var $connection would still point to a MySQL link identifier, which would be invalid after the mysql_close(). It's a little pedantic; whether you unset or not, the $connection var will not be usable after the mysql_close().

$conn = mysql_connect('localhost', 'root', 'root') or die('connect error:' . mysql_error());
mysql_query("SET NAMES utf8");
mysql_select_db('users', $conn);
var_dump($conn);
echo '<br>';
mysql_close($conn);
var_dump($conn);
exit;

 返回:

resource(3, mysql link)
resource(3, Unknown)
mysql_close只是关闭了拦截,但是$conn这个变量还存在,如果想关闭后销毁变量,可以再mysql_close($conn)后加:unset($conn);
$conn = mysql_connect('localhost', 'root', 'root') or die('connect error:' . mysql_error());
mysql_query("SET NAMES utf8");
mysql_select_db('19youxi', $conn);
unset($conn);
$res = mysql_query("SELECT * FROM users");
var_dump($res);
exit;

 返回:resource(4, mysql result)

可见:虽然在mysql_query之前unset($conn)了,但是并没有关闭数据库连接,unset 仅仅是把对应的$conn变量给销毁了

 

十八:什么是php的延迟绑定?

 

十九:写出一个正则表达式,过虑网页上的所有JS/VBS脚本(即把标记及其内容都去掉)

答:/<[^>].*?>.*?<\/>/si

 

20:数组函数 arsort 的作用是(6);语句 error_reporting(2047)的作用是(7)。

:(6)对数组进行逆向排序并保持索引关系  (7)All errors and warnings

21.语句 include 和 require 都能把另外一个文件包含到当前文件中,它们的区别是(12);为了避免多次包含同一文件,可以用语句(13)来代替它们。
答:(12) 发生异常时include产生警告require产生致命错误  (13) require_once()/include_once()

22.一个函数的参数不能是对变量的引用,除非在php.ini中把(15)设为on.

答:allow_call_time_pass_reference

23.在PHP中,heredoc是一种特殊的字符串,它的结束标志必须(18)。
答:结束标识符所在的行不能包含任何其它字符除";"

24.echo(),print(),print_r()的区别

答:

echo 和print不是一个函数,是一个语言结构

print(string $arg), 只有一个参数

echo $arg1, $arg2  可以输出多个参数

 

 

echo和print只能打印出string,不能打印出结构

 

print_r能打印出结构,用于输出数组对象

 

 

25.使用五种以上方式获取一个文件的扩展名

要求:dir/upload.image.jpg,找出 .jpg 或者 jpg ,

答:使用五种以上方式获取一个文件的扩展名

1)
get_ext1($file_name)
{
    return strrchr($file_name, '.');
}

2)
get_ext2($file_name)
{
    return substr($file_name, strrpos($file_name, '.'));
}

3)
get_ext3($file_name)
{

    return array_pop(explode('.', $file_name));

}

4)
get_ext4($file_name)
{
    $p = pathinfo($file_name);
    return $p['extension'];
}


5)
get_ext5($file_name)

{
    return strrev(substr(strrev($file_name), 0, strpos(strrev($file_name), '.')));
}

 

26.如何修改SESSION的生存时间

答:其实 Session 还提供了一个函数 session_set_cookie_params(); 来设置 Session 的生存期的,该函数必须在 session_start() 函数调用之前调用:

<?php

// 保存一天

$lifeTime = 24 * 3600;

session_set_cookie_params($lifeTime);

session_start();

$_SESSION["admin"] = true;

?>

 

27. 请写一个函数,实现以下功能: 字符串“open_door” 转换成 “OpenDoor”、”make_by_id” 转换成 ”MakeById”。

$arr1=explode('_',$str);

 

$str = implode(' ',$arr1);
return ucwords($str);
 

28.表中有A B C三列,SQL语句实现:当A列大于B列时选择A列否则选择B列,当B列大于C列时选择B列否则选择C列。

答:select case when A>B then A else B end,
       case when B>C then B else C end
From test

 

 

30.请简述项目中优化sql语句执行效率的方法,从哪些方面,sql语句性能如何分析?

答:(1)选择最有效率的表名顺序

2WHERE子句中的连接顺序

3SELECT子句中避免使用‘*’

4)用Where子句替换HAVING子句


5)通过内部函数提高SQL效率

6)避免在索引列上使用计算。

7)提高GROUP BY 语句的效率, 可以通过将不需要的记录在GROUP BY 之前过滤掉。

 

 

31.如何通过javascript判断一个窗口是否已经被屏蔽

答:获取open()的返回值,如果是null,就是屏蔽了

 

 

32.对于大流量的网站,您采用什么样的方法来解决访问量问题

答:首先,确认服务器硬件是否足够支持当前的流量

其次,优化数据库访问。

第三,禁止外部的盗链。

第四,控制大文件的下载。

第五,使用不同主机分流主要流量

第六,使用流量分析统计软件

 

33.写一个函数,尽可能高效的,从一个标准 url 里取出文件的扩展名 例如: http://www.sina.com.cn/abc/de/fg.php?id=1 需要取出 php 或 .php

$url = 'http://www.sina.com.cn/abc/de/fg.php?id=1';
$arr = parse_url($url);
$path = $arr['path'];
$pathinfo = pathinfo($path);
$ext = $path['extension'];
 
34.输出一个文件先对于另一个文件的相对路径
$a = '/a/b/c/d/e.php';
$b = '/a/b/12/34/c.php';
function getRelativePath($path1, $path2) {
	$arr_path1 = explode('/', $path1);
	$arr_path2 = explode('/', $path2);
	foreach($arr_path1 as $key => $val) {
		if ($arr_path1[$key] == $arr_path2[$key]) {
			unset($arr_path1[$key], $arr_path2[$key]);
		}
	}
	return str_repeat('../', count($arr_path1) - 1) . implode('/', $arr_path2);
}
$reltive_path = getRelativePath($a, $b);
echo $reltive_path;

 

35. 简单说明PHP的垃圾收集机制是怎样的?
对变量有个引用计数,计数到0时变量被销毁。

 

36.使对象可以像数组一样进行foreach循环,要求属性必须是私有

php5里面已经有了iterator接口,只要实现该接口,即可以实现对象私有属性被foreach遍历

 
class Sample implements iterator{

private $var = array(1,2,3,4,5);

public function __construct(){}

public function rewind(){ reset($this->var);}

public function current(){return current($this->var);}

public function key(){return key($this->var);}

public function next(){return next($this->var);}

public function valid(){return ($this->current()!==false);}

}

$s = new Sample();

foreach($s as $k=>$v){ echo $k.'='.$v.'<br/>';}

37、__destruct /unset 
__destruct() 析构函数,是在垃圾对象被回收时执行。 
unset 销毁的是指向对象的变量,而不是这个对象。

 

38、 Session 与 GC 
由于PHP的工作机制,它并没有一个daemon线程来定期的扫描Session信息并判断其是否失效,当一个有效的请求发生时,PHP 会根据全局变量 session.gc_probability和session.gc_divisor的值,来决定是否启用一个GC, 在默认情况下,session.gc_probability=1, session.gc_divisor =100也就是说有1%的可能性启动GC(也就是说100个请求中只有一个gc会伴随100个中的某个请求而启动). 
GC的工作就是扫描所有的Session信息,用当前时间减去session最后修改的时间,同session.gc_maxlifetime参数进行比较,如果生存时间超过gc_maxlifetime(默认24分钟),就将该session删除。 
但是,如果你Web服务器有多个站点,多个站点时,GC处理session可能会出现意想不到的结果,原因就是:GC在工作时,并不会区分不同站点的session. 

那么这个时候怎么解决呢? 
1. 修改session.save_path,或使用session_save_path()让每个站点的session保存到一个专用目录, 
2. 提供GC的启动率,自然,GC的启动率提高,系统的性能也会相应减低,不推荐。 
3. 在代码中判断当前session的生存时间,利用session_destroy()删除.

 

39. 012/4 输出多少?
输出2.5;  012为8进制数据,转为10进制对应为 10
 
40.实现php排序算法及指出复杂度:
 <?php
// 冒泡排序
function BubbleSort($arr) {
    // 获得数组总长度
    $num = count($arr);
    // 正向遍历数组
    for ($i = 1; $i < $num; $i++) {
        // 反向遍历
        for ($j = $num - 1; $j >= $i ; $j--) {
            // 相邻两个数比较
            if ($arr[$j] < $arr[$j-1]) {
                // 暂存较小的数
                $iTemp = $arr[$j-1];
                // 把较大的放前面
                $arr[$j-1] = $arr[$j];
                // 较小的放后面
                $arr[$j] = $iTemp;
            }
        }
    }
    return $arr;
}

// 交换法排序
function ExchangeSort($arr){
    $num = count($arr);
    // 遍历数组
    for ($i = 0;$i < $num - 1; $i++) {
        // 获得当前索引的下一个索引
        for ($j = $i + 1; $j < $num; $j++) {
            // 比较相邻两个的值大小
            if ($arr[$j] < $arr[$i]) {
                // 暂存较小的数
                $iTemp = $arr[$i];
                // 把较大的放前面
                $arr[$i] = $arr[$j];
                // 较小的放后面
                $arr[$j] = $iTemp;
            }
        }
    }
    return $arr;
}

// 选择法排序
function SelectSort($arr) {
    // 获得数组总长度
    $num = count($arr);
    // 遍历数组
    for ($i = 0;$i < $num-1; $i++) {
        // 暂存当前值
        $iTemp = $arr[$i];
        // 暂存当前位置
        $iPos = $i;
        // 遍历当前位置以后的数据
        for ($j = $i + 1;$j < $num; $j++){
            // 如果有小于当前值的
            if ($arr[$j] < $iTemp) {
                // 暂存最小值
                $iTemp = $arr[$j];
                // 暂存位置
                $iPos = $j;
            }
        }
        // 把当前值放到算好的位置
        $arr[$iPos] = $arr[$i];
        // 把当前值换成算好的值
        $arr[$i] = $iTemp;
    }
    return $arr;
}

// 插入法排序
function InsertSort($arr){
    $num = count($arr);
    // 遍历数组
    for ($i = 1;$i < $num; $i++) {
        // 获得当前值
        $iTemp = $arr[$i];
        // 获得当前值的前一个位置
        $iPos = $i - 1;
        // 如果当前值小于前一个值切未到数组开始位置
        while (($iPos >= 0) && ($iTemp < $arr[$iPos])) {
            // 把前一个的值往后放一位
            $arr[$iPos + 1] = $arr[$iPos];
            // 位置递减
            $iPos--;
        }
        $arr[$iPos+1] = $iTemp;
    }
    return $arr;
}

// 快速排序
function QuickSort($arr){
    $num = count($arr);
    $l = $r = 0;
    // 从索引的第二个开始遍历数组
    for ($i = 1;$i < $num; $i++) {
        // 如果值小于索引1
        if ($arr[$i] < $arr[0]) {
            // 装入左索引数组(小于索引1的数据)
            $left[] = $arr[$i];
            $l++;
        } else {
            // 否则装入右索引中(大于索引1的数据)
            $right[] = $arr[$i];
            $r++; //
        }       
    }
    // 如果左索引有值 则对左索引排序
    if($l > 1) {
        $left = QuickSort($left);
    }
    // 排序后的数组
    $new_arr = $left;
    // 将当前数组第一个放到最后
    $new_arr[] = $arr[0];
    // 如果又索引有值 则对右索引排序
    if ($r > 1) {
        $right = QuickSort($right);
    }
    // 根据右索引的长度再次增加数据
    for($i = 0;$i < $r; $i++) {
        $new_arr[] = $right[$i];
    }
    return $new_arr;
}
?>

 

41.下面的程序错在哪里?
class Box {
	protected $num = 0;
	public function __construct() {
		$this->num = 2;
	}
	
	public static function getNum() {
		return $this->num;
	}
}

$obj = new Box();
echo Box::getNum();

因为方法getNum被申明为静态的,故他的方法体里只能有静态的属性(用self:: 调用也不可以,因为$num是实例属性,如果没有
创建实例,则不能调用)

应该把发放声明中的static去掉

 

42、utf8 和 UTF-8 有什么区别

“UTF-8”是标准写法,在Windows下边英文不区分大小写,所以也可以写成“utf-8”。“UTF-8”也可以把中间的“-”省略,写成“UTF8”。一般程序都能识别,但也有例外(如下文),为了严格一点,最好用标准的大写“UTF-8”。

在MySQL数据库中只能使用“utf8”

  在MySQL的命令模式中只能使用“utf8”,不能使用“utf-8”,也就是说在PHP程序中只能使用“set names utf8(不加小横杠)”,如果你加了“-”此行命令将不会生效,但是在PHP中header时却要加上“-”,因为IE不认识没杠的“utf8”,原因 见下文。

在IE浏览器中只能使用“utf-8”

  IE中如果使用了“utf8”,页面可能会 空白 或 显示为乱码。

  但是在其它浏览器却是正常的,原因是因为:其它浏览器默认使用的是UTF-8的编码,如果无法识别页面的编码就会用默认的UTF-8来解码,但 是IE的默认编码是GB2312,所以默认的话就。。。。。(其它浏览器指“FireFox”、“Chrome”、“Opera”)


总结  

  【只有在MySQL中可以使用“utf-8”的别名“utf8”,但是在其他地方一律使用大写“UTF-8”。】

  具体为:

    在命令“mysql_query(set names utf8)”外一律用大写“UTF-8”。

posted @ 2013-10-21 12:25  一束光  阅读(759)  评论(0编辑  收藏  举报

友情链接

CFC4N