目錄
我忘了PHP函數的參數順序,它們是隨機的嗎?
當使用 password_hash() 或 crypt() 函數時, 「鹽」會被傳回作為產生的雜湊值的一部分。 你可以直接把完整的回傳值儲存到資料庫中, 因為這個回傳值中已經包含了足夠的信息, 可以直接用在 password_verify() 或  crypt() 函數來進行密碼驗證。
在 PHP 中,一段程式碼的結束標記要不是「?>」或是「?>\n」(\n  表示換行)。因此在上面的例子中,輸出的句子將顯示在同一行中,因為 PHP 忽略了程式碼結束標記後面的換行。這表示如果要輸出一個換行符,需要在每段  PHP 程式碼的結束標記後面多加一個換行。
如果你執行下面的程式碼,他將會輸出一個
運行下面程式碼,尤其是第三行,請注意,如果
NULL 的值將會被會略
來源: https://www.php.net/manual/zh/function.http-build-query.php#109466
 PHP執行這段程式碼會經過以下4個步驟(確切的來說,應該是PHP的語言引擎Zend)
var_dump(1...9)输出什么?
HTTPOXY 漏洞
如何形成?
如何影响?
如何处理?
运算符优先级
&& 和 and 在赋值运算中的问题
instanceof 运算符
array_map 的有趣用法
多个 array 用法
原生函数使用不当的话会比你想象的要慢
小心代码中的比较
禁用 PHP 中不安全的 eval 方法
将任意类型转换为 null
isset 和 unset 同时支持多个参数
快速查询一个函数或者类或语法的参考
使用反射调用 protected 或者 private 的类方法
实例化一个类,但是绕过他的构造方法
获取类一个类的所有父类
有趣的递增和递减
递增递减不能作用域 bool 值
递增可以作用域 NULL,但是递减不可以
递增可以作用于字母,但是递减不可以
混合递增数字和字母
请注意你的嵌套强制类型转换,否则他会发生意外
高版本中的数字与字符串进行比较
数组也可以直接比较
合并数组
结束
首頁 後端開發 php教程 PHP學習中實用的知識點與坑分享

PHP學習中實用的知識點與坑分享

May 31, 2021 pm 05:43 PM
php

這篇文章要跟大家分享一些 PHP 中有用的知識和坑。有一定的參考價值,有需要的朋友可以參考一下,希望對大家有幫助。

PHP學習中實用的知識點與坑分享

在一次偶然查看PHP 文件的時候,發現了一些有趣的內容,隨著閱讀的增加,越發覺得有趣的內容或說時坑越來越多,所以我決定記錄下來,分享出去,下文中一些內容摘錄自一些優秀的博客、PHP 文件的用戶筆記,或者文檔原文。

尤其是文檔原文,我發現很多人不會去讀,很多東西也不會去注意(是的,我也是這樣,所以藉著這次機會,一起來學習一下。)

我忘了PHP函數的參數順序,它們是隨機的嗎?

PHP is a glue that brings together hundreds of external libraries, so  sometimes this gets messy. However, a simple rule of thumb is as  follows:

a #aale function soo# cast " whereas String functionsare the opposite, so " haystack, needle".

##譯:陣列相關方法的參數順序為,「needle, haystack」,字串相關方法則是相反的「haystack, needle”,

來源: https://www.php.net/manual/zh/faq.using.php#faq.using.parameterorder

我應該如何保存“鹽”?

當使用 password_hash() 或 crypt() 函數時, 「鹽」會被傳回作為產生的雜湊值的一部分。 你可以直接把完整的回傳值儲存到資料庫中, 因為這個回傳值中已經包含了足夠的信息, 可以直接用在 password_verify() 或  crypt() 函數來進行密碼驗證。

下圖展示了 crypt() 或 password_hash() 函數傳回值的結構。如你所見,演算法的資訊以及「鹽」都已經包含在回傳值中, 在後續的密碼驗證中將會用到這些資訊。

來源: https://www.php.net/manual/zh/faq.passwords.php#faq.password.storing-salts

怎麼沒有分成兩行顯示下面程式碼?

