【PHP】对于PHP某些代码的总结

本文深入探讨PHP中的变量解析、字符串处理、数组操作等核心概念,同时涵盖了错误处理、JSON编码及安全实践等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、PHP的单引号、双引号、变量解析。

1.1、在php中单引号内的变量名是不会被解析的,双引号内的变量名是会被解析的。

如下所示:

$test = 'return';
$test1 = "$test";
$test2 = '$test';
$test3 = "{$test}";
var_dump($test1, $test2, $test3);
输出是:

string(6) "return"
string(5) "$test"
string(6) "return"

1.2、sql语句中的单引号,双引号的使用。

sql语句最外层必须使用双引号,这样在双引号内部的变量名才会被解析。而且sql语句中where后面的值要用单引号括起来(int 除外)。

$sql = "SELECT `worker_pwd`, `worker_salt`,`worker_name` FROM `worker_info` WHERE `worker_id`='{$worker_id}'";
拿上面的sql语句举例,双引号内部的$worker_id 会被解析,并在最外面用 单引号包起来了。

如果worker_id这个字段在数据库中是int类型,sql语句中的值使用的是字符串或者int,都会成立而且速度一致。

如果worker_id这个字段在数据库中是(数字型的)string类型,而且存在某些(数字型)的string非常长,也就是超大数字,这种情况下如果sql语句还是使用值为int。

可能会得不到想要的结果。这个其实有很多例子。


案例1:

SELECT `uid` FROM `t_user` WHERE `phone`=13812345678 

会导致全表扫描,而不能命中phone索引这个坑大家没踩过么?

phonevarchar类型,SQL语句带入的是整形,故不会命中索引,加个引号就好了

SELECT `uid` FROM `t_user` WHERE `phone`='13812345678'


所以,综上所述,sql语句的值最好都用单引号括起来的值。

案例2:曾经同事遇到以下问题,他的SQL语句是,如下所示。

SELECT `content`,`report` FROM `t_send_20180211` WHERE `report`=0 AND `cid`=48

该语句可以将report='UNDELIV'的筛选出来,这个字段的定义是char。

为啥会这样。MySql底层是C++写的,当它与int类型进行比较时,会将存储的char类型的数据尝试着

强制转换为int,比如上面的'UNDELIV'强制转换成int的过程中,变成了0,所以sql语句将他筛选出来了。



1.3、关于变量名外面用{}包含。

为了区分以下情况。

比如$test = "nihao"; “{$test}test”   和 “$testtest”,前者可以解析,后者没法解析。

所以,建议如果要在字符串中解析变量时,统一加上{}。

下面还给出一个例子,为啥要加上{}括起来。

throw new RuntimeException("$item['_start']-$item['_end']不存在,请重试."); // error
throw new RuntimeException("{$item['_start']}-{$item['_end']}不存在,请重试."); // ok
throw new RuntimeException("$item[0]-$item[1]不存在,请重试.");// ok
在上面抛出异常的3行代码中,第1行,不加{} 就不行。必须要加{},当array,key = string时,如果不加,无法解析。

1.4、解析字符串中的代码,得到想要的数据。

比如:

$test = "array('test' => array('test1', 'test2'))";
var_dump($test);
其实,本来是想得到字符串所表达的数组,结果,没有得到。可以用如下办法。

$test = "return array('test' => array('test1', 'test2'));";
var_dump(eval($test));
eval函数把 字符串当做语言的正常逻辑(不能有语法错误)执行,得到想要的结果。这种方式在很多弱类型语言都有,

比如js(js不推荐这样使用,效率低)、lua。


1.5、\n等这些需要转义的字符,只有在双引号里面才会被正常转义,比如下面语句。

echo "hello \n world";
echo 'hello \n world';
前者有换行输出,后者会原封不动输出\n

1.6、在不是特别需要使用双引号的情况下,建议优先使用单引号,因为 双引号,php底层的引擎要先进行匹配和置换处理。相对来讲会比较耗时。

什么叫必须使用双引号的场景呢,就是 sql语句、需要解析字符串中的变量的情况等。


