大話轉崗 PHP 開發小結

image

前言

近期因公司內部轉崗,開始參與PHP項目進行後端開發,一直都是強類型寫的比較多,弱類型語言也有接觸了一些,如:nodejs,python,作一些輔助服務,數據採集的事情,恰好內部有這個機會進行能夠學以至用,加上以前對後端的理解和經驗,很容易上手,這裏記錄下開發過程遇到的些問題解決方案和本身對PHP的理解,以及項目中的部分架構php

當前已經進入PHP7的版本,作了不少的調整,尤爲在性能上有很大的提高

面向對象

image

PHP框架內置不少強大函數,超級全局變量,魔術函數,魔術變量,能夠經過提供的內置函數對PHP項目進行拓展,數據類型操做,http信息獲取等,經過安裝拓展添加各類功能支持,框架內置函數調用大部分仍是偏向面向過程,經過調用函數,傳入要操做的類型數據和依賴數據,這裏剛開始有些不習慣,面向對象的開發中習慣直接 類型變量/對象 點出函數。html

如今PHP開發能夠選擇使用面向過程也能夠用面向對象,最先PHP版本不支持面向對象特性,PHP5開始對OOP有良好的支持,不少PHP開發者沒有系統性的學習OOP相關知識,包括工齡長的PHP開發者或者老的項目不少仍是偏向面向過程開發,因此會接觸到不少偏向面向過程開發的項目java

在項目開發過程當中遇到些偏應用業務開發的項目,看似有用到類,可是並沒用到面向對象的特性對業務進行抽象,如:項目中每一個業務功能有個php文件對應一個類,類裏裏大部分都是邏輯function,而後經過拓展autoload,實現自動include php文件,好比經過L函數傳入要調用的類名,構造出PHP文件路徑,進行include,而後返回類實例對象,只是經過類文件來區分功能函數,並無使用到面向對象的特性進行封裝,仍是偏向面向過程思路在開發node

PHP5開始對OOP提供了良好支持,基本已經和java,C# 面向對象語法類似,可使用命名空間,封裝interface,abstract,多態:implements,extends,PHP7還支持多繼承trait,方便封裝些公用的功能,經過PSR4規範,引入composer 實現的autoload,能夠很好的進行OOP開發python

PHP開發仍是比較靈活,能夠面向過程也能夠面向對象,根據具體的業務場景設計

使用composer psr4mysql

  • 在項目中添加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語句,而後經過查看錶結構才能知道數據字段信息,這點很難受,影響開發效率nginx

PHP如今已經支持typehint,經過定義類型能夠對部分肯定的類型變量,參數,返回類型進行強類型的定義,尤爲須要定義表數據Model類,這樣獲得數據對象後經過->能夠感知出全部數據字段,方便後續拓展開發和維護git

根據場景使用,不能說由於本身習慣使用強力型就把全部類型定義都寫成強類型
/**
 * 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;
    }
}

經過定義變量類型獲得代碼感知github

/** @var Logic $logic */
$logic=new Logic();
弱類型比較一個頭兩個大:

由於PHP是弱類型緣由,在作類型比較的時候,每每會由於一個不當心就掉坑裏,下面列出類型函數和類型比較的表格web

就問你,看到這些表格怕不怕,心中有一萬隻草泥馬奔騰而過,瞬間變成幽怨的小眼神

image

使用 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靈活性

上面說了這麼多弱類型下的問題,這裏說下弱類型的優勢,弱類型一個明顯的優點就是靈活
PHP動態特性,能夠動態實例化,動態添加屬性,動態調用函數,等,經過這些特性能夠用簡單的代碼封裝出強大的功能

image

簡單舉栗子:

<?php

class Developer
{
    public $name;
    public $hair;

    /**
     * 介紹
     */
    public function introduce()
    {
        $desc = '名字:' . $this->name . ',髮量:' . $this->hair;
        if (!empty($this->age)) $desc = $desc . ',年齡:' . $this->age;
        echo $desc . "\r\n";
    }

    /**
     * 數據邏輯處理
     * @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 . "\r\n";
}


// ------參數類型和返回值支持多類型------

$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 echo @$var['sflyq'];

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部署

最近階段感悟

image

從一個熟悉的語言到另外一個相對陌生的語言,語言只是工具,在適合的場景下使用適合的工具,從本身熟悉的業務到陌生的業務,離開本身的舒服區,擁抱變化才能成長

在相同的後端領域切換語言學習成本仍是比較低的,主要是對後端開發的思路,經驗是能夠共用的,只是換了個語言去實現

當公司發展到必定的規模,崗位職能區分的很細,作應用開發的童鞋接觸不到服務器架構,沒有機會接觸職能之外的技術,工做內容除了完成業務需求開發,仍是業務需求開發,這樣常年開發下去對我的成長的侷限性很高,須要本身在工做之餘進行拓展,對公司內部有興趣的技術進行了解和學習,耐心等待機會的到來

在結尾重點說下做爲開發應該有的工做態度,感受大部分開發參與項目廣泛責任感和帶入感不強,需求過來沒有多想,啪啪啪就是一梭子代碼,按照產品的邏輯流程碼了整個業務功能,功能測試上線能夠正常運行沒有問題,而後功成身退,兩耳不聞天下事,做爲開發在參與項目把本身擺在什麼樣的位置決定這你是什麼樣的工做態度

從項目角度出發應該把本身全部參與的項目當成本身的孩子,須要主動關注和關心項目的數據狀況和後續發展,伴隨着孩子成長了,慢慢就有了成就感

從技術角度出發須要把項目需求功能開發當成造房子,須要分析業務需求提供合理的設計方案,適當的抽象和使用設計模式,只有在開發的時候把地基打穩了才能保證後續的維護和拓展,避免技術債

image

2019年開年第一篇,祝你們和本身新的一年裏豬事順利,大吉大利!

歡迎Star 【大話WEB開發】

相關文章
相關標籤/搜索