<pre class="brush:php;toolbar:false">
<?php echo "This should be the first line."; ?>
<?php echo "This should show up after the new line above."; ?>
登入後複製

在 PHP 中,一段程式碼的結束標記要不是「?>」或是「?>\n」(\n  表示換行)。因此在上面的例子中,輸出的句子將顯示在同一行中,因為 PHP 忽略了程式碼結束標記後面的換行。這表示如果要輸出一個換行符,需要在每段  PHP 程式碼的結束標記後面多加一個換行。

PHP 為什麼要這麼做呢?因為在格式化正常的 HTML 時,通常會比較容易。假如輸出了換行而你不需要這個換行時,就不得不用一個非常長的行來達到這樣的效果,或者讓產生的 HTML 頁面的源文件的格式很難讀。

來源: https://www.php.net/manual/zh/faq.using.php#faq.using.newlines

字串連線運算子的優先權問題

如果你執行下面的程式碼,他將會輸出一個

警告

和結果3 ,因為字串連接運算子. 和數學運算符 - 的優先權時一樣的,它們會從左往右執行。 Result: 會被強轉成陣列 0 。如果你在低版的PHP 中運行,會告訴你 中邊不是一個數字,如果你在7.4 中運行,會告訴你,在PHP 8 中  、 - 的優先級將會被提升。如果你使用了 PHPSTORM 中的 EA 插件,將會提醒你這個問題。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>&lt;php $var = 3; echo &quot;Result: &quot; . $var + 3;</pre><div class="contentsignin">登入後複製</div></div>如果你不希望這樣,那麼最好使用括號把它包裹起來,就像下面那樣。

<?php
$var = 3;

echo "Result: " . ($var + 3);
登入後複製

來源: https://www.php.net/manual/zh/language.operators.string.php#41950

字串連線運算子與數字

運行下面程式碼,尤其是第三行,請注意,如果

.

左右存在空格,那麼即使是一個數字,也會作用成字串連接。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>&lt;?php echo &quot;thr&quot;.&quot;ee&quot;; //prints the string &quot;three&quot; echo &quot;twe&quot; . &quot;lve&quot;; //prints the string &quot;twelve&quot; echo 1 . 2; //prints the string &quot;12&quot; echo 1.2; //prints the number 1.2 echo 1+2; //prints the number 3</pre><div class="contentsignin">登入後複製</div></div>來源: https://www.php.net/manual/zh/language.operators.string.php#41950

使用http_build_query

NULL 的值將會被會略

