PHP變數型別

那頁陽光發表於2019-02-16

簡介

PHP支援9種原始資料型別。

4種標量型別:

  • boolean布林型
  • integer 整形
  • float 浮點型(也稱作double
  • string 字串

3種複合型別:

  • array 陣列
  • object 物件
  • callable 可呼叫

2種特殊型別

  • resource 資源
  • null 無型別

為了確保程式碼的易讀性,我們通常會使用一些偽型別:

  • mixed 混合型別
  • number 數字型別
  • callback 回撥型別(又稱為callable
  • array|object 陣列|物件型別
  • void 無型別

變數的型別不是程式設計師設定,是由PHP根據該變數使用的上下文在執行時決定的。

與變數型別有關的常用函式

  • 如果想檢視某個表示式的值和型別,使用var_dump()函式。
  • 獲取變數的型別,使用gettype()函式。
  • 要檢驗某個型別,可以使用is_type函式,如:
    <?php
        $a = 1;
        
        if(is_int($a)){
            echo "
$a是在整形
";
        }
        
        if(is_float($a)){
            echo "
$a是在浮點型
";
        }
        
        if(is_string($a)){
            echo "
$a是在字串
";
        }

        ......
    ?>
  • 如果需要將一個變數強制轉換為某型別,可以對其使用強制轉換或者settype()函式。

接下來我們先來看看四種標量型別

Boolean 布林型別

這是最簡單的型別。boolean表達了真值,可以為TRUEFALSE

語法

要指定一個布林值,使用常量TRUEFALSE。(不區分大小寫)如:

<?php
    $bool = TRUE; // 設定$bool 為 TRUE
?>

通常運算子所返回的boolean值結果會被傳遞給控制流程。

轉換為布林值

要明確的將一個值轉換成boolean,用(bool)或者(boolean)來強制轉換,但是很多情況下不需要用強制轉換,因為當運算子,函式或者流程控制結構需要一個 boolean 引數時,該值會被自動轉換。

當轉換為 boolean 時,以下值被認為是 FALSE:

  • 布林值FALSE本身
  • 整型值 0
  • 浮點型 0.0
  • 空字串,以及字串”0″
  • 不包括任何元素的陣列
  • 特殊型別NULL(包括尚未賦值的變數)
  • 從空標記生成的SimpleXML物件

所有其它值都被認為是TRUE(包括任何資源和NAN)。

Integer 整型

integer 是集合 ℤ = {…, -2, -1, 0, 1, 2, …} 中的某個數。

語法

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

要使用八進位制表達,數字前必須加上 0(零)。要使用十六進位制表達,數字前必須加上 0x。要使用二進位制表達,數字前必須加上 0b

Example

<?php
    $a = 1234; // 十進位制數
    $a = -123; // 負數
    $a = 0123; // 八進位制數 (等於十進位制 83)
    $a = 0x1A; // 十六進位制數 (等於十進位制 26)
    $a = 0b11111111; // 二進位制數字 (等於十進位制 255)
?>

整型數的字長和平臺有關,儘管通常最大值是大約二十億(32 位有符號)。64 位平臺下的最大值通常是大約 9E18,除了 Windows 下 PHP 7 以前的版本,總是 32 位的。 PHP 不支援無符號的 integer。Integer 值的字長可以用常量 PHP_INT_SIZE來表示,自 PHP 4.4.0 和 PHP 5.0.5後,最大值可以用常量 PHP_INT_MAX 來表示,最小值可以在 PHP 7.0.0 及以後的版本中用常量 PHP_INT_MIN 表示。

整數溢位

如果給定的一個數超出了 integer 的範圍,將會被解釋為 float。同樣如果執行的運算結果超出了 integer 範圍,也會返回 float

PHP 中沒有整除的運算子。1/2 產生出 float 0.5。 值可以捨棄小數部分,強制轉換為 integer,或者使用 round() 函式可以更好地進行四捨五入。

轉換為整型

要明確地將一個值轉換為 integer,用 (int)(integer) 強制轉換。不過大多數情況下都不需要強制轉換,因為當運算子,函式或流程控制需要一個 integer 引數時,值會自動轉換。還可以通過函式 intval() 來將一個值轉換成整型。

思考下以下兩種流程控制的區別:

<?php
    $num = `1`;
    if(1 == $num){
        # code ...
    }
    
    if($num == 1){
        # code ...
    }
?>

從資源型別轉換

resource 轉換成 integer 時, 結果會是 PHP 執行時為 resource 分配的唯一資源號。

從浮點型轉換

當從浮點數轉換成整數時,將向下取整。

如果浮點數超出了整數範圍(32 位平臺下通常為 +/- 2.15e+9 = 2^31,64 位平臺下,除了 Windows,通常為 +/- 9.22e+18 = 2^63),則結果為未定義,因為沒有足夠的精度給出一個確切的整數結果。在此情況下沒有警告,甚至沒有任何通知!

PHP 7.0.0 起,NaNInfinity 在轉換成 integer 時,不再是 undefined 或者依賴於平臺,而是都會變成零。

Warning

絕不要將未知的分數強制轉換為 integer,這樣有時會導致不可預料的結果。

<?php
    echo (int) ( (0.1+0.7) * 10 ); // 顯示 7!
?>

Float 浮點型

浮點型(也叫浮點數 float,雙精度數 double 或實數 real)可以用以下任一語法定義:

<?php
    $a = 1.234; 
    $b = 1.2e3; 
    $c = 7E-10;
?>

浮點數的字長和平臺相關,儘管通常最大值是 1.8e308 並具有 14 位十進位制數字的精度(64 位 IEEE 格式)

浮點數的精度

浮點數的精度有限。儘管取決於系統,PHP 通常使用 IEEE 754 雙精度格式,則由於取整而導致的最大相對誤差為 1.11e-16。非基本數學運算可能會給出更大誤差,並且要考慮到進行復合運算時的誤差傳遞。

此外,以十進位制能夠精確表示的有理數如 0.1 或 0.7,無論有多少尾數都不能被內部所使用的二進位制精確表示,因此不能在不丟失一點點精度的情況下轉換為二進位制的格式。這就會造成混亂的結果:例如,floor((0.1+0.7)*10) 通常會返回 7 而不是預期中的 8,因為該結果內部的表示其實是類似 7.9999999999999991118…。

所以永遠不要相信浮點數結果精確到了最後一位,也永遠不要比較兩個浮點數是否相等。如果確實需要更高的精度,應該使用任意精度數學函式或者 gmp 函式。

比較浮點數

如上述警告資訊所言,由於內部表達方式的原因,比較兩個浮點數是否相等是有問題的。不過還是有迂迴的方法來比較浮點數值的。

要測試浮點數是否相等,要使用一個僅比該數值大一丁點的最小誤差值。該值也被稱為機器極小值(epsilon)或最小單元取整數,是計算中所能接受的最小的差別值。

$a 和 $b 在小數點後五位精度內都是相等的。

<?php
    $a = 1.23456789;
    $b = 1.23456780;
    $epsilon = 0.00001;
    
    if(abs($a-$b) < $epsilon) {
        echo "true";
    }
?>

NaN

某些數學運算會產生一個由常量 NAN (not a number) 所代表的結果。此結果代表著一個在浮點數運算中未定義或不可表述的值。任何拿此值與其它任何值(除了 TRUE)進行的鬆散或嚴格比較的結果都是 FALSE

由於 NAN 代表著任何不同值,不應拿 NAN 去和其它值進行比較,包括其自身,應該用 is_nan() 來檢查。

String 字串

一個字串 string 就是由一系列的字元組成,其中每個字元等同於一個位元組。這意味著 PHP 只能支援 256 的字符集,因此不支援 Unicode

分析一下:

1 Byte = 8 bit
由於1個位元組儲存一個字元,那麼1位元組所能儲存字元的可能性為:2^8=256

語法

一個字串可以用 4 種方式表達:

  1. 單引號
  2. 雙引號
  3. heredoc 語法結構
  4. nowdoc 語法結構

單引號

定義一個字串的最簡單的方法是用單引號把它包圍起來(字元 `)。

要表達一個單引號自身,需在它的前面加個反斜線()來轉義。要表達一個反斜線自身,則用兩個反斜線()。其它任何方式的反斜線都會被當成反斜線本身:也就是說如果想使用其它轉義序列例如 r 或者 n,並不代表任何特殊含義,就單純是這兩個字元本身。

不像雙引號和 heredoc 語法結構,在單引號字串中的變數特殊字元的轉義序列將不會被替換。

雙引號

果字串是包圍在雙引號(”)中, PHP 將對一些特殊的字元進行解析:

序列 含義
n 換行(ASCII 字符集中的 LF 或 0x0A (10))
r 回車(ASCII 字符集中的 CR 或 0x0D (13))
t 水平製表符(ASCII 字符集中的 HT 或 0x09 (9))
v 垂直製表符(ASCII 字符集中的 VT 或 0x0B (11))(自 PHP 5.2.5 起)
e Escape(ASCII 字符集中的 ESC 或 0x1B (27))(自 PHP 5.4.0 起)
f 換頁(ASCII 字符集中的 FF 或 0x0C (12))(自 PHP 5.2.5 起)
反斜線
&dollar; 美元標記
雙引號
[0-7]{1,3} 符合該正規表示式序列的是一個以八進位制方式來表達的字元
x[0-9A-Fa-f]{1,2} 符合該正規表示式序列的是一個以十六進位制方式來表達的字元

和單引號字串一樣,轉義任何其它字元都會導致反斜線被顯示出來。
用雙引號定義的字串最重要的特徵是變數會被解析。

Heredoc 結構

第三種表達字串的方法是用 heredoc 句法結構:<<<。在該運算子之後要提供一個識別符號,然後換行。接下來是字串 string 本身,最後要用前面定義的識別符號作為結束標誌。

結束時所引用的識別符號必須在該行的第一列,而且,識別符號的命名也要像其它標籤一樣遵守 PHP 的規則:只能包含字母、數字和下劃線,並且必須以字母和下劃線作為開頭。

Warning

要注意的是結束識別符號這行除了可能有一個分號(;)外,絕對不能包含其它字元。這意味著識別符號不能縮排,分號的前後也不能有任何空白或製表符。更重要的是結束識別符號的前面必須是個被本地作業系統認可的換行,比如在 UNIX 和 Mac OS X 系統中是 n,而結束定界符(可能其後有個分號)之後也必須緊跟一個換行。

如果不遵守該規則導致結束標識不“乾淨”,PHP 將認為它不是結束識別符號而繼續尋找。如果在檔案結束前也沒有找到一個正確的結束識別符號,PHP 將會在最後一行產生一個解析錯誤。

Heredocs 結構不能用來初始化類的屬性。自 PHP 5.3 起,此限制僅對 heredoc 包含變數時有效。

Heredoc 結構就象是沒有使用雙引號的雙引號字串,這就是說在 heredoc 結構中單引號不用被轉義,但是上文中列出的轉義序列還可以使用。變數將被替換,但在 heredoc 結構中含有複雜的變數時要格外小心。

在 PHP 5.3.0 以後,也可以用 Heredoc 結構來初始化靜態變數和類的屬性和常量。

自 PHP 5.3.0 起還可以在 Heredoc 結構中用雙引號來宣告識別符號:

<?php
    echo <<<"FOOBAR"
    Hello World!
    FOOBAR;
?>

Nowdoc 結構

就像 heredoc 結構類似於雙引號字串,Nowdoc 結構是類似於單引號字串的。Nowdoc 結構很象 heredoc 結構,但是 nowdoc 中不進行解析操作。這種結構很適合用於嵌入 PHP 程式碼或其它大段文字而無需對其中的特殊字元進行轉義。與 SGML 的 <![CDATA[ ]]> 結構是用來宣告大段的不用解析的文字類似,nowdoc 結構也有相同的特徵。

一個 nowdoc 結構也用和 heredocs 結構一樣的標記 <<<, 但是跟在後面的識別符號要用單引號括起來,即 <<<`EOT`。Heredoc 結構的所有規則也同樣適用於 nowdoc 結構,尤其是結束識別符號的規則。

相關文章