2020-05-02 / JSN / 0 Comments / 尚無瀏覽量
這裡介紹兩種用法的比較:
我們開發常常會有一種情況,把一筆陣列資料輸入到某隻 method(),但因為是陣列,在強型別 type hinting 的時候,不知道怎麼做限制。例如加入購物車 Cart,可能會放入多筆商品,常見的寫法是:
|
<?php $products = [ // 這裡省略產品類別範例 // Product("商品名稱", "數量", "單價", "單位") new Product("手機", 2, 100, "支"), new Product("衣服", 3, 50, "件") ]; $cart = new Cart($products); |
我們常見設計的購物車類別:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
<?php class Cart { /** * 購物車的商品項目 * @var array */ private array $items; /** * 建構子把輸入的參數賦予到類別屬性 * @param array $products */ public function __construct(array $products) { $this->items = $products; } } |
這會有一個小問題,我們在建構子 __construct(array $products) 使用強型別規範輸入 array 卻無法明定陣列中的每項型態,這對接手或日後維護的人來說,無法一目瞭然陣列裡面的項目長什麼樣子。
如果我們可以針對陣列中的每個值做類型提示,那麼無論閱讀上或是搭配 IDE 如 phpStorm 都能做出優美的提示。 因此能透過 “…” 參數語法來表示,以下修改上述範例:
|
// 方法一,一次丟入陣列 $products = [ new Product("手機", 2, 100, "支"), new Product("衣服", 3, 50, "件") ]; // 注意帶入的時候要加上 "..." $cart = new Cart(...$products); // 方法二,在參數追加 $cart = new Cart( new Product("手機", 2, 100, "支"), new Product("衣服", 3, 50, "件") ); |
那麼購物車類別如何修改?其實很簡單
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
<?php class Cart { private array $items; /** * 我們透過 ... 語法,代表參數可以輸入多筆類別是 Product 的物件 * @param Product[] $products */ public function __construct(Product ...$products) { $this->items = $products; } } |
上面建構子改良後有兩種用法,方法一是我覺得實務上最常用的方式
|
$products = [ new Product("手機", 2, 100, "支"), new Product("衣服", 3, 50, "件") ]; $cart = new Cart(...$products); |
因為使用者放入的商品數量並不固定,因此方法一實務上最常見。IDE 也能非常清楚的提示:
而方法二適合用在我們寫 Code 的應用上
|
$cart = new Cart( new Product("手機", 2, 100, "支"), new Product("衣服", 3, 50, "件") ); |
例如 Laravel 的 dd() 就是個好懂的範例
|
dd($name); dd($name, $age); |
實務上使用 Interface
中型實務上,展開運算子的強型別我們會使用 Interface 而不是 class 。例如這項發票中心系統 InvoiceCenter 的建構子簡化如下:
注意函式參數第三個,我們在 type hint 做展開運算子使用的是介面 ProductInterface 而不是 類別 Product。因此我們實例化類別的時候會是這樣:
沒錯就是依賴反轉,我們把這項發票中心系統 InvoiceCenter,所依賴的第三方廠商 API 從外部注入,也就是說廠商A
- EzPay 實作 InvoicePlatformInterface
- User 實作 UserInterface
- Product 實作 ProductInterface
我們要換成廠商B,也許叫做 xxPay,那麼他們的發票系統我們也只需要實作這三項 Interface。而第三個參數 new Product() 就是我們本篇提到的應用。IDE 會告訴你這個陣列的每個類別,務必實作 ProductInterface
假設我們帶入任何一項類別,沒有實作介面 ProductInterface 那麼會輕鬆報錯給你看,這對維護人員太有效了
本篇概念參考來源 https://stackoverflow.com/questions/34273367/type-hinting-in-php-7-array-of-objects
2020-04-29 / JSN / 0 Comments / 尚無瀏覽量
Laravel 7 我寫了一隻 command,透過 schedule 註冊每個小時都要跑這隻程式
|
protected function schedule(Schedule $schedule) { $schedule->command("deploy")->hourly()->unlessBetween('01:00', '07:00'); } |
透過指令
確實可以執行如 “git pull”, “composer install”, “php artisan optimize”, “npm install” …… 但是透過 crontab 卻會異常,顯示 “exec: composer: not found” 找不到指令的問題。以下兩種方法
如果是還沒 Build 專案
首先 Laradock 的專案資料夾會看到 workspace/crontab/laradock,已經寫好了每分鐘執行 php artisan,把它註解掉,因為這個身份是 “laradock”,我們要使用的是 “root”
|
vim workspace/crontab/laradock |
|
# * * * * * laradock /usr/bin/php /var/www/artisan schedule:run >> /dev/null 2>&1 |
接著跑起所需要的環境
|
docker-compose build workspace php-fpm docker-compose up -d nginx mongo redis |
進入 workspace 修改 crontab
|
docker-compose exec workspace bash # 我們確定使用者身份 laradock 已經被註解掉了 vim /etc/cron.d/laradock # 增加 root vim /etc/crontab |
添加這行
|
* * * * * root cd /var/www && php artisan schedule:run >> /dev/null 2>&1 |
這樣就能使用 root 身份執行 schedule 了。
如果已經 Build
註腳掉原本使用者 laradock 的 crontab
|
docker-composer exec workspace bash vim /etc/cron.d/laradock |
|
# * * * * * laradock /usr/bin/php /var/www/artisan schedule:run >> /dev/null 2>&1 |
增加 root 的 crontab
|
* * * * * root cd /var/www && php artisan schedule:run >> /dev/null 2>&1 |
這樣就可以了。
如果有用到 Git Pull ,因為是自動化的關係,因此要使用 ssh ,請參考這篇網友分享的文章,設定不需要打帳號密碼的方式。
2020-04-27 / JSN / 0 Comments / 尚無瀏覽量
最近在 Laravel 開發使用 MongoDB 做時間區間的篩選。
因為 Mongo 預設的 _id 具有時間戳記,因此篩選某個時間區段,可以直接透過 _id 做取得。那問題是,如何把時間轉換為 _id 格式呢?以下程式碼提供參考
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
<?php namespace App\Libraries; use MongoDB\BSON\ObjectId; class MongoDB { /** * 透過指定日期時間,取得 Mongo ObjectId * * @param string $timeString 時間字串,如 2019-01-01 12:52:14 或 2019-01-01 ,只要是時間字串即可 * @return ObjectId 返回 Mongo _id 格式 */ public static function getObjectIdFromTimeString(string $timeString): ObjectId { $timestamp = strtotime($timeString); return new ObjectId(dechex($timestamp) . str_repeat("0", 16)); } } |
那麼 Laravel 就可以這樣比對
|
$id = MongoDB::getObjectIdFromTimeString("2020-02-11 11:18:15"); $result = Interview::select("_id") ->where("_id", ">=", $id) ->get(); |
2020-04-23 / JSN / 0 Comments / 尚無瀏覽量
有個狀況是這樣:我們在 GitHub 修改了第三方套件,也 Pull Request 給作者,但作者還沒有 Merge 回去。這時候我們專案又要使用該怎麼辦?
解決方式:
改用自己的 GitHub Repository 即可。
舉例流程,以下示範修改第三方套件 php-simple-html-dom-parser
- 我們從來源
sunra/php-simple-html-dom-parser
fork 一份到自己的 repository 如 fdjkgh580/php-simple-html-dom-parser
- 在自己的 repository
fdjkgh580/php-simple-html-dom-parser
開一個分支命名為 update-php7.4
- 開始修改程式碼並提交到該分支
update-php7.4
- 在 composer.json 改寫。這裡要注意,repository 指定我們 fork 過來的位置;require 改為我們自訂的分支名稱,官方提到會成為這種格式
dev-*
因此要寫成 dev-update-php7.4
,但套件名稱不要更改
|
{ "repositories": [ { "type": "vcs", "url": "https://github.com/fdjkgh580/php-simple-html-dom-parser.git" } ], "require": { "sunra/php-simple-html-dom-parser": "dev-update-php7.4" } } |
- 沒有裝過就 composer install ;已經裝過原本第三方來源,就用 composer update 換成自己的 repository。
上面發生什麼事?
套件 sunra/php-simple-html-dom-parser
本來應該要從第三方來源 sunra/php-simple-html-dom-parser
下載,經過 composer.json 替換後,安裝或更新時,會先檢查是否在 composer.json 定義過 repository。那因為我們定義過了,因此 composer 將原本應該要連去 sunra 的 repository 改成 fdjkgh580 的 repository。
參考官方文件:https://getcomposer.org/doc/05-repositories.md#vcs
2020-03-30 / JSN / 0 Comments / 尚無瀏覽量
目前在 Laravel-mix 5.4 (package.json 找得到) 下指令 npm run dev 會跑上好幾分鐘,解決這個辦法可以在 webpack.mix.json 加入已下指令,運行飛快。
|
mix.options({ processCssUrls: false }); |
參考來源:https://github.com/JeffreyWay/laravel-mix/issues/287、JeffreyWay/laravel-mix#287 (comment)