1.7、php中可以使用可变变量名(代码中动态的字符串)的变量。

比如,我们在C++\python中,经常遇到这样的情况,就是变量名需要是可变的,有些变量名是动态生成的,有的时候,就不知道怎么弄了。

有的时候,可能会借助 数据、字典,来实现。但是在php里可以直接用可变变量名的变量。说起来非常绕口,现在直接列举如下:

$testArr = array("nihao1","nihao2","nihao3","nihao4");
foreach( $testArr as $value ) {
    ${$value} = $value." i come from hust(wuhan)";
}
echo $nihao1;

在最后一行代码中,就可以直接使用变量$nihao1了,我遇到的很多语言,目前只有php可以这样。

当你阅读php代码时,发现某个变量值压根就没有地方定义或者给它赋值,你就会感到奇怪,这个值从哪里来的呢。这个时候,就要查看是不是哪个地方使用了

这个功能了。


2、php中判断值为空。(此处有坑)

2.1、isset()

当变量不存在时,返回false;

当变量存在但是为NULL时,返回false;

当变量存在且不为NULL,比如可以是0、空格,返回true.

2.2、empty()

当变量不存在时,返回true;

当变量存在,且是""、0、"0"、NULL、、FALSE、array()、var $var;时,返回true;

当变量存在,且不是上面几个值时返回false;

此处坑点在于0,‘0’。

2.3、defined()

判断一个常量是否定义了,用这个函数,且函数的参数为字符串。

define("SERVER_IP", "127.0.0.1");
if (defined("SERVER_IP")) {
	echo "有值";//这里会输出有值
}
注意函数里判断,用的是常量对应的字符串。定义常量时,也是用的字符串。

问题:

empty("               ");  这个返回啥呢。这个返回false。
2.4、对于空数组的 empty的判断。代码如下:

<?php
$test = array(array(), array());
if ( empty($test) ) {
    echo "空的1";// 没有输出
}
$test = array();
if ( empty($test) ) {
    echo "空的2";// 有输出
}
第一个数组,在意义上,肯定是空的,但是empty判断不是空的。。

所以,综合2.3、2.4来看,empty对于数组是否为空,是根据其长度来判断的。


3、php中字符串相关。(php5)

3.1、字符串大小的比较。

比较两个字符串最好是用strcasecmp()\strcmp() \strncasecmp()。因为会有坑。

比如:

$test = "20160729151825554734875";
if (strcasecmp($test, "20160801") > 0) {
    echo "大于";// 不会输出(恰好满足我们要的结果)
}

if ($test > "20160801") {
    echo ">>>";// 会输出
}
如果是python代码:
#coding=utf-8 
#!/usr/bin/env python
test = "20160729151825554734875";

if (test > "20160801"):
    print ">>>" #这里不会有输出



if("10012014021504410428"=="10012014021504410429") {
    echo "==="; // 会输出 ===
}
if("10012014021504410428"==="10012014021504410429") {
    echo "==="; // 带有类型的比较,肯定不会输出
}

也就是说,对于数字字符串时,简单的大于、小于、= 比较符号,不适用了,会将他们转成int后再进行比较。
所以,你想得到你想要的结果(字符串比较)还是用严格的内置函数比较好。

3.2、php\python中计算字符串的长度。这里有坑点。

这么说吧,直接用strlen计算中文字符串长度的时候,1个中文字符算成了3个长度,1个英文字符算成了1个长度,这个与通常的理解不一样。通常

的理解,中文是2个字节,英文是1个字节。所以,要将这些转换过来,所以,php中有了mb_strlen这个函数(计算绝对长度,所有不管中文、英文

都算1个长度)。但是这个函数,不一定被php.ini里加载了,所以需要判断,如果没有加载,就使用preg_match_all("/./u", $str, $ar)。

具体代码实现如下:

1、功能:在php中获得中英文混合字符串长度(绝对长度、或者是 英文1个字节 中文2个字节)
2、参数:$type = true 表示中文算 2 个字节长度,$type = false 表示中文算 1 个