<?php
$arr = array(&#39;test&#39; => null, &#39;test2&#39; => 1);

// test2=1
echo http_build_query($arr);
登入後複製

來源: https://www.php.net/manual/zh/function.http-build-query.php#60523

True 和False 將會被轉換成數字

<?php
$a = [teste1= true,teste2=false];
// teste1=1&teste2=0
echo http_build_query($a)
登入後複製

來源: https://www.php.net/manual/zh/function.http-build-query.php#122232

空的陣列不會出現在結果中

<?php

$post_data = array(&#39;name&#39;=>&#39;miller&#39;, &#39;address&#39;=>array(&#39;address_lines&#39;=>array()), &#39;age&#39;=>23);
// name=miller&age=23
echo http_build_query($post_data);
登入後複製

來源: https://www.php.net/manual/zh/function.http-build-query.php#109466

簡述OpCache 的原理

 PHP執行這段程式碼會經過以下4個步驟(確切的來說,應該是PHP的語言引擎Zend)

  • 1. Scanning(Lexing) ,将PHP代码转换为语言片段(Tokens)
  • 2. Parsing, 将Tokens转换成简单而有意义的表达式
  • 3. Compilation, 将表达式编译成Opocdes
  • 4. Execution, 顺次执行Opcodes,每次一条,从而实现PHP脚本的功能。

现在有的Cache比如APC,可以使得PHP缓存住Opcodes,这样,每次有请求来临的时候,就不需要重复执行前面3步,从而能大幅的提高PHP的执行速度。

来源: https://www.laruence.com/2008/06/18/221.html

var_dump(1...9)输出什么?

<?php

// 10.9
var_dump(1...9);
登入後複製

输出10.9, 乍一看这个var_dump的输出很奇怪是不是? 为什么呢?

这里教大家,如果看到一段PHP代码感觉输出很奇怪,第一反应是看下这段代码生成的opcodes是啥,虽然这个问题其实是词法分析阶段的问题,不过还是用phpdbg分析下吧(一般为了防止opcache的影响,会传递-n):

phpdbg -n -p /tmp/1.php
function name: (null)
L1-35 {main}() /tmp/1.php - 0x7f56d1a63460 + 4 ops
L2 #0 INIT_FCALL<1> 96 "var_dump"
L2 #1 SEND_VAL "10.9" 1
L2 #2 DO_ICALL
L35 #3 RETURN<-1> 1
登入後複製

所以这么看来,早在生成opcode之前,1...9就变成了常量10.9,考虑到这是字面量,我们现在去看看zend_language_scanner.l, 找到这么一行:

DNUM ({LNUM}?"."{LNUM})|({LNUM}"."{LNUM}?)
登入後複製

这个是词法分析定义的浮点数的格式,到这里也就恍然大悟了:
1...9 会被依次接受为: 1. (浮点数1), 然后是 . (字符串连接符号) 然后是.9(浮点数0.9)

所以在编译阶段就会直接生成 “1” . “0.9” -> 字符串的字面量”10.9”

来源: https://www.laruence.com/2020/02/23/1990.html

HTTPOXY 漏洞

这里有一个核心的背景是, 长久一来我们习惯了使用一个名为"http_proxy"的环境变量来设置我们的请求代理。

http_proxy=127.0.0.1:9999 wget http://www.laruence.com/
登入後複製

如何形成?

在CGI(RFC 3875)的模式的时候, 会把请求中的Header, 加上HTTP_ 前缀, 注册为环境变量, 所以如果你在Header中发送一个Proxy:xxxxxx, 那么 PHP 就会把他注册为HTTP_PROXY环境变量, 于是getenv("HTTP_PROXY")就变成可被控制的了. 那么如果你的所有类似的请求, 都会被代理到攻击者想要的地址,之后攻击者就可以伪造,监听,篡改你的请求了

如何影响?

所以, 这个漏洞要影响你, 有几个核心前提是:

  • 你的服务会对外请求资源
  • 你的服务使用了HTTP_PROXY(大写的)环境变量来代理你的请求(可能是你自己写,或是使用一些有缺陷的类库)
  • 你的服务跑在PHP的CGI模式下(cgi, php-fpm)

如何处理?

以Nginx为例, 在配置中加入:

fastcgi_param HTTP_PROXY "";
登入後複製

所以建议, 即使你不受此次漏洞影响, 也应该加入这个配置.
而如果你是一个类库的作者,或者你因为什么原因没有办法修改服务配置, 那么你就需要在代码中加入对sapi的判断, 除非是cli模式, 否则永远不要相信http_proxy环境变量,

<?php
if (php_sapi_name() == &#39;cli&#39; && getenv(&#39;HTTP_PROXY&#39;)) {
  //只有CLI模式下, HTTP_PROXY环境变量才是可控的
}
登入後複製

补充: 从PHP5.5.38开始, getenv增加了第二个参数, local_only = false, 如果这个参数为true, 则只会从系统本地的环境变量表中获取, 从而修复这个问题, 并且默认的PHP将拦截HTTP_PROXY:fix

HTTPOXY漏洞说明 - 风雪之隅
https://www.laruence.com/2016/07/19/3101.html

运算符优先级

&& 和 and 在赋值运算中的问题

运行下面的代码,第一个 $bool 将打印为 false ,预期如此,但是第二个 $bool 将打印 true 。这是因为 = 的优先级高于 and 运算符,所以,第二个 $bool 将会被当成 ($bool = true) and false 执行。

<?php

$bool = true && false;
// false
var_dump($bool);


$bool = true and false;
// true
var_dump($bool);
登入後複製

来源: https://www.php.net/manual/zh/language.operators.precedence.php#117390

instanceof 运算符

你是否曾经写过下面这样的代码?

<?php

class A {

}

$A = new A();

var_dump((! $A instanceof A));

// 其实不用担心,因为 instanceof 的优先级要高于 ! ,你可以放心的使用,
// 不必添加括号,让他们看起来是一个表达式,但是在复杂的情况下例外。
var_dump(! $A instanceof A);
登入後複製

在你需要对 instanceof 运算的结果做取反运算时,因为取反运算符 ! 的优先级低于 instanceof 所以,你不必再它们外面再加上一个圆括号来表明这是一组表达式,但是再复杂情况下例外。

array_map 的有趣用法

通常,我会使用 array_map 来处理一个数组,让他返回一个新的数组,当然,它的用处就是这样的,但是除了这种基础的用法,它其实还有一些有趣的用法,并且,这些用法都存在于 PHP 的手册中。

多个 array 用法

通常你会这样使用它。

<?php

$arr1 = [&#39;apple&#39;, &#39;orange&#39;, &#39;mango&#39;, &#39;pear&#39;];
$newArr1 = array_map(&#39;strtoupper&#39;,$arr1);
登入後複製

这只是一个简单的,它会把所有的值转为大写的。那么看看下面的用法,猜猜会打印什么?

<?php

$arr1 = [&#39;apple&#39;, &#39;orange&#39;, &#39;mango&#39;, &#39;pear&#39;];
$arr2 = [&#39;cauliflower&#39;, &#39;lettuce&#39;, &#39;kale&#39;, &#39;romaine&#39;];

function map1($a, $b){
    var_dump($a, $b);
  // apple   cauliflower
  // orange  lettuce
  // mango   kale
  // pear    romaine
}

array_map(&#39;map1&#39;, $arr1, $arr2);
登入後複製

如上 map1 方法所示,将会顺序遍历 $arr1 , $arr2 中的值,并且传递给 map1 ,根据手册所定义: 如果多个数组的长度不一,即短的数组将会被填充空,至长的数组一样

原生函数使用不当的话会比你想象的要慢

array_unique、array_merge 等,如果使用方法不正确,会比你想想的要慢,甚至是慢很多,远不如 foreach。

在下面这个回答中,列举了 PHP 中一些 array_* 方法的时间复杂度
performance - List of Big-O for PHP functions - Stack Overflow

小心代码中的比较

下面的比较将会返回 true,是不是不敢相信?

因为两个 md5 值都有开始'0e',所以PHP类型理解这些字符串是科学符号。根据定义,0 的任何次方都是 0,所以在这里会成立‎,所以当你确定一个变量的类型时,你最好使用 ===(恒等于)进行比较。

<?php

$a = md5(&#39;240610708&#39;);// 0e462097431906509019562988736854
$b = md5(&#39;QNKCDZO&#39;); // 0e830400451993494058024219903391

var_dump($a == $b); // true
登入後複製

注意,当你在考虑使用 md5 存储密码时,你应该放弃这个想法,应该改用为 password_hash 系列方法。

来自:https://www.php.net/manual/zh/function.md5.php#123392

禁用 PHP 中不安全的 eval 方法

众所周知, 在 php 中,eval 方法可以执行任意 PHP 代码,如果没有做好处理,被用户利用了, 就有可能会造成安全漏洞,所以最好想办法禁用它,谈到禁用 php 函数,你应该想到了 php.ini 中的 disable_functions参数,可以用来禁用 PHP 函数,一些集成环境中也会禁用一些高风险函数来降低风险。

但是,这个配置项,却禁用不了 eval 函数,因为根据官方文档的定义, eval 不是一个函数,他如同 echo 、这些特殊方法一样,他是一个语法结构,所以不能使用 disable_functions进行禁用,除此之外,还有 require、list、array、print、unset、include、isset、empty 、die、exit 等,这些都是语法结构,不是函数,如果你使用 function_exists判断,他们都会返回 false

如果你真的需要禁用 eval ,你得安装一些第三方扩展来实现,比如 mk-j/PHP_diseval_extension

参考:https://www.php.net/manual/zh/functions.variable-functions.php#functions.variable-functions

将任意类型转换为 null

听起来没什么用但是你确实可以这样做。

<?php

$a = &#39;Hi!&#39;;
// 在 PHP 7.2 以下,这行代码会返回 null,7.2 ~ 7.4 会返回 NULL,但是会提示被遗弃,
// 8.0 开始,将不再支持
var_dump((unset)$a);
var_dump($a);
登入後複製

除此之外,你还可以用 settype 函数
参考:https://www.php.net/settype

参考:https://www.php.net/manual/zh/function.unset.php#example-5601

isset 和 unset 同时支持多个参数

unset 支持多个参数,想必大多数人是知道的,但是 isset 也支持哟。

<?php

var_dump(isset($a, $b, $c));

unset($a, $b, $c);
登入後複製

你不需要担心这几个变量没有被设置,他们在这里都是安全的,不会报错,在 isset 多个变量时,必须要所有变量都不为 null时,才会返回 true,当遇到一个不存在时,将会立即返回。

参考:https://www.php.net/isset

快速查询一个函数或者类或语法的参考

当你要查询一个 php 方法或者对象或者语法时,你不需要打开 php 手册进行搜索,你只需要在 https://php.net/<keyword>后面跟上方法、语法、对象的名字即可,并且不需要关心大小i额,比如像下面这些链接。

  • https://php.net/curlfile
  • https://php.net/isset
  • https://php.net/if

使用反射调用 protected 或者 private 的类方法

如果想避免一个方法被外部可见或者子类可见,可以采用 protected 或者 private 关键字来修改这些类,但是我们有时候又想在外部调用这些方法,应该怎么办呢?只能改成 public 吗?如果这是我们自己的代码,当然可以这样做,但是如果是引入的外部代码的话,可能就不太好直接修改了。

现在,我们可以在外部使用 反射 来调用这些方法,现在我们来定义一个 Lisa 类

<?php

class Lisa
{
    public function name()
    {
        return &#39;Lisa&#39;;
    }

    protected function age()
    {
        return 22;
    }

    private function weight()
    {
        return 95;
    }
  
    private static function eat(){
        return 1;
    }
}
登入後複製

通常情况下,我们是没有办法直接调用 age 和 weight 方法的,现在,我们使用反射来调用。

<?php
// ...
$reflectionClass = new ReflectionClass(&#39;Lisa&#39;);
$ageMethod = $reflectionClass->getMethod(&#39;age&#39;); // 获取 age 方法
$ageMethod->setAccessible(true); // 设置可见性
// 调用这个方法,需要传入对象作为上下文
$age = $ageMethod->invoke($reflectionClass->newInstance());
var_dump($age);// 22
登入後複製

上面的代码看起来有些繁琐,还有一个更简单的办法。

<?php
// ...
$reflectionClass = new ReflectionClass(&#39;Lisa&#39;);
$weightMethod = $reflectionClass->getMethod(&#39;weight&#39;);// 获取 weight 方法
// 获取一个闭包,然后调用,同样需要传入对象作为上下文,后面调用的地方就可以传入参数
$weight = $weightMethod->getClosure($reflectionClass->newInstance())();
var_dump($weight);
登入後複製

调用静态方法

<?php
// ...
$reflectionClass = new ReflectionClass(&#39;Lisa&#39;);
$eatMethod = $reflectionClass->getMethod(&#39;eat&#39;);
$eatMethod->setAccessible(true);
$eat = $eatMethod->invoke(null); // 如果是一个静态方法,你可以传递一个 null
var_dump($eat);
登入後複製

同样,类成员也可以使用反射进行修改。
参考: https://www.php.net/manual/zh/class.reflectionproperty.php

实例化一个类,但是绕过他的构造方法

有没有这样想过?实例化一个类,但是却不想调用他的构造方法(__construct),这里也可以用反射做到。

<?php

class Dog
{
    private $name;

    public function __construct($name)
    {
        $this->name = $name;
    }

    public function getName()
    {
        return $this->name;
    }
}

$dogClass = new ReflectionClass(&#39;Dog&#39;);
// 创建一个新实例,但是不调用构造方法
$dogInstance = $dogClass->newInstanceWithoutConstructor();
var_dump($dogInstance->getName()); // null
登入後複製

如果你的环境不能使用反射,你还可以试试另一个很 cool 的方法,就是使用反序列化,可以参考包 doctrine/instantiator - Packagist

参考: https://www.php.net/manual/zh/reflectionclass.newinstancewithoutconstructor.php

获取类一个类的所有父类

使用 class_parents可以获取一个类的所有父类,并且支持自动加载。

<?php

class A{}
class B extends A{}
class C extends B{}
class D extends C{}

var_dump(class_parents(&#39;D&#39;));
/*
array(3) {
  &#39;C&#39; =>
  string(1) "C"
  &#39;B&#39; =>
  string(1) "B"
  &#39;A&#39; =>
  string(1) "A"
}
*/
登入後複製

参考:https://www.php.net/manual/zh/function.class-parents.php

有趣的递增和递减

递增递减不能作用域 bool 值

递增、递减不能使用在 false 上面,但是 +=-= 可以

<?php

$a = false;

++$a;

var_dump($a);// false

$a++;

var_dump($a);// false

--$a;

var_dump($a);// false

$a--;

var_dump($a);// false

$a-= 1;

var_dump($a);// -1

$a+= 1;// 因为前面改变了,变成了 -1,所以下面是 0 ,请不要在这里疑惑

var_dump($a);// 0
登入後複製

递增可以作用域 NULL,但是递减不可以

<?php

$a = null;
++$a;
var_dump($a); //1

$a = null;
--$a;
var_dump($a); // null
登入後複製

递增可以作用于字母,但是递减不可以

a-y 递增时字母都将向后增加一个,但是当 z 的时候,就将会回到 aa ,循环如此,但是只能递增,不能递减

<?php

$a = &#39;a&#39;;
++$a;
var_dump($a); // b

$a = &#39;z&#39;;
++$a;
var_dump($a); // aa

$a = &#39;A&#39;;
++$a;
var_dump($a); // B

$a = &#39;Z&#39;;
++$a;
var_dump($a); // AA
登入後複製

混合递增数字和字母

现在你还可以把字母和数字混合起来,就像这样:

>>> $a = &#39;A1&#39;
=> "A1"
>>> ++$a
=> "A2"
>>> ++$a
=> "A3"
>>> $a = &#39;001A&#39;
=> "001A"
>>> ++$a
=> "001B"
>>> ++$a
=> "001C"
>>> $a = &#39;A001&#39;
=> "A001"
>>> ++$a
=> "A002"
>>> ++$a
=> "A003"
登入後複製

但是请注意一些意外情况,比如这样。

>>> $a = &#39;9E0&#39;
=> "9E0"
>>> ++$a
=> 10.0
登入後複製

这是因为9E0 被当作成了浮点数的字符串表示,被 PHP 当成了 9*10^0 ,被评估成了 9 ,然后在执行的递增。

参考来源: https://www.php.net/manual/zh...

请注意你的嵌套强制类型转换,否则他会发生意外

<?php

var_dump(TRUE === (boolean) (array) (int) FALSE);// true

var_dump((array) (int) FALSE);
登入後複製

因为当把 FALSE 转为数字是,他是 0,再转为数组后,就成了,[0],所以再转为 boolean 时,将会返回 true,因为数组不为空,并且 [0] != []

参考:https://www.php.net/manual/zh/language.types.type-juggling.php#115373

高版本中的数字与字符串进行比较

自 PHP 8.0 开始。

数字与非数字形式的字符串之间的非严格比较现在将首先将数字转为字符串,然后比较这两个字符串。 数字与数字形式的字符串之间的比较仍然像之前那样进行。 请注意,这意味着 0 == "not-a-number" 现在将被认为是 false 。
ComparisonBeforeAfter
0 == "0"truetrue
0 == "0.0"truetrue
0 == "foo"truefalse
0 == ""truefalse
42 == " 42"truetrue
42 == "42foo"truefalse

参考:https://www.php.net/manual/zh/migration80.incompatible.php#migration80.incompatible.core

数组也可以直接比较

你可以直接使用 == 比较两个数组有相同的键值对,如果这不是一个关联数组,那么就要保证值的顺序相对应,如果时一个关联数组,你就可以不用担心。

>>> $b = [1,2,3,4]
=> [
     1,
     2,
     3,
     4,
   ]
>>> $a = [1,2,3,4]
=> [
     1,
     2,
     3,
     4,
   ]
>>> $a == $b
=> true

// 注意,他不会比较类型。

>>> $a = [0,1,2,3,4]
=> [
     0,
     1,
     2,
     3,
     4,
   ]
>>> $b = [false,1,2,3,4]
=> [
     false,
     1,
     2,
     3,
     4,
   ]
>>> $a == $b
=> true

// 如果你要比较类型,你应该使用 ===

>>> $a === $b
=> false
登入後複製

无序的比较:
下面的列表中,使用 == 将会返回 true ,因为他们的值是相等的,只是顺序不同,但是如果使用 === 将会返回类型,因为 === 的时候会考虑键值顺序和数据类型。

>>> $a = [&#39;name&#39;=>&#39;Jack&#39;,&#39;sex&#39;=>1,&#39;age&#39;=>18];
=> [
     "name" => "Jack",
     "sex" => 1,
     "age" => 18,
   ]
>>> $b = [&#39;name&#39;=>&#39;Jack&#39;,&#39;age&#39;=>18,&#39;sex&#39;=>1];
=> [
     "name" => "Jack",
     "age" => 18,
     "sex" => 1,
   ]
>>> $a == $b
=> true
>>> $a === $b
=> false
>>>
登入後複製

来源:PHP: 数组运算符 - Manual

https://www.php.net/manual/zh/language.operators.array.php

合并数组

数组还可以相加 (+),用来合并数组,使用 array_merge 可以合并数组可以把两个数组相加,想必是都知道的,但是其实 + 号也可以,虽然都是合并数组,这两个方法各有区别。+ 更像是替换。

1、使用 array_merge 合并非关联数组时,不会过滤重复项目, + 会(更像是替换)

>>> $a = [1,2,3]
=> [
     1,
     2,
     3,
   ]
>>> $b = [2,3,4]
=> [
     2,
     3,
     4,
   ]
>>> array_merge($a,$b)
=> [
     1,
     2,
     3,
     2,
     3,
     4,
   ]
>>> $a + $b
=> [
     1,
     2,
     3,
   ]
登入後複製

2、使用 array_merge 合并关联数组时,如果键重复,将会保留最后一个数组的值,而使用 + 将会保留第一个键下面的值。

>>> $a = [&#39;name&#39;=>&#39;Jack&#39;,&#39;sex&#39;=>1,&#39;age&#39;=>18];
=> [
     "name" => "Jack",
     "sex" => 1,
     "age" => 18,
   ]
>>> $b = [&#39;name&#39;=>&#39;Jack&#39;,&#39;age&#39;=>&#39;18&#39;,&#39;sex&#39;=>&#39;1&#39;];
=> [
     "name" => "Jack",
     "age" => "18",
     "sex" => "1",
   ]
>>> array_merge($a, $b)
=> [
     "name" => "Jack",
     "sex" => "1",
     "age" => "18",
   ]
>>> $a + $b
=> [
     "name" => "Jack",
     "sex" => 1,
     "age" => 18,
   ]
登入後複製

3、当关联数组中存在数字键时, array_merge 会重置数字键, + 则不会

>>> $a = [&#39;name&#39;=>&#39;Jack&#39;,&#39;sex&#39;=>1,&#39;age&#39;=>18];
=> [
     "name" => "Jack",
     "sex" => 1,
     "age" => 18,
   ]
>>> $b = [&#39;name&#39;=>&#39;Jack&#39;,&#39;age&#39;=>&#39;18&#39;,&#39;sex&#39;=>&#39;1&#39;,&#39;10&#39;=>&#39;hi&#39;];
=> [
     "name" => "Jack",
     "age" => "18",
     "sex" => "1",
     10 => "hi",
   ]
>>> array_merge($a,$b)
=> [
     "name" => "Jack",
     "sex" => "1",
     "age" => "18",
     // 注意这里
     0 => "hi",
   ]
>>> $a + $b
=> [
     "name" => "Jack",
     "sex" => 1,
     "age" => 18,
     // 注意这里
     10 => "hi",
   ]
登入後複製

下面用一张图来概括一下。

PHP學習中實用的知識點與坑分享

图片来源:array_merge vs array_replace vs + (plus aka union) in PHP | SOFTonSOFA

结束

  • 文章中大部分内容来自网络搜集,我已经尽所能去验证其真实性,但可能部分会有纰漏,如果有请不吝赐教。
  • 另外,如果文中的内容侵犯到了你得权益,请与我联系处理。
  • 你还可以点击文章中的来源链接,了解更详细的内容。

推荐学习:《PHP视频教程

以上是PHP學習中實用的知識點與坑分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

適用於 Ubuntu 和 Debian 的 PHP 8.4 安裝和升級指南 適用於 Ubuntu 和 Debian 的 PHP 8.4 安裝和升級指南 Dec 24, 2024 pm 04:42 PM

PHP 8.4 帶來了多項新功能、安全性改進和效能改進,同時棄用和刪除了大量功能。 本指南介紹如何在 Ubuntu、Debian 或其衍生版本上安裝 PHP 8.4 或升級到 PHP 8.4

在PHP API中說明JSON Web令牌(JWT)及其用例。 在PHP API中說明JSON Web令牌(JWT)及其用例。 Apr 05, 2025 am 12:04 AM

JWT是一種基於JSON的開放標準,用於在各方之間安全地傳輸信息,主要用於身份驗證和信息交換。 1.JWT由Header、Payload和Signature三部分組成。 2.JWT的工作原理包括生成JWT、驗證JWT和解析Payload三個步驟。 3.在PHP中使用JWT進行身份驗證時,可以生成和驗證JWT,並在高級用法中包含用戶角色和權限信息。 4.常見錯誤包括簽名驗證失敗、令牌過期和Payload過大,調試技巧包括使用調試工具和日誌記錄。 5.性能優化和最佳實踐包括使用合適的簽名算法、合理設置有效期、

您如何在PHP中解析和處理HTML/XML? 您如何在PHP中解析和處理HTML/XML? Feb 07, 2025 am 11:57 AM

本教程演示瞭如何使用PHP有效地處理XML文檔。 XML(可擴展的標記語言)是一種用於人類可讀性和機器解析的多功能文本標記語言。它通常用於數據存儲

解釋PHP中的晚期靜態綁定(靜態::)。 解釋PHP中的晚期靜態綁定(靜態::)。 Apr 03, 2025 am 12:04 AM

靜態綁定(static::)在PHP中實現晚期靜態綁定(LSB),允許在靜態上下文中引用調用類而非定義類。 1)解析過程在運行時進行,2)在繼承關係中向上查找調用類,3)可能帶來性能開銷。

php程序在字符串中計數元音 php程序在字符串中計數元音 Feb 07, 2025 pm 12:12 PM

字符串是由字符組成的序列,包括字母、數字和符號。本教程將學習如何使用不同的方法在PHP中計算給定字符串中元音的數量。英語中的元音是a、e、i、o、u,它們可以是大寫或小寫。 什麼是元音? 元音是代表特定語音的字母字符。英語中共有五個元音,包括大寫和小寫: a, e, i, o, u 示例 1 輸入:字符串 = "Tutorialspoint" 輸出:6 解釋 字符串 "Tutorialspoint" 中的元音是 u、o、i、a、o、i。總共有 6 個元

什麼是PHP魔術方法(__ -construct,__destruct,__call,__get,__ set等)並提供用例? 什麼是PHP魔術方法(__ -construct,__destruct,__call,__get,__ set等)並提供用例? Apr 03, 2025 am 12:03 AM

PHP的魔法方法有哪些? PHP的魔法方法包括:1.\_\_construct,用於初始化對象;2.\_\_destruct,用於清理資源;3.\_\_call,處理不存在的方法調用;4.\_\_get,實現動態屬性訪問;5.\_\_set,實現動態屬性設置。這些方法在特定情況下自動調用,提升代碼的靈活性和效率。

PHP和Python:比較兩種流行的編程語言 PHP和Python:比較兩種流行的編程語言 Apr 14, 2025 am 12:13 AM

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

PHP:網絡開發的關鍵語言 PHP:網絡開發的關鍵語言 Apr 13, 2025 am 12:08 AM

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

See all articles