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索引这个坑大家没踩过么?
phone是varchar类型,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 "==="; // 带有类型的比较,肯定不会输出
}
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个字符长度。
主要有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函数里,可以查阅到异常的写地址。