# php 變量
[toc]
## 1. 變量是什么
| 概念 | 描述 |
| ------------------ | ------------------------------------------------------------------- |
| 臨時存儲數據的空間 | 并不所有數據都需要保存到文件中,對于只用于當前程序的數據用變量更合適 |
| 數據復用的手段 | 將程序需要反復調用的數據,保存到一個變量中, 可以實現數據復用 |
---
## 2. 命名規范
| 序號 | 規則 | 描述 |
| ---- | ---------- | -------------------------------------------------------------------------- |
| 1 | 語法 | `$ + 標識符` (必須以`$`做為變量標志) |
| 2 | 標識符 | `[a-z][A-Z][0-9]_` 只允許使用大小寫英文字母,數字或下劃線, 且不能以數字開始 |
| 3 | 大小寫敏感 | 嚴格區分大小寫: `$name`和 `$Name`是完全不同的變量 |
示例代碼: `demo3.php`
```php
# 變量命名
$username = 'admin';
$userName = 'peter';
// 區分大小寫
echo $username, '<br>', $userName, '<hr>';
// 無效變量名
// 沒有使用$開頭
// Hello = 'php';
// 標識符以數字開始
// $123aaa = 100;
// 標識符使用了特殊字符
// $user@id = 20;
// 有意義但不推薦, 如中文變量名
$我的郵箱 = 'peter@php.cn';
echo $我的郵箱;
// 無意義變量名
$aaa = 'php.cn';
$_ = 123;
$_123 = 888;
// 變量要做到望名生義, 一個有意義的變量名,可以極大提升代碼的可讀性和可維護性
```
> 推薦一個變量命名網站,告別命名恐懼癥:<https://unbug.github.io/codelf/>
---
## 3. 創建方式
php 是動態語言,所以它的類型,值和變量名都是動態的
| 序號 | 名稱 | 描述 |
| ---- | ---------- | ----------------------------------------------------- |
| 1 | 弱類型 | 變量的類型,由它的當前值決定 |
| 2 | 變量傳遞 | 變量的值來自另一個變量時,有"值傳遞與引用傳遞"二種方式 |
| 3 | 動態變量名 | 也叫"可變變量", 即變量標識符可以來自另一個變量的值 |
### 3.1 弱類型
- php 是**弱類型**語言, 它的變量類型,由賦給它的**值**決定
- 因此, php 變量也不需要使用前進行聲明
示例代碼: `demo4.php`
```php
# php變量是弱類型
$var = 100;
var_dump($var);
echo '<br>';
$var = 'Hello World';
var_dump($var);
/*
int(100)
string(11) "Hello World"
*/
```
### 3.2 值傳遞與引用傳遞
將變量賦值給另一個變量時,有**值傳遞與引用傳遞**二種方式
| 序號 | 傳遞方式 | 描述 |
| ---- | -------- | --------------------------------------- |
| 1 | 值傳遞 | 將原變量的副本(_變量值_)復制到新變量中 |
| 2 | 引用傳遞 | 將原變量內存訪問地址`&引用`賦值給新變量 |
> 變量的值保存在"棧"中, 引用地址保存在"堆"中, 想深入了解請學習數據結構知識
示例代碼: `demo5.php`
```php
# 值傳遞與引用傳遞
// 1. 值傳遞
$price1 = 99;
// 將price1的值,傳遞給變量price2
$price2 = $price1;
// 更新price2
$price2 = 199;
// 查看price1當前值:99
echo 'price1 = ' . $price1;
echo '<hr>';
// 2. 引用傳遞
$price1 = 99;
// 將price1的引用(可理解為地址),傳遞給變量price2
// 注意, 在變量price1前添加一個&:地址引用符
$price2 = &$price1;
// 更新price2
$price2 = 199;
// 查看price1當前值: 199
echo 'price1 = ' . $price1;
// 此時,price1已經隨price2同步更新為199
```
### 3.3 可變變量
- 可變變量: 是指變量的標識符可以動態的改變,即變量標識符可以來自另一個變量的值
- 應用場景: 需要通過動態改變變量來處理不同需求的時候,例如圖像處理,請求處理時
示例代碼: `demo6.php`
```php
?php
# 可變變量
$var = 'email';
$$var = 'admin@php.cn';
// 等價于
// $email = 'admin@php.cn';
echo $email;
```
---
## 4. 檢測與刪除
| 序號 | 函數 | 描述 |
| ---- | ----------- | -------------------------------------- |
| 1 | `isset()` | 檢測變量是否存在且值非`null` |
| 2 | `unset()` | 刪除變量,無返回值 |
| 3 | `empty()` | 是否為空(`""/0/'0'/null/false/[]/\$a`) |
| 4 | `is_null()` | `NULL`: 賦值為`null`/未賦值/`unset()` |
## 5. 數據類型
變量的訪問方式,受以下條件的限制
| 序號 | 名稱 | 描述 |
| ---- | ---------- | -------------------------------------------- |
| 1 | 數據類型 | 主要有基本類型, 復用類型,特殊類型 |
| 2 | 作用域 | 變量的有效范圍,即可見性,查詢變量的工具 |
| 3 | 生命周期\* | 變量從創建到注銷的全過程(程序結束會自動注銷) |
- 確定了數據類型, 才可以確定數據的 "取值范圍" 與 "操作方式",所以非常重要
- 變量數據類型由值決定, 值的數據類型有三類:
### 5.1 基本類型
> 基本類型: 是構成復合類型的基本數據單元
| 序號 | 類型 | 標識符 | 檢測函數 | 舉例 |
| ---- | ------ | --------- | ------------- | ------------------ |
| 1 | 整數 | `integer` | `is_int()` | `150`, `999` |
| 2 | 浮點數 | `float` | `is_float()` | `3.14`, `.315` |
| 2 | 字符 | `string` | `is_string()` | `'php'`, `"email"` |
| 4 | 布爾 | `boolean` | `is_bool()` | `true`, `false` |
### 5.2 復合類型
| 序號 | 類型 | 標識符 | 檢測函數 | 舉例 |
| ---- | ---- | -------- | ------------- | ---------------- |
| 1 | 對象 | `object` | `is_object()` | `new stdClass()` |
| 2 | 數組 | `array` | `is_array()` | `$arr = [1,2,3]` |
### 5.3 特殊類型
| 序號 | 類型 | 標識符 | 檢測函數 | 舉例 |
| ---- | ---- | ---------- | --------------- | ----------------- |
| 1 | 空 | `null` | `is_object()` | `new stdClass()` |
| 2 | 資源 | `resource` | `is_resource()` | `$f = fopen(...)` |
示例代碼: `demo7.php`
```php
<?php
# 變量類型
// 基本類型
$name = '手機';
$price = 3890;
$is5G = true;
echo $name . '價格: ' . $price . ', 是否5G? ' . ($is5G ? '是' : '否') . '<br>';
// 復合類型
$obj = new stdClass;
$obj->email = 'admin@php.cn';
echo $obj->email, '<br>';
$arr = ['電腦', 8000, 'huawei'];
// print_r($arr);
echo '<pre>' . print_r($arr, true) . '</pre>';
// 特殊類型
$num = null;
var_dump($num);
$f = fopen('demo6.php', 'r');
var_dump($f);
// gettype(): 返回類型字符串
echo gettype($f);
```
### 5.4 類型查詢
- 類型檢測函數,如`is_int()`返回的都是一個布爾值
- `gettype()`: 返回類型的字符串表示
---
## 6 類型轉換
### 6.1 自動轉換
- 自動轉換: 表達式根據**操作符**, 將操作數轉為一致的數據類型后再進行運算
- 自動轉換, 通常只發生在 **基本類型** 參與的**算術或字符串**運算中
| 序號 | 類型 | 轉換規則 |
| ---- | --------- | ------------------------------ |
| 1 | `null` | `null => 0` |
| 2 | `boolean` | `true => 1`, `false => 0` |
| 3 | `string` | `123abc => 123`, `abc123 => 0` |
| 4 | `integer` | `int => float` |
### 6.2 強制轉換
- 強制轉換分為: **臨時轉換** 和 **永久轉換** 二種
- 臨時轉換, 可使用**類型提示符**,或者**類型函數**實現
使用**類型提示符**:
| 序號 | 類型 | 轉換規則 |
| ---- | ---------- | ---------- |
| 1 | `(int)` | 轉為整數 |
| 2 | `(float)` | 轉為浮點數 |
| 3 | `(string)` | 轉為字符串 |
| 4 | `(array)` | 轉為數組 |
| 5 | `(object)` | 轉為對象 |
使用**類型函數**:
| 序號 | 類型 | 轉換規則 |
| ---- | ------------ | ---------- |
| 1 | `intval()` | 轉為整數 |
| 2 | `floatval()` | 轉為浮點數 |
| 3 | `strval()` | 轉為字符串 |
| 4 | `boolval()` | 轉為布爾 |
- 永久轉換: 使用函數`settype($var , $type)`
示例代碼: `demo8.php`
```php
<?php
# 變量類型轉換
// 自動轉換
$a = null;
$b = true;
$c = false;
$d = '5g';
$e = 'php';
$f = 15;
echo $a + 10, '<br>';
echo $b + 10, '<br>';
// 字符串轉數值型會有警告,但代碼仍會執行, 推薦使用強制轉換
echo $d + 10, '<br>';
echo $e + 10, '<br>';
// 整數15轉為字符串'15'
echo $e . $f;
echo '<hr>';
// 強制轉換
// 轉換提示符: (int),(sgring)...
// (int)將$d強制轉為整數,不再有警告信息
echo (int) $d + 10, '<br>';
// intval()轉整數
echo intval($d) + 18, '<br>';
// strval($f)轉字符串
echo strval($f) . ' hello', '<br>';
// 以上通過提示符和函數完成的強制轉換,并不改變變量原始類型
// $f 依然是整數類型:integer
echo gettype($f), '<br>';
// settype()可將變量類型永久轉換
settype($f, 'string');
// $f 永久的成為字符串類型
echo gettype($f), '<br>';
```
---
## 7. 作用域
- 變量作用域,也叫"變量范圍", 即定義變量時的上下文環境
- 變量作用域,通俗的說,就是變量的生效范圍
- 一個變量必定屬于一個作用域, 這個作用域也包括了當前作用域中引入其它文件
- 也有不受作用域限制的變量,例如超全局變量, 在程序中任何地方都是有定義的
- 函數作用域: php 中只有函數可以創建作用域, 函數之外的代碼全部在全局空間中
| 序號 | 作用域 | 描述 |
| ---- | ---------- | -------------------------------- |
| 1 | 函數作用域 | 使用`function`關鍵字創建的作用域 |
| 2 | 全局作用域 | 函數之外的變量生效范圍 |
- php 中沒有**塊作用域**的概念, 這與其它編程語言不同, 請留意
- 根據作用域不同, 變量可以分為三類:
| 序號 | 變量類型 | 描述 |
| ---- | ---------- | --------------------------------- |
| 1 | 私有變量 | 函數中定義的變量 |
| 2 | 全局變量 | 函數之外定義的變量 |
| 3 | 超全局變量 | 也叫預定義變量,訪問不受作用域限制 |
- 超全局變量,也叫**超全局數組**,隨系統加載,因此在所有腳本中均有定義,全局和函數中都可以訪問
| 序號 | 變量名 | 描述 |
| ---- | ----------- | ------------------------------------------------------- |
| 1 | `$GLOBALS` | 引用全局作用域中可用的全部變量 |
| 2 | `$_SERVER` | 服務器和執行環境信息 |
| 3 | `$_GET` | HTTP GET 請求:通過 URL 參數傳遞給當前腳本的變量的數組 |
| 4 | `$_POST` | HTTP POST 請求: 將變量以關聯數組形式傳入當前腳本 |
| 5 | `$_FILES` | HTTP 文件上傳變量,保存著上傳文件的全部信息 |
| 6 | `$_COOKIE` | 通過 HTTP Cookies 方式傳遞給當前腳本的變量的數組 |
| 7 | `$_SESSION` | 當前腳本可用 SESSION 變量的數組 |
| 8 | `$_REQUEST` | 默認情況下包含了 `$_GET`,`$_POST` 和 `$_COOKIE` 的數組 |
| 9 | `$_ENV` | 通過環境方式傳遞給當前腳本的變量的數組 |
示例代碼: `demo9.php`
```php
# 變量作用域
// 全局作用域: 默認
$siteName = 'php中文網';
// 函數作用域
function getInfo()
{
// 函數中不能直接訪問全局變量
// $private = $siteName;
// 方法1: global 引入
global $siteName;
$local = $siteName;
// 訪問2: 使用超全局變量: $GLOBALS
$local = $GLOBALS['siteName'];
// 函數中訪問超全局變量
echo $_SERVER['SCRIPT_NAME'] . '<br>';
return $local;
}
// 全局中訪問函數私有變量: 未定義錯誤
echo getInfo(), '<br>';
// 全局中訪問超全局變量
echo $_SERVER['SCRIPT_NAME'];
/*
/demo9.php
php中文網
/demo9.php
*/
```
---
## 8. 靜態變量
### 8.1 基本常識
- 定義在函數中的靜態變量使用`static`修飾,并且與函數作用域綁定
- 靜態變量定義時必須初始化,且只能初始化一次,默認為`0`
- 當程序執行離開函數作用域后,靜態變量的值不丟失
- 靜態變量的值,可以在函數的多次調用中保持不變,即可帶入下次調用中
- 函數中靜態變量遵循私有變量約束, 全局不可訪問
### 8.2 應用場景
- 當多次調用同一函數,且要求每次調用之間共享或保留某些變量的時候
- 盡管全局變量也可以辦到,但沒必要, 采用局部靜態變量更合適
示例代碼: `demo10.php`
```php
# 靜態變量
namespace ns1;
function test1()
{
// $sum: 局部動態變量,每次調用都會初始化,無法在多次調用中保持不變
$sum = 0;
$sum = $sum + 1;
return $sum;
}
echo test1(), '<br>';
echo test1(), '<br>';
echo test1(), '<br>';
echo '<hr>';
namespace ns2;
// 全局變量
$sum = 0;
function test1()
{
// 通過全局變量,將每次的調用結果保存到全局中
global $sum;
$sum = $sum + 1;
return $sum;
}
echo test1(), '<br>';
echo test1(), '<br>';
echo test1(), '<br>';
echo '<hr>';
namespace ns3;
function test1()
{
// 靜態變量: 僅第一次調用時初始化,以后調用可保持原值
// 靜態變量: 可簡單理解為僅在函數中使用的"偽全局變量"
// 可以實現在函數的多次調用中的數據共享
static $sum = 0;
$sum = $sum + 1;
return $sum;
}
echo test1(), '<br>';
echo test1(), '<br>';
echo test1(), '<br>';
```
---
## 9. 變量過濾器
- PHP 過濾器用于驗證和過濾來自非安全來源的外部數據
- 外部數據來源:
| 序號 | 數據來源 | 描述 |
| ---- | -------------- | ---------------------- |
| 1 | 表單 | 來自表音的用戶輸入數據 |
| 2 | Cookies | 來自瀏覽器中的 cookie |
| 3 | 服務器變量 | 防止偽裝的合法訪問 |
| 4 | Web 服務數據 | Web 請求的數據 |
| 5 | 數據庫查詢結果 | 數據表中的數據并不可信 |
- 常用的過濾器函數
| 序號 | 函數 | 描述 |
| ---- | ---------------------- | ------------------------ |
| 1 | `filter_list()` | |
| 2 | `filter_id()` | |
| 3 | `filter_var()` | 過濾單個變量 |
| 4 | `filter_var_array()` | 過濾多個變量 |
| 5 | `filter_has_var()` | 檢測是否存在某個外部變量 |
| 6 | `filter_input()` | 過濾單個外部變量 |
| 7 | `filter_input_array()` | 過濾多個外部變量 |
- 外部變量類型: `INPUT_GET`, `INPUT_POST`, `INPUT_COOKIE`, `INPUT_SERVER`, `INPUT_ENV`
- 過濾器主要分為二類: **驗證過濾器**, **清理過濾器**
### 9.1 驗證過濾器常量
- 驗證過濾器: 又叫"驗證器", 主要用于數據的類型和格式驗證
| 序號 | 過濾器函數 | 描述 |
| ---- | ------------------------- | ------------- |
| 1 | `FILTER_VALIDATE_INT` | 驗證整數 |
| 2 | `FILTER_VALIDATE_FLOAT` | 浮點點驗證 |
| 3 | `FILTER_VALIDATE_BOOLEAN` | 驗證布爾項 |
| 4 | `FILTER_VALIDATE_EMAIL` | 驗證郵箱 |
| 5 | `FILTER_VALIDATE_URL` | 驗證 URL 地址 |
| 6 | `FILTER_VALIDATE_IP` | 驗證 IP 地址 |
| 7 | `FILTER_VALIDATE_REGEXP` | 正則驗證 |
- `FILTER_VALIDATE_BOOLEAN`: 布爾選項的返回值類型
| 序號 | 返回值 | 描述 |
| ---- | ------- | ----------------------------- |
| 1 | `true` | "1", "true", "on" 和 "yes" |
| 2 | `false` | "0", "false", "off", "no", "" |
| 3 | `null` | 除以上情形外 |
### 9.2 清理過濾器常量
- 清理過濾器: 去掉非法字符,僅保留指定內容
| 序號 | 過濾器函數 | 描述 |
| ---- | ------------------------------- | -------------------------------------------- |
| 1 | `FILTER_UNSAFE_RAW` | 保持原始數據 |
| 2 | `FILTER CALLBACK` | 自定義函數過濾數據 |
| 3 | `FILTER_SANITIZE_STRING` | 去除標簽以及特殊字符:`strip_tags()` |
| 4 | `FILTER_SANITIZE_STRIPPED` | "string" 過濾器別名 |
| 5 | `FILTER_SANITIZE_ENCODED` | URL-encode 字符串,去除或編碼特殊字符 |
| 6 | `FILTER_SANITIZE_SPECIAL_CHARS` | HTML 轉義字符, 等價于 `htmlspecialchars()` |
| 7 | `FILTER_SANITIZE_EMAIL` | 僅保留郵箱地址的合法字符 |
| 8 | `FILTER_SANITIZE_URL` | 僅保留合法的 URL 字符串 |
| 9 | `FILTER_SANITIZE_NUMBER_INT` | 僅保留合法的數字和正負號`+-` |
| 10 | `FILTER_SANITIZE_NUMBER_FLOAT` | 僅保留合法的數字和正負號`+-` 以及指數 `.,eE` |
| 11 | `FILTER_SANITIZE_MAGIC_QUOTES` | 等價于函數: `addslashes()` |
### 9.3 選項與標志
- 可以對過濾器設置選項和標志, 對數據進行更加精準的過濾處理
- 選項與標志使用數組鍵名表示: `'options'=>[...], 'flags'=>...`(復數)
- 舉例:
```php
filter_var($int, FILTER_VALIDATE_INT, ['options'=>['min_range'=>10,'max_range'=>80]]);
filter_var($data, FILTER_VALIDATE_EMAIL, ['flags'=>FILTER_REQUIRE_SCALAR]);
```
示例代碼: `demo11.php`
```php
<?php
# 變量過濾器
// filter_list(): 查看支持的所有過濾器
// filter_id(): 返回過濾器常量對應的ID
foreach (filter_list() as $filter) {
// echo $filter . ' => ' . filter_id($filter) . '<br>';
}
echo '<hr>';
// 1. filter_var(): 過濾單個變量
$age = 30;
var_dump(filter_var($age, FILTER_VALIDATE_INT));
// 驗證時,會將變量值轉為字符串類型, 所以這樣寫也對
$age = '30';
var_dump(filter_var($age, FILTER_VALIDATE_INT));
echo '<br>';
// 還可以添加第三個參數,對過濾器行為進行限定
// 被過濾的數據也支持字面量,但不推薦這樣
var_dump(filter_var(10, FILTER_VALIDATE_INT, ['options' => ['min_range' => 18, 'max_range' => 60]]));
var_dump(filter_var(40, FILTER_VALIDATE_INT, ['options' => ['min_range' => 18, 'max_range' => 60]]));
echo '<br>';
// 既可以使用過濾器常量,也可以使用過濾器ID
$email = 'admin@php.cn';
// 過濾器常量
var_dump(filter_var($email, FILTER_VALIDATE_EMAIL));
echo '<br>';
// 過濾器ID
var_dump(filter_var($email, 274));
echo '<br>';
var_dump(filter_var('peter@qq.com', 274));
echo '<br>';
// 2. filter_var_array():過濾多個變量
$a = 10;
$b = 'php';
// 返回值是數組, 驗證失敗返回false,成功返回原值
var_dump(filter_var_array([$a, $b], FILTER_VALIDATE_INT));
echo '<br>';
// 對于多變量驗證最好將數組放在數組中統一處理
$data = [$a, $b, 'html', [6, 7, 8], 150, 200];
var_dump(filter_var_array($data, FILTER_VALIDATE_INT));
// 過濾掉驗證未通過的元素
var_dump(array_filter(filter_var_array($data, FILTER_VALIDATE_INT)));
echo '<hr>';
// 3. filter_has_var(): 檢測是否存在指定類型的外部變量
// 變量類型僅限:INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER, INPUT_ENV
var_dump(filter_has_var(INPUT_GET, 'id'));
echo '<br>';
//4. filter_input(): 通過名稱獲取特定的外部變量,并且可以通過過濾器處理它
// 變量類型僅限:INPUT_GET, INPUT_POST, INPUT_COOKIE, INPUT_SERVER, INPUT_ENV
// false:驗證失敗, null: 變量不存在, 成功返回當前值
// $_GET['id'] 必須是大于1的整數
$res = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT, ['options' => ['min_range' => 1]]);
var_dump($res);
echo '<hr>';
// 5. filter_input_array(): 同時驗證多個外部變量
// 為一組數據應用統一過濾器
var_dump(filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING));
// 為每一個元素應用不同的過濾器
// 設置變量對應過濾器
$args = [
'username' => FILTER_SANITIZE_STRING,
'email' => FILTER_VALIDATE_EMAIL,
'age' => ['filter' => FILTER_VALIDATE_INT, 'flags'=>FILTER_REQUIRE_SCALAR, 'options' => ['min_range' => 18]],
'blog' => FILTER_VALIDATE_URL,
];
var_dump(filter_input_array(INPUT_GET, $args));
```