摘要:錯誤是運行期間的嚴重問題,通常是因為代碼出錯而造成,必須要修正它,否則會使停止執行。警告是非致命錯誤,程序執行也不會因此而中止。
前言
近期因公司內部轉崗,開始參與PHP項目進行后端開發,一直都是強類型寫的比較多,弱類型語言也有接觸了一些,如:nodejs,python,做一些輔助服務,數據采集的事情,剛好內部有這個機會進行可以學以致用,加上之前對后端的理解和經驗,很容易上手,這里記錄下開發過程遇到的些問題解決方案和自己對PHP的理解,以及項目中的部分架構
當前已經進入PHP7的版本,做了很多的調整,尤其在性能上有很大的提升面向對象
PHP框架內置很多強大函數,超級全局變量,魔術函數,魔術變量,可以通過提供的內置函數對PHP項目進行拓展,數據類型操作,http信息獲取等,通過安裝拓展添加各種功能支持,框架內置函數調用大部分還是偏向面向過程,通過調用函數,傳入要操作的類型數據和依賴數據,這里剛開始有些不習慣,面向對象的開發中習慣直接 類型變量/對象 點出函數。
現在PHP開發可以選擇使用面向過程也可以用面向對象,最早PHP版本不支持面向對象特性,PHP5開始對OOP有良好的支持,很多PHP開發者沒有系統性的學習OOP相關知識,包括工齡長的PHP開發者或者老的項目很多還是偏向面向過程開發,所以會接觸到很多偏向面向過程開發的項目
在項目開發過程中遇到些偏應用業務開發的項目,看似有用到類,但是并沒用到面向對象的特性對業務進行抽象,如:項目中每個業務功能有個php文件對應一個類,類里里大部分都是邏輯function,然后通過拓展autoload,實現自動include php文件,比如通過L函數傳入要調用的類名,構造出PHP文件路徑,進行include,然后返回類實例對象,只是通過類文件來區分功能函數,并沒有使用到面向對象的特性進行封裝,還是偏向面向過程思路在開發
PHP5開始對OOP提供了良好支持,基本已經和java,C# 面向對象語法相似,可以使用命名空間,封裝interface,abstract,多態:implements,extends,PHP7還支持多繼承trait,方便封裝些公用的功能,通過PSR4規范,引入composer 實現的autoload,可以很好的進行OOP開發
PHP開發還是比較靈活,可以面向過程也可以面向對象,根據具體的業務場景設計
使用composer psr4
在項目中添加composer.json文件,根據自己需求配置
{ "autoload": { "psr-4": { "Library": "library/" } } }
在composer.json文件所在目錄下輸入命令,就會自動 download vendor/composer autoload 相關文件
composer install
php中的入口index include autoload.php
include_once "vendor/autoload.php";
注意,配置修改,內容變更的時候需要執行
composer dump-autoload -o
在剛學習PHP語法的時候比較不習慣的就是弱類型,不用去定義變量類型,參數類型,返回值類型,對于習慣強類型的童鞋開始會有些不習慣,不定義類型心里怪怪的,總感覺哪里會導致些錯誤,而且弱類型在編碼的過程中IDE不會有類型錯誤的一些提示,只有在運行的時候報錯了才能知道這里錯誤了,錯誤提示滯后。尤其是從DB查詢數據返回的是一個stdclass/array,獲取到的數據沒有對應一個實體類,無法知道具體數據有哪些字段,需要通過查詢的sql語句,然后通過查看表結構才能知道數據字段信息,這點很難受,影響開發效率
PHP現在已經支持typehint,通過定義類型可以對部分確定的類型變量,參數,返回類型進行強類型的定義,尤其需要定義表數據Model類,這樣得到數據對象后通過->可以感知出所有數據字段,方便后續拓展開發和維護
根據場景使用,不能說因為自己習慣使用強力型就把所有類型定義都寫成強類型
/** * Class MJop * @property int $id 工作ID * @property string $name 工作名字 * @property int $salary 薪水 */ class MJop { } /** * Class MWorker * @property string $name 員工名字 * @property int $age 年齡 * @property MJop $jop 工作 */ class MWorker { } class Worker { /** * 獲取員工信息 * @param int $id * @return MWorker|stdClass */ public function get(int $id): stdClass { // mysql select return new stdClass(); } } class Logic { /** * 獲取員工描述 * @param int $workId * @return string */ public function Desc(int $workId): string { $worker = new Worker(); $mWorker = $worker->get($workId); return "名字:" . $mWorker->name . ",年齡:" . $mWorker->age . ",工作:" + $mWorker->jop->name . ",薪水:" . $mWorker->jop->salary; } }
通過定義變量類型得到代碼感知
/** @var Logic $logic */ $logic=new Logic();
因為PHP是弱類型原因,在做類型比較的時候,往往會因為一個不小心就掉坑里,下面列出類型函數和類型比較的表格
就問你,看到這些表格怕不怕,心中有一萬只草泥馬奔騰而過,瞬間變成幽怨的小眼神
使用 PHP 函數對變量 $x 進行比較
表達式 | gettype() | empty() | is_null() | isset() | boolean : if($x) |
---|---|---|---|---|---|
$x = ""; | string | TRUE | FALSE | TRUE | FALSE |
$x = null; | NULL | TRUE | TRUE | FALSE | FALSE |
var $x; | NULL | TRUE | TRUE | FALSE | FALSE |
$x is undefined | NULL | TRUE | TRUE | FALSE | FALSE |
$x = array(); | array | TRUE | FALSE | TRUE | FALSE |
$x = false; | boolean | TRUE | FALSE | TRUE | FALSE |
$x = true; | boolean | FALSE | FALSE | TRUE | TRUE |
$x = 1; | integer | FALSE | FALSE | TRUE | TRUE |
$x = 42; | integer | FALSE | FALSE | TRUE | TRUE |
$x = 0; | integer | TRUE | FALSE | TRUE | FALSE |
$x = -1; | integer | FALSE | FALSE | TRUE | TRUE |
$x = "1"; | string | FALSE | FALSE | TRUE | TRUE |
$x = "0"; | string | TRUE | FALSE | TRUE | FALSE |
$x = "-1"; | string | FALSE | FALSE | TRUE | TRUE |
$x = "php"; | string | FALSE | FALSE | TRUE | TRUE |
$x = "true"; | string | FALSE | FALSE | TRUE | TRUE |
$x = "false"; | string | FALSE | FALSE | TRUE | TRUE |
松散比較 ==
類型 | TRUE | FALSE | 1 | 0 | -1 | "1" | "0" | "-1" | NULL | array() | "php" | "" |
---|---|---|---|---|---|---|---|---|---|---|---|---|
TRUE | TRUE | FALSE | TRUE | FALSE | TRUE | TRUE | FALSE | TRUE | FALSE | FALSE | TRUE | FALSE |
FALSE | FALSE | TRUE | FALSE | TRUE | FALSE | FALSE | TRUE | FALSE | TRUE | TRUE | FALSE | TRUE |
1 | TRUE | FALSE | TRUE | FALSE | FALSE | TRUE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE |
0 | FALSE | TRUE | FALSE | TRUE | FALSE | FALSE | TRUE | FALSE | TRUE | FALSE | TRUE | TRUE |
-1 | TRUE | FALSE | FALSE | FALSE | TRUE | FALSE | FALSE | TRUE | FALSE | FALSE | FALSE | FALSE |
"1" | TRUE | FALSE | TRUE | FALSE | FALSE | TRUE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE |
"0" | FALSE | TRUE | FALSE | TRUE | FALSE | FALSE | TRUE | FALSE | FALSE | FALSE | FALSE | FALSE |
"-1" | TRUE | FALSE | FALSE | FALSE | TRUE | FALSE | FALSE | TRUE | FALSE | FALSE | FALSE | FALSE |
NULL | FALSE | TRUE | FALSE | TRUE | FALSE | FALSE | FALSE | FALSE | TRUE | TRUE | FALSE | TRUE |
array() | FALSE | TRUE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | TRUE | TRUE | FALSE | FALSE |
"php" | TRUE | FALSE | FALSE | TRUE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | TRUE | FALSE |
"" | FALSE | TRUE | FALSE | TRUE | FALSE | FALSE | FALSE | FALSE | TRUE | FALSE | FALSE | TRUE |
嚴格比較 ===
類型 | TRUE | FALSE | 1 | 0 | -1 | "1" | "0" | "-1" | NULL | array() | "php" | "" |
---|---|---|---|---|---|---|---|---|---|---|---|---|
TRUE | TRUE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE |
FALSE | FALSE | TRUE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE |
1 | FALSE | FALSE | TRUE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE |
0 | FALSE | FALSE | FALSE | TRUE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE |
-1 | FALSE | FALSE | FALSE | FALSE | TRUE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE |
"1" | FALSE | FALSE | FALSE | FALSE | FALSE | TRUE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE |
"0" | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | TRUE | FALSE | FALSE | FALSE | FALSE | FALSE |
"-1" | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | TRUE | FALSE | FALSE | FALSE | FALSE |
NULL | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | TRUE | FALSE | FALSE | FALSE |
array() | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | TRUE | FALSE | FALSE |
"php" | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | TRUE | FALSE |
"" | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | FALSE | TRUE |
參考官方類型比較文檔
剛接觸PHP看到這幾個表格的時候會有點兒暈,開發的時候需要特別注意下類型比較,對等比較盡量用"===",一些函數類型已經能夠確定不會傳遞多類型參數,就可以強制類型進行限制,后面熟練度上來再看這個表格就感覺也還好,常用的類型之間的比較已經深深的進入到腦海中
IDE沒辦法給定義的變量進行錯誤提示,因為沒有定義類型IDE也不清楚定義變量的類型,沒辦法做錯誤提醒,往往需要在運行的時候輸出到頁面上才能發現問題
PHP弱類型引發的漏洞實例
上面說了這么多弱類型下的問題,這里說下弱類型的優點,弱類型一個明顯的優勢就是靈活
PHP動態特性,可以動態實例化,動態添加屬性,動態調用函數,等,通過這些特性可以用簡單的代碼封裝出強大的功能
簡單舉栗子:
name . ",發量:" . $this->hair; if (!empty($this->age)) $desc = $desc . ",年齡:" . $this->age; echo $desc . " "; } /** * 數據邏輯處理 * @param $condition * @return bool|string */ public function handle($condition) { if (is_int($condition)) { // ... ... 邏輯 return "數字處理結果"; } else if (is_string($condition)) { // ... ... 邏輯 return "字符串處理結果"; } else if (is_array($condition)) { // ... ... 邏輯 return "數組處理結果"; } else { return false; } } } // -----動態添加對象屬性----- $xm = new Developer(); $xm->name = "碼圣"; $xm->hair = 80; // 方式1 - 變量作為屬性名 // $fieldAge = "age"; // $developer->$fieldAge = 20; // 方式2 - 直接設置屬性值 $xm->age = 20; // -----動態調用對象函數----- // 變量作為函數名調用 $fn = "introduce"; if (method_exists($xm, $fn)) $xm->$fn(); // -----動態實例化----- // 方式1 - 變量作為類名進行實例化 $className = "Developer"; /** @var Developer $xf */ $xf = new $className(); $xf->name = "小方"; $xf->hair = 30; $xf->introduce(); // ------屬性遍歷------ foreach ($xf as $key => $val) { echo $key . "=" . $val . " "; } // ------參數類型和返回值支持多類型------ $rs = $xf->handle(null); if ($rs === false) { echo "處理失敗"; } else { echo $rs; } // ------函數變量------ $fn = function () { echo "do something"; }; $fn();
PHP WEB服務端開發,服務器部署多依賴fastcgi進程管理器,static變量和C#包括java生命周期不一樣,C#/java 的WEB應用服務進程靜態變量是常駐在內存里并且共享,PHP大多使用nginx部署fastcgi進程管理,服務器接收請求的進程是彼此獨立的,請求響應完了就回收資源,不存在常駐。
當然PHP也是可以內存常駐的,cli(命令行模式)下內存是常駐,swoole框架開發部署的WEB應用服務也是內存常駐
以往在C#開發的時候,執行遇到錯誤會直接拋出異常,try catch 可以捕獲錯誤異常,出現異常不會繼續執行后面的內容,PHP會比較不一樣,根據不同的錯誤級別不一樣的執行機制
PHP 有幾個錯誤嚴重性等級。三個最常見的的信息類型是錯誤(error)、通知(notice)和警告(warning)。它們有不同的嚴重性: E_ERROR、E_NOTICE和E_WARNING。錯誤是運行期間的嚴重問題,通常是因為代碼出錯而造成,必須要修正它,否則會使 PHP停止執行。通知是建議性質的信息,是因為程序代碼在執行期有可能造成問題,但程序不會停止。 警告是非致命錯誤,程序執行也不會因此而中止。
PHP 可以控制錯誤是否在屏幕上顯示(開發時比較有用)或隱藏記錄日志(適用于正式環境)
更改錯誤報告行為:
# 方式1:配置php.ini error_reporting=E_ALL & ~E_NOTICE
//方式2:函數調用設置報錯級別 error_reporting(E_ALL & ~E_NOTICE);
行內錯誤抑制:
錯誤控制操作符 @ 來抑制特定的錯誤。將這個操作符放置在表達式之前,其后的任何錯誤都不會出現。
php的Error與Exception捕獲問題:
Error是檢測到的這個問題極有可能使程序無法繼續運行,而Exception則是雖然有問題但是程序繼續運行不受影響。在php7以前的版本中Error類型是不能被捕獲的,僅僅可以捕獲Exception類型。php7以后Error與Exception都繼承了Throwable接口,使得Error被捕獲成為可能,在php7以下的版本也可以捕獲Error
register_shutdown_function 注冊一個 callback ,它會在腳本執行完成或者 exit() 后被調用。
set_error_handler 自己定義的方式來處理運行中的錯誤
set_exception_handler 設置默認的異常處理程序,用于沒有用 try/catch 塊來捕獲的異常
連接池
涉及數據庫開發過程中一般都會用到連接池,通過使用連接池減少每次需要重新建立連接的時間消耗提高數據操作效率,在高并發業務場景下效果尤為明顯,因為目前大部分PHP應用服務都是使用fastcgi的進程管理,每個請求服務器會分配進程去處理,返回結果后進程資源就會自動回收,因為這個因素無法建立連接池
方式1:
fastcgi模式下目前比較合理的方式就是通過單例模式,保證在當前請求操作下的數據連接只創建一個對象方式2:
可以通過swoole拓展實現數據連接池服務,傳遞sql到服務里執行返回數據,swoole內存常駐,應用客戶端連接斷開連接池服務進程資源不會自動回收
多線程 協程多線程
線程(thread) 是操作系統能夠進行運算調度的最小單位。它被包含在進程之中,是進程中的實際運作單位。一個線程指的是進程中一個單一順序的控制流,一個進程中可以并發多個線程,每條線程并行執行不同的任務
pthread擴展
適用于cli
多帶帶配置php-cli.ini
swoole
是一個底層網絡庫
gearman
實現了一個 Master-Worker 的模型
分布式任務分發
教程
workerman
php 實現的一個網絡庫
協程
線程是由操作系統內核進行調度的,我們無法干預,協程是用戶態程序,相當于應用程序自己進行了調度。
因為它是用戶態程序,所以相當于多個協程會運行在一個線程中。
要注意的是,只有內核對線程的調度才能夠利用cpu的多核資源,讓程序做到并行,所以在一個線程中的多個協程,是無法做到并行的。
用戶態和內核態:
簡單一句話,程序執行時,如果執行的是我們編寫的應用程序的代碼,這些代碼就是運行在用戶態的;當代碼中調用了系統調用后,接下來內核中的代碼就會執行,內核中的代碼就是運行在內核態的swoole 4.0 全新的協程內核
應用服務器架構服務部署:
php7+nginx+php-fpm
gitlab代碼托管,自動發布環境
ELK日志服務
Elasticsearch 搜索引擎
Logstash/Filebeat 用戶日志處理
Kibana 用于對存儲在Elasticsearch里的結構化數據做可視化展現
mysql
根據業務分布式集群
redis
codis 分布式部署
mongodb
kafaka
日志記錄,BI處理
代碼托管和測試環境:
均使用阿里云服務器,代碼托管自建gitlab服務,從開發分支合并到gitlab環境分支自動部署到對應環境服務器上
測試環境
test-app.sflyq.com
測試數據庫
公司內網訪問
gitlab release
預發環境
yf-app.sflyq.com
生產數據庫
公司內網訪問
gitlab simulation
生產環境
app.sflyq.com
gitlab master
本地測試環境
通過docker部署
最近階段感悟從一個熟悉的語言到另一個相對陌生的語言,語言只是工具,在適合的場景下使用適合的工具,從自己熟悉的業務到陌生的業務,離開自己的舒服區,擁抱變化才能成長
在相同的后端領域切換語言學習成本還是比較低的,主要是對后端開發的思路,經驗是可以共用的,只是換了個語言去實現
當公司發展到一定的規模,崗位職能區分的很細,做應用開發的童鞋接觸不到服務器架構,沒有機會接觸職能以外的技術,工作內容除了完成業務需求開發,還是業務需求開發,這樣常年開發下去對個人成長的局限性很高,需要自己在工作之余進行拓展,對公司內部有興趣的技術進行了解和學習,耐心等待機會的到來
在結尾重點說下作為開發應該有的工作態度,感覺大部分開發參與項目普遍責任感和帶入感不強,需求過來沒有多想,啪啪啪就是一梭子代碼,按照產品的邏輯流程碼了整個業務功能,功能測試上線可以正常運行沒有問題,然后功成身退,兩耳不聞天下事,作為開發在參與項目把自己擺在什么樣的位置決定這你是什么樣的工作態度
從項目角度出發應該把自己所有參與的項目當成自己的孩子,需要主動關注和關心項目的數據情況和后續發展,伴隨著孩子成長了,慢慢就有了成就感
從技術角度出發需要把項目需求功能開發當成造房子,需要分析業務需求提供合理的設計方案,適當的抽象和使用設計模式,只有在開發的時候把地基打穩了才能保證后續的維護和拓展,避免技術債
2019年開年第一篇,祝大家和自己新的一年里豬事順利,大吉大利!歡迎Star 【大話WEB開發】
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/30109.html
摘要:用來指向已創建好的實例構造函數為空注意這里是關鍵這是我們需要調用的方法把函數也定義為空,這樣就大功告成啦。 接上一篇大話PHP設計模式之單例模式 這一篇介紹一下升級版的單例模式,廢話不說先上代碼 不完美的單例模式 class singleMode { //用來指向已創建好的實例 public static $instance; //判斷是...
摘要:上面是簡單的單例模式,自己寫程序的話夠用了,如果想繼續延伸,請傳送至大話設計模式之單例模式升級版 看了那么多單例的介紹,都是上來就說怎么做,也沒見說為什么這么做的。那小的就來說說為什么會有單例這個模式以便更好的幫助初學者真正的理解這個設計模式,如果你是大神,也不妨看完指正一下O(∩_∩)O首先我不得不吐槽一下這個模式名字單例,初學者通過字面很難理解什么是單例,我覺得應該叫唯一模式更貼切...
摘要:權限中心的依賴聲明聲明依賴關系檢查代碼規范聲明開發依賴命名空間檢查代碼規范,執行單元測試。單元測試持續交付一切都如此的完美,沒有測試,又如何可以證明這件事情的完美,又如何可以保障交付的質量。 序 權限管理是無線運營系統中的核心模塊,通過訪問控制策略的配置,來約定人與資源的訪問關系。 本文著重講解如何通過PHP來構建一個靈活、通用、安全的權限管理系統。 關于權限 首先我們來聊聊權限。 權...
摘要:時光飛逝,歲月如梭,我從前端開發崗位轉入測試崗位已經三年了,這期間從迷茫到熟悉,到強化,到熟練,到總結,感受還是很深的三年前的某一個晚上,我正準備下班回家,我們的項目經理把我叫到辦公司和我談話,談了很多,具體說什么不記得 ...
閱讀 2344·2021-11-23 09:51
閱讀 1998·2021-10-14 09:43
閱讀 2759·2021-09-27 13:35
閱讀 1144·2021-09-22 15:54
閱讀 2495·2021-09-13 10:36
閱讀 3784·2019-08-30 15:56
閱讀 3404·2019-08-30 14:09
閱讀 1710·2019-08-30 12:57