static function abslength($str, $type=true) {
        if(!isset($str)){
            return 0;
        }
        $strLen = strlen($str);
        if(function_exists('mb_strlen')){
            $mbStrLen = mb_strlen($str,'utf-8');
        }
        else {
            preg_match_all("/./u", $str, $ar);
            $mbStrLen = count($ar[0]);
        }
        if ($type) {
            return ($mbStrLen+$strLen)/2;
        } else {
            return $mbStrLen;
        }
    }

3.3、字符串长度与mysql中的varchar定义的长度的对比。

(1)在mysql 5.0以上版本,varchar的最大字节是 65532字节(65535-3<3代表起始位、结束位>) ,这个是定死的最大上限,无论如何都不可以超过。

(2)如果,varchar(32),这么定义,在mysql5.0以上,最多只能存32个汉字、32个英文字符,而且这里不管汉字是

utf-8编码,还是gbk编码。至于,最终32个汉字在数据库中占用了多少内存空间(字节),很显然与编码有关。

(3)varchar最大上限是 65532字节,是不是代表可以存65532个汉字,显然不是,

对于utf-8,最大的汉字长度 = 21844 =65532/3,有些网上的资料说是 21845(具体你可以测试下)。

对于gbk,最大的汉字长度 = 32766 = 65532/2。

但是一般情况下,varchar定义都是在1000以下,如果超过了,你最好是改成TEXT。

(4)所以,对于数据库系统使用5.0以上的,当判断长度的时候,php里可以直接使用绝对长度来判断,不管是中文、英文都定义为1个字符长度。

4、php中的json相关。

主要有2个函数,比较重要,json_decode\json_encode,前者用于json字符串的解码,后者用于json字符的编码。

$json = '{"a":1,"b":2,"c":3,"d":4,"e":5}'; 
var_dump(json_decode($json)); 
var_dump(json_decode($json, true)); 

前者返回的是 object(stdClass)#1 (5),后者返回的是 array(5)。object\array,访问成员的方式是不一样的。

$json = '{"a":1,"b":2,"c":3,"d":4,"e":5}'; 
$obj = json_decode($json);
$_arr = json_decode($json, true); 
echo $obj->{"a"}, PHP_EOL;
echo $obj->a, PHP_EOL;
echo $_arr["a"], PHP_EOL;
以上的差别,一定要注意,建议,在代码中约定用$_arr = json_decode($json, true);


json_encode这个函数,就不用说了,就是将数组,转成json字符串。一般为了节省内存,或者带宽,会将存盘或者转发的数据都转成json格式字符串,

这样比较好点。


5、php中的数据越界的判断。

我们在写c++程序时,如果某个key在数组中是不存在的,但是你却在代码里访问了它。这样,肯定会报错。c++里肯定要对这种情况进行容错处理。

那在php中,我们怎么容错呢。php中有个函数叫array_key_exists,这个是可以,但是效率不够。

如果用 if (!$test["key"]) 来判断呢,也是不行,这样也会报警(在php里,报警与报错都是错误,只是错误的级别不一样)

