## php文件加載有四種語句:
1. include
2. require
3. include_once
4. require_once
**方法詳解:**
1. `include` 語句包含并運行指定文件。
2. `require` 和 `include` 幾乎完全一樣,除了處理失敗的方式不同之外。`require` 在出錯時產生 `E_COMPILE_ERROR`(編譯致命錯誤 64 編譯時致命性錯。這就像由Zend腳本引擎生成了一個 `E_ERROR`。) 級別的錯誤。換句話說將導致腳本中止而 `include` 只產生警告(`E_WARNING`),腳本會繼續運行。
3. `include_once` 語句在腳本執行期間包含并運行指定文件。此行為和 `include` 語句類似,唯一區別是如果該文件中已經被包含過,則不會再次包含。如同此語句名字暗示的那樣,只會包含一次。可以用于在腳本執行期間同一個文件有可能被包含超過一次的情況下,想確保它只被包含一次以避免函數重定義,變量重新賦值等問題。
4. `require_once` 語句和 `require` 語句完全相同,唯一區別是 `PHP` 會檢查該文件是否已經被包含過,如果是則不會再次包含。
**總結:**
1. `include` 和 `require` 語句都是包含并運行指定文件,不同的是處理失敗的方式不同,所以一般 require 用于加載重要文件,比如加載框架的引導文件,如果出錯將終止程序,`include` 一般用于加載配置文件或者第三方擴展庫等,比如 `composer` 就是用的 `include` 加載文件的。
2. `include_once` 和 `require_once` 語句與 `include` 和 `require` 語句的不同就是,如果該文件已經包含過就不會再次包含了,這在避免文件重復加載,函數重定義,變量重新賦值等問題上有用,但是一定程度上會有性能損耗問題,畢竟需要檢查是否加載過。所以一般確定的情況下會優先使用 `include` 和 `require` ,而不是 `include_once` 和 `require_once` 語句。
* * * * *
### 實驗
**擴展知識:**
包含文件的語句會受`php.ini` 和 `include_path`(;include_path = ".:/php/includes")配置項影響,相關函數:
- `ini_set()` - 為一個配置選項設置值
- `set_include_path` - 設置當前的 `include_path` 配置選項
- `get_include_path()` - 獲取當前的 `include_path` 配置選項
- `restore_include_path()` - 還原 `include_path` 配置選項的值
1. 直接引入(包含)文件默認是以上面set_include_path設置的目錄為環境目錄,環境目錄找不到再從當前目錄找
2. /表示服務器根目錄,linux上面直接表示磁盤根目錄,Windows下面表示某個磁盤根目錄例如D:\\\\,`realpath()`可以返回絕對路徑。
3. ./表示當前運行文件的同級目錄(入口),而不是當前腳本所在的目錄(include 語句所在腳本文件的目錄)
4. 如果以相對于當前腳本文件引用文件請用\__DIR\__常量
>[danger] **注意:第一種情況,請小心了!這個一般表示從當前目錄找,但是什么是當前目錄呢?這個不同情況是不同的,它會先把當前運行文件的目錄當成當前目錄,如果找不到,再把當前腳本所在的目錄當成當前目錄,從當前腳本所在目錄開始找,如果還找不到就報錯,引入文件不存在。**
>[info] 所以如果意圖清楚,最好是使用最后兩種方式引入文件,這樣能減少不必要的麻煩,另外使用絕對路徑比使用相對路徑加載文件性能更高,這樣能避免系統去解析相對路徑而耗費一些時間。
**當前運行文件**,**當前腳本**,請注意仔細理解它們的差別,前者作為入口運行,后者則被腳本通過引用的方式調用。魔術常亮`\__FILE\__`,`\__DIR\__` 就是后者的文件名(包含完整的絕對路徑)和目錄。
* * * * *
**關于路徑的其他引申**
PHP腳本這種文件相互引用包含的關系可和網頁中靜態文件css中的`../`路徑不同,css中的路徑之和所在css文件url路徑相關,和網頁沒有半毛錢關系,網頁只是加載它而已,但是如果css中使用`/`那情況就不同了,一般`/`為根域名,再說一遍,靜態文件中除了`/`其他的路徑都是相對于當前靜態文件的,和網頁地址沒有關系。網頁中的`./`和`/`則是相對于當前url路徑(對于pathinfo也沒有關系,不會受影響,認不出是假目錄的)和根域。
還可以通過注冊自動加載方法來實現自動加載,框架大部分都實現了自動加載,不然手動寫包含語句不利于維護,太麻煩。
----
### 包含變量作用域問題
```php
// a.php
<?php
$a = 1;
function fa()
{
global $b;
echo 'fa.b: ' . $b . PHP_EOL;
}
// include 'b.php';
function i()
{
$c = 1;
include 'b.php';
}
i();
function fa2()
{
global $b;
echo 'fa2.b: ' . $b . PHP_EOL;
}
echo 'a.a: ' . $a . PHP_EOL;
echo 'a.b: ' . $b . PHP_EOL;
fa();
fa2();
fb2();
// 輸出結果:
// b.b: 2
// b.a: 1
// fb.b: 2
// fb2.a: 1
// a.a: 1
// a.b: 2
// fa.b: 2
// fa2.b: 2
// fb2.a: 1
// b.php
<?php
$b = 2;
function fb()
{
global $b;
echo 'fb.b: ' . $b . PHP_EOL;
}
function fb2()
{
global $a;
echo 'fb2.a: ' . $a . PHP_EOL;
}
echo 'b.b: ' . $b . PHP_EOL;
echo 'b.a: ' . $a . PHP_EOL;
echo 'b.c: ' . $c . PHP_EOL;
fb();
fb2();
```
#### 結論
如果包含發生在函數內部,則 包含文件中的 變量作用域處于 該函數內部,函數不受影響 還是全局的。
如果包含不是發生在函數內部,則 包含文件中的 變量作用域處于 全局,這點和預期一致。
#### 擴展思考
到目前為止我們發現,所有程序都會有一個唯一的啟動入口,也就是只會有一個啟動入口文件(注意這不是指web應用的單入口文件,而是指程序啟動的首個入口文件,并不泛指某個應用入口文件),不會有兩個,程序是從一個入口開始啟動的,不會由兩個入口共同啟動程序。我們猜想進程是不是也是這樣的,任何程序最開始都是從一個程序入口啟動的,哪怕它是多進程多線程的程序,最開始也都是從一個入口啟動的。
#### 結論
如果包含發生在函數內部,則 包含文件中的 變量作用域處于 該函數內部,函數不受影響 還是全局的。
如果包含不是發生在函數內部,則 包含文件中的 變量作用域處于 全局,這點和預期一致。
#### 擴展思考
到目前為止我們發現,所有程序都會有一個唯一的啟動入口,也就是只會有一個啟動入口文件(注意這不是指web應用的單入口文件,而是指程序啟動的首個入口文件,并不泛指某個應用入口文件),不會有兩個,程序是從一個入口開始啟動的,不會由兩個入口共同啟動程序。我們猜想進程是不是也是這樣的,任何程序最開始都是從一個程序入口啟動的,哪怕它是多進程多線程的程序,最開始也都是從一個入口啟動的。
last update:2018-1-27 01:26:59
- 開始
- 公益
- 更好的使用看云
- 推薦書單
- 優秀資源整理
- 技術文章寫作規范
- SublimeText - 編碼利器
- PSR-0/PSR-4命名標準
- php的多進程實驗分析
- 高級PHP
- 進程
- 信號
- 事件
- IO模型
- 同步、異步
- socket
- Swoole
- PHP擴展
- Composer
- easyswoole
- php多線程
- 守護程序
- 文件鎖
- s-socket
- aphp
- 隊列&并發
- 隊列
- 講個故事
- 如何最大效率的問題
- 訪問式的web服務(一)
- 訪問式的web服務(二)
- 請求
- 瀏覽器訪問阻塞問題
- Swoole
- 你必須理解的計算機核心概念 - 碼農翻身
- CPU阿甘 - 碼農翻身
- 異步通知,那我要怎么通知你啊?
- 實時操作系統
- 深入實時 Linux
- Redis 實現隊列
- redis與隊列
- 定時-時鐘-阻塞
- 計算機的生命
- 多進程/多線程
- 進程通信
- 拜占庭將軍問題深入探討
- JAVA CAS原理深度分析
- 隊列的思考
- 走進并發的世界
- 鎖
- 事務筆記
- 并發問題帶來的后果
- 為什么說樂觀鎖是安全的
- 內存鎖與內存事務 - 劉小兵2014
- 加鎖還是不加鎖,這是一個問題 - 碼農翻身
- 編程世界的那把鎖 - 碼農翻身
- 如何保證萬無一失
- 傳統事務與柔性事務
- 大白話搞懂什么是同步/異步/阻塞/非阻塞
- redis實現鎖
- 淺談mysql事務
- PHP異常
- php錯誤
- 文件加載
- 路由與偽靜態
- URL模式之分析
- 字符串處理
- 正則表達式
- 數組合并與+
- 文件上傳
- 常用驗證與過濾
- 記錄
- 趣圖
- foreach需要注意的問題
- Discuz!筆記
- 程序設計思維
- 抽象與具體
- 配置
- 關于如何學習的思考
- 編程思維
- 談編程
- 如何安全的修改對象
- 臨時
- 臨時筆記
- 透過問題看本質
- 程序后門
- 邊界檢查
- session
- 安全
- 王垠
- 第三方數據接口
- 驗證碼問題
- 還是少不了虛擬機
- 程序員如何談戀愛
- 程序員為什么要一直改BUG,為什么不能一次性把代碼寫好?
- 碎碎念
- 算法
- 實用代碼
- 相對私密與絕對私密
- 學習目標
- 隨記
- 編程小知識
- foo
- 落盤
- URL編碼的思考
- 字符編碼
- Elasticsearch
- TCP-IP協議
- 碎碎念2
- Grafana
- EFK、ELK
- RPC
- 依賴注入
- 開發筆記
- 經緯度格式轉換
- php時區問題
- 解決本地開發時調用遠程AIP跨域問題
- 后期靜態綁定
- 談tp的跳轉提示頁面
- 無限分類問題
- 生成微縮圖
- MVC名詞
- MVC架構
- 也許模塊不是唯一的答案
- 哈希算法
- 開發后臺
- 軟件設計架構
- mysql表字段設計
- 上傳表如何設計
- 二開心得
- awesomes-tables
- 安全的代碼部署
- 微信開發筆記
- 賬戶授權相關
- 小程序獲取是否關注其公眾號
- 支付相關
- 提交訂單
- 微信支付筆記
- 支付接口筆記
- 支付中心開發
- 下單與支付
- 支付流程設計
- 訂單與支付設計
- 敏感操作驗證
- 排序設計
- 代碼的運行環境
- 搜索關鍵字的顯示處理
- 接口異步更新ip信息
- 圖片處理
- 項目搭建
- 閱讀文檔的新方式
- mysql_insert_id并發問題思考
- 行鎖注意事項
- 細節注意
- 如何處理用戶的輸入
- 不可見的字符
- 抽獎
- 時間處理
- 應用開發實戰
- python 學習記錄
- Scrapy 教程
- Playwright 教程
- stealth.min.js
- Selenium 教程
- requests 教程
- pyautogui 教程
- Flask 教程
- PyInstaller 教程
- 蜘蛛
- python 文檔相似度驗證
- thinkphp5.0數據庫與模型的研究
- workerman進程管理
- workerman網絡分析
- java學習記錄
- docker
- 筆記
- kubernetes
- Kubernetes
- PaddlePaddle
- composer
- oneinstack
- 人工智能 AI
- 京東
- pc_detailpage_wareBusiness
- doc
- 電商網站設計
- iwebshop
- 商品規格分析
- 商品屬性分析
- tpshop
- 商品規格分析
- 商品屬性分析
- 電商表設計
- 設計記錄
- 優惠券
- 生成唯一訂單號
- 購物車技術
- 分類與類型
- 微信登錄與綁定
- 京東到家庫存系統架構設計
- crmeb
- 命名規范
- Nginx https配置
- 關于人工智能
- 從人的思考方式到二叉樹
- 架構
- 今日有感
- 文章保存
- 安全背后: 瀏覽器是如何校驗證書的
- 避不開的分布式事務
- devops自動化運維、部署、測試的最后一公里 —— ApiFox 云時代的接口管理工具
- 找到自己今生要做的事
- 自動化生活
- 開源與漿果
- Apifox: API 接口自動化測試指南