最好是用if (isset($test['“key”]) 或者 if (!empty($test["key"])) 来判断。

我们来举一个例子,来很好的说明这个问题:

$sid = $_COOKIE['c_sid'];
if (empty($sid)) {
    // 自己生成sid
}
上面代码的本意是,去cookie中获取c_sid,如果获取到的是empty的,就通过{}中的代码,自己来生成。

这段代码的问题,就是有可能在$sid = $_COOKIE['c_sid'] 这了的时候,就报错,因为可能没有相应的key。所以,需要在这段代码的时候,就进行容错处理。

或者直接写成下面这样:

if ( empty($_COOKIE['c_sid']) ) {
    // 自己生成sid
}

6、php中的数组的合并。

数组合并有以下2种方法:array_merge\+,php对于"+"号,进行了重载。

6.1、

(1)当键名为 数字时:

对于 +,如果有相同的键名,谁在前,就选择谁,后面相同键名对应的值会被抛弃掉;

对于array_merge,如果有相同的键名,不会覆盖,重新生成数字索引;

(2)当键名为非数字时:

对于+,键名相同,与上一样,都是谁在前,就选择谁;

对于array_merge,如果有相同的键名,会覆盖,谁在后,选择谁(在这种情况下,如果不想被覆盖选择使用array_merge_recursive()

注意:

(1)如果传入array_merge中的数组是以整数(数字)为key,最后得到的结果,以key=0重新开始索引

(2)函数array_merge_recursive() 与array_merge不同是在处理两个或更多个数组元素有相同的键名的情况。array_merge_recursive() 

不会进行键名覆盖,而是将多个相同键名的值递归组成一个数组。

测试代码如下,当要测试数字key时,请将n去掉。

$testArr = array(
    "n2" => "你好",
    "n4" => "hellow"
    );
$testArr1 = array(
    "n6" => "哈哈",
    "n9" => "我不知为啥",
    "n4" => "爱情"
    );
$test = array_merge($testArr1, $testArr);
print_r($test);
$test = $testArr + $testArr1;
print_r($test);


7、php中的引用,跟php中的变量作用域有一定的关系。

<?php
$arr = array('apple','banana','cat','dog');
foreach($arr as $key=>$val) {
    //some code
}
echo $val;  //输出dog
echo $key;  //输出3

//下面对val进行赋值
$val = 'e';
print_r($arr);  //输出Array ( [0] => apple [1] => banana [2] => cat [3] => dog ) 

说明:在foreach循环之后,还有可输出$val,证明php中for循环中定义的临时变量在后面不会清除掉,只会在函数结束后,去清除内存。

而且,在下面对于$val,进行重新赋值,也不会改变原始的$arr 数组。


<?php
$arr = array('apple','banana','cat','dog');
foreach($arr as $key => &$val) {
    //some code
}
echo $val;  //输出dog
echo $key;  //输出3

//下面对val进行赋值
$val = 'e';
print_r($arr);  //输出Array ( [0] => apple [1] => banana [2] => cat [3] => e ) 
如果在foreach中使用引用,在下面的代码中,如果改变这个值,相应的$arr也会跟着改变。这点毋庸置疑。


这样,会带来一个问题,如果,我们在后续的代码中再次使用了$val,这样就很容易改变原来的$arr,其实这又不是我们的本意。

所以,正确的方法,每次在foreach中,使用了引用变量,都最好将其unset掉。在foreach代码后面,加上如下:

uset($val);  // 这样既可,相当于释放掉这个引用。

$award = array(
        	1 => array('typeCn' => '11111111111', 'chance' => 0),
        	2 => array('typeCn' => '22222222222', 'chance' => 0),
        	3 => array('typeCn' => '33333333333', 'chance' => 0),
        	4 => array('typeCn' => '44444444444', 'chance' => 0),
        	5 => array('typeCn' => '55555555555', 'chance' => 0),
        	6 => array('typeCn' => '66666666666', 'chance' => 0),
        	7 => array('typeCn' => '77777777777', 'chance' => 0),
        	8 => array('typeCn' => '88888888888', 'chance' => 0),
    	);
		$rows = array(
			array('nickname' => "TBN", 'award_type' => 6, 'typeCn' => "66666666666", 'ct' => "2017-11-02"),
			array('nickname' => "瑗瑗瑗瑗瑗", 'award_type' => 6, 'typeCn' => "66666666666", 'ct' => "2017-11-02"),
		);
		foreach ($rows as &$row){
            $row['ct'] = date('Y-m-d', strtotime($row['ct']));
        }
        // unset($row);
		for ($i=0;$i<5;$i++) {
            $award_type = array_rand($award);
            $len = rand(5, 12);
            $row = array(
                'nickname' => getRandomStr($len),
                'award_type' => $award_type,
                'typeCn' => $award[$award_type]['typeCn'],
                'ct' => date('Y-m-d'),
            );
            array_unshift($rows, $row);
        }
        print_r($rows);// 如果不加上面的unset($row),我们会发现将 上面 'nickname' => "TBN"的项给抹掉了
    
    	// 获取随机的验证码
    	function getRandomStr($length=6) {
        	try {
            	if ( $length > 32 ) {
                	throw new RuntimeException('随机字符串不能大于32长度', self::$IllegalParametersError);
            	}
            	$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
            	$str = '';
            	for ( $i = 0;$i < $length; $i++ ) {
                	$str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
            	}
            	return $str;
       		} catch (LogicException $e){
            	die($e->getMessage());
        	}
    	}


查看上面代码,如果在foreach循环后,没有使用unset,那么后面再向数组中添加数据时会影响数组原来的数据。


8、命令行执行PHP脚本时,怎么模拟成HTTP请求。

比如:php index.php 'ct=wxIf&ac=postOrderWxCheck&key=a**************************'。我们通过命令行执行上面的命令时,怎么

让index.php里的脚本逻辑,走的是类似于http请求的逻辑呢。可以在index.php中添加如下代码:

if(!empty($_SERVER['argv'][1]) && PHP_SAPI == 'cli'){
    parse_str($_SERVER['argv'][1], $_GET);
}
首先判断,执行的脚本有参数,且是命令行执行模式(PHP_SAPI = 'cli')的情况下,执行函数parse_str($_SERVER['argv'][1], $_GET)即可。

parse_str的作用就是将查询字符串格式化到后面的数组当中去。比如:name=Bill&age=60格式化到后面的数组就变成了:

array('name' => 'Bill', 'age' => 60);

其次,PHP_SAPI表示当前php的执行模式,php的执行模式有cli(命令行)、cgi、FastCgi等。

最后,$_SERVER['argv']表示命令行提供的参数,这个与很多语言类似。


9、PHP中一个非常好用的数组排序函数array_multisort。

<?php
$arr1 = array(
	array('name' => 'lg', 'age' => 28, 'address' => 'guanzhou'),
	array('name' => 'yjf', 'age' => 29, 'address' => 'shanghai'),
	array('name' => 'lc', 'age' => 24, 'address' => 'guanzhou'),
	array('name' => 'gzk', 'age' => 26, 'address' => 'guanzhou'),
	array('name' => 'lwt', 'age' => 27, 'address' => 'shenzhen'),
	array('name' => 'lj', 'age' => 28, 'address' => 'shanghai'),
);
$arr2 = array();
foreach ($arr1 as $key => $value) {
	$arr2[] = $value['age'];
}
array_multisort($arr2, SORT_ASC, SORT_NUMERIC, $arr1);
print_r($arr1);

比如,上面代码,我们要对$arr1,按照age(年龄)进行排序,如果单单使用sort来进行排序,这无法做到。

PHP里有个函数array_multisort,这个函数用来排序就非常好。

你可以将age字段单独取出来弄成一个数组$arr2,然后使用函数array_multisort($arr2, SORT_ASC, SORT_NUMERIC, $arr1); 这样在对$arr2进行排序的同时,也

排序了$arr1。而且这种排序是稳定的,不信你可以实验下。


而且,现在的排序一般情况下有多个维度。如果增加维度 address。

我们可以先以age来排序,完了之后,再以address,再来一次。

不管增加多少维度,复杂度都是M*logN(M表示维度的数目,N表示数组中元素个数)。。。我们假设PHP底层对于排序的实现的算法为logN。

其他与array_multisort相关的解读在 array_multisort解读


10、PHP格式化json字符串中的Unicode。

我们在打印log时,通常会遇到unicode编码后的汉字。这样打印出来的log无法查看那些汉字到底啥意思。

所以,我们需要对于这些Unicode编码的汉子进行重新编码。

下面代码,调用jsonFormat,可以对Unicode进行重新编码。再次打印出来,可以看到很好的效果。


<?php    
static function jsonFormatProtect(&$val){  
    if($val!==true && $val!==false && $val!==null){
    	$val = urlencode($val);
    }  
}  
private function jsonFormat($data, $indent=null) {
	// 对数组中每个元素递归进行urlencode操作,保护中文字符
	array_walk_recursive($data, 'Class::jsonFormatProtect');
	// json encode
	$data = json_encode($data);

	// 将urlencode的内容进行urldecode
	$data = urldecode($data);
	// 缩进处理
	$ret = '';
	$pos = 0;
	$length = strlen($data);
	$indent = isset($indent)? $indent : '    ';
	$newline = "\n";
	$prevchar = '';
	$outofquotes = true;

	for($i=0; $i<=$length; $i++) {
		$char = substr($data, $i, 1);

		if($char=='"' && $prevchar!='\\'){
			$outofquotes = !$outofquotes;  
        }elseif(($char=='}' || $char==']') && $outofquotes){
        	$ret .= $newline;
        	$pos --;
        	for($j=0; $j<$pos; $j++){
        		$ret .= $indent;
        	}
        }

        $ret .= $char;
        if(($char==',' || $char=='{' || $char=='[') && $outofquotes){
        	$ret .= $newline;
        	if($char=='{' || $char=='['){
        		$pos ++;
        	}
        	for($j=0; $j<$pos; $j++){
        		$ret .= $indent;
        	}
        }
        $prevchar = $char;
    }
    return $ret;  
}  




11、PHP代码热更新相关。
当我们更新PHP后端的代码后,此时重新再次请求接口,PHP后端的逻辑就会自动更新了。这个是怎么做到的呢。

我们现在的系统是nginx+fpm+php这样的运行模式,而且我们每次调用接口后,都exit(),没用停留在代码片段中。

所以,导致我们每次请求接口时,都重新require了文件。

其实,我们可以启用代码缓存,这样可以减轻服务器的负担,这个跟php版本相关、根本你使用的php框架底层的

设计相关。

PHP代码缓存相关的内容请参考:php-opcache运行时配置参数详解

下面来讲述下,如果我们的代码逻辑是从php-cli运行,且一直停留在while(true)中,如何保证代码更新后,

while(true)里的逻辑能够一起更新呢。


// 可以先在服务端启用这个接口,就会循环执行。然后去修改test.php,会发现实时更新了。
public function test2() {
    if ( PHP_SAPI != 'cli') {
        throw new RuntimeException('PHP执行方式不对', 2);
    }
    $file_stat = array();                          // 用来记录文件的状态
    while (true) {
        $file_path = PATH_CTL. '/test.php';        // 将while逻辑抽出来放到test.php里
        clearstatcache(true, $file_path);          // 清除文件缓存,这样stat获取的才是最新的
    
        $file_md5 = md5($file_path);
        $file_cur_stat = stat($file_path);         // 每次都去获取test.php的文件修改时间
        // 判断文件的修改时间,与先前记录的时间是否一致,如果不一致重新require(不能用require_once)
        if ( $file_stat[$file_md5]['mtime'] != $file_cur_stat['mtime'] ) {
            require $file_path;                    // 重新将代码片段opcode require进来
            $file_stat[$file_md5] = $file_cur_stat;// 并将最新的stat信息放到内存$file_stat中
        }
        sleep(3);
    }
}

通过上面的代码,我们将主要的逻辑放入test.php中,当我们更新test.php时,就会做到实时更新代码逻辑了。

不需要重启php-cli的进程了。参考:关于SWOOLE_FRAMEWORK的热更新


12、PHP向Mysql中存储json字符串时,如果json_encode的array中有中文时,存储在Mysql里的中文会变成unicode。

有多种方法可以不存unicode。

(1)PHP版本>=5.4的。

PHP5.4版本,已经给Json新增了一个选项: JSON_UNESCAPED_UNICODE。加上这个选项后,就不会自动把中文编码了。

(2)其他情况。

    // 中文存数据库前,urlencode下,防止出现unicode
    private function myEncode($_arr) {
        foreach ($_arr as $key => &$item) {
            if ( is_array($item) ) {
                $item = $this->myEncode($item);
            } else {
                $item = urlencode($item);
            }
        }
        return $_arr;
    }
    private function myJsonEncode($_arr) {
        $_arr = $this->myEncode($_arr);
        return urldecode(json_encode($_arr));
    }
    private function myJsonDecode($json_str) {
        return json_decode($json_str, true);
    }


13、PHP安全相关。

(1)

PHP服务逻辑中经常遇到这样的情况,就是通过前端给的参数,后端检查后进行跳转。为了防止跳到其他钓鱼网址。

可以对给出的参数进行域名解析,只有特定域名的才会跳转。

$goto = 'http://test.com@163.com';
$_arr = array('test.com');// 我们规定只能跳转到 test.com

preg_match("/^(http:\/\/)?([^\/]+)/i", $goto, $matches); 
$host = $matches[2]; 
// 从主机名中取得后面两段 
preg_match("/[^\.\/]+\.[^\.\/]+$/", $host, $matches);
// echo "domain name is: {$matches[0]}\n";

if ( in_array($matches[0], $_arr) ) {
    die('<script>top.location.href="'.$goto.'"</script>');
}

通过上面的代码判断,如果所给参数对应的域名不在白名单里,就不能跳转。

(2)输出xss攻击。

除了要对于输入的参数进行检查外,stripslashes(htmlspecialchars($value))。

在输出到页面时,要对于script、JavaScript等关键字进行过滤,将这些关键字给去掉。


14、PHP中重定向到其他网址。

(1)我们能够想到的第一种方法,肯定是使用PHP中的header。

private function go($url){
	ob_end_clean();
    header("Location: {$url}");
    // echo sprintf("%s window.location.href='%s' %s", "<script type='text/javascript'>", $url, "</script>");
    exit();
}



但是这种方式,有如下几个问题。

A. header之后的代码还是会执行,所以为了不让后面的代码执行,就最好是在header之后立即加上exit()函数。

B. 在使用header函数之前必须保证没有输出。怎么看有无输出呢?如果当你的代码使用了header后总还是不跳转,

你可以打开Chrome,调试查看。如下图所示。红框里表示有2个空行输出。


(2)第二种方式,就是上面(1)中代码所展示的使用js进行跳转。



15、PHP中file_get_contents使用时的路径问题。

我们在使用file_get_contents时,路径参数可以选择http链接,也可以选择本地路径。如果使用本地路径时,

最好是使用绝对路径。

在目录php下,有目录inc、文件test.php。

在目录php/inc下有文件loading.php、loading.txt。

如果在文件loading.php中写如下代码:

<?php
$jenkins_job_script_java = file_get_contents('./loading.txt'); //loading内容

然后在php/inc的外层目录php目录下的文件test.php中写如下代码:

<?php
$_file = './inc/loading.php';
include($_file);

echo $jenkins_job_script_java;

你会发现$jenkins_job_script_java变量没有get进来,为空。

但是如果你把loading.txt文件直接放在php目录下,就可以get进来了。

证明,file_get_contents的路径索引规则是以当前执行的php脚本的路径为起始寻址路径。


16、Fatal error: Can't use function return value in write context。

我有段代码在我们的测试环境中是好的,但是在正式环境中就是不行,查看PHP的错误日志。

发现了如上的报错。后来查了一些博客发现是因为不恰当使用empty函数导致。

empty函数的参数只能是变量,不能是函数的返回值,也不能是直接一个int、string。

比如,以下两种情况都是不可以的(PHP5.6+对此进行了容错,低版本的都会造成PHP文件无法解析):

empty($this->getMemcache($type));

emtpy('nihao');


17、经常去查看报错日志。

(1)第一类是php.ini里定义的报错日志。

echo '<?php phpinfo(); ?>' | php 2>&1 |grep -i error_log
通过php.ini来查看错误日志存放地址。

(2)第二类是框架里定义的抛出异常。

在我们的框架的如下代码里有定义异常的log地址。

在代码ExceptionHandler.php的log函数里,可以查阅到异常的写地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值