在開發的時候,可能會因為code髒像是變數命名不好、部分程式碼可以重複使用想要進行重構,往往這個時候我都會找時間直接改掉,沒有使用到 phpstorm 提供的功能,想說來認識一下phpstorm 提供的重構功能 在 phpstorm 工具列有提供 Refactor 或者滑鼠右鍵也會顯示這個功能裡面就包含 Refactor 的功能 ![截圖 2024-03-20 上午10.37.12](https://hackmd.io/_uploads/BJEk3avRp.png) 圖1. 工具列 Refactor 功能 ![截圖 2024-03-20 上午10.42.00](https://hackmd.io/_uploads/H1zZaaDRT.png) 圖2. 滑鼠右鍵 Refactor 功能 # Rename 重新命名 ## 變數 會把方法內的變數都選取起來可以一次做改名並不會影響到其它方法的同名變數 ```php= // before public function exchangeCoupon() { $a = true; if ($a) { ... } } // after public function exchangeCoupon() { $isExpire = true; if ($isExpire) { ... } } ``` 如果是針對 $a 右鍵 refactor => rename 那麼第3行和第5行的 $a 都會一起更動 ## 屬性 會把檔案內相關的屬性都改掉名字 ```php= // before class UploadController extends Controller { protected $a = true; public function uploadImage() { $this->a = true; } public function downloadImage() { $this->a = false; } } // after class UploadController extends Controller { protected $isUpload = true; public function uploadImage() { $this->isUpload = true; } public function downloadImage() { $this->isUpload = false; } } ``` ## 方法 會把檔案裡同名的方法都進行更動 ```php= // before public function a() { // 取得優惠券 } public function exchangeCoupon() { $coupon = $this->a(); } public function deprecateCoupon() { $coupon = $this->a(); } // after public function getCoupon() { // 取得優惠券 } public function exchangeCoupon() { $coupon = $this->getCoupon(); } public function deprecateCoupon() { $coupon = $this->getCoupon(); } ``` 如果用 refactor => rename 那麼檔案內相同名稱的 method 會一起被更改名字 ## 檔名 會連檔案內的 class 名稱與相關 reference 與註解或字串都會進行更動,如果不想都更動可以選擇要的範圍 ![截圖 2024-03-20 上午11.03.01](https://hackmd.io/_uploads/r1egGAD06.png) 圖3. rename 檔名 ![截圖 2024-03-20 上午11.05.16](https://hackmd.io/_uploads/H1v_zRPCa.png) 圖4. 重構檔案可以選擇重構的部分與範圍 # change signature 調整 method - 名字與回傳型態 - 新增參數/刪除參數/重新排序參數 - 新增參數帶入預設值 ![截圖 2024-03-20 上午11.29.14](https://hackmd.io/_uploads/rkSM_Rw0a.png) 圖5. change signature 調整 visibility、return type、name、parameter 畫面 # Extract/Introduce ![截圖 2024-03-20 上午11.44.27](https://hackmd.io/_uploads/S1rsjAwR6.png) 圖6. 將選取到的部分提煉成 Variable、Parameter、Field、Constant、Method、Class、Interface ## Extract Parameter 新增參數到method定義且更新呼叫方式 ```php= // before class Class1 { public function Calculate($i){ while ( $i < 10 ) { $i = $i + 1; }; return $i; } public function DisplaySum(){ $a = 1; $result = $this -> Calculate($a); echo "The final result is " . $result; } } // after class Class1 { // 多增加 $c parameter public function Calculate($i,$c){ while ( $i < $c ) { $i = $i + 1; }; return $i; } public function DisplaySum(){ $a = 1; $result = $this -> Calculate($a, 10); echo "The final result is " . $result; } } ``` ## Extract Field 把選取到的 expression 變成 field ```php= // before public function find($params) { return execute($params['param_query']); } public function findAll($params) { return executeAll($params['param_query']); } //after public $query = 'param_query'; public function find($params) { return execute($params[self::$query]); } public function findAll($params) { return executeAll($params[self::$query]); } ``` ## Extract Method 讓選取到的區塊變成 method ```php= // before if ('POST' != $_SERVER['REQUEST_METHOD']) { header('Allow: POST'); header('HTTP/1.1 405 Method Not Allowed'); header('Content-Type: text/plain'); exit; } // after function printEmptyHeader() { header('Allow: POST'); header('HTTP/1.1 405 Method Not Allowed'); header('Content-Type: text/plain'); } if ('POST' != $_SERVER['REQUEST_METHOD']) { printEmptyHeader(); exit; } ``` ## Extract Class 讓選取到的 field 與 method 移動到目標 class 並且調整 reference ```php= // before class Source { private $foo; public function bar() { echo $this->foo; } } (new Source())->bar(); // after class Source { private $foo; /** @var \Target */ private $target; public function __construct() { $this->target = new \Target($this); } public function bar() { $this->target->bar(); } public function get_foo() { return $this->foo; } } class Target { private $source; public function __construct(Source $source) { $this->source = $source; } public function bar() { echo $this->source->get_foo(); } } (new Source())->bar(); ``` ## Extract Interface 選擇 className 後可以選擇相關 method 抽成介面 ![截圖 2024-03-20 下午12.17.28](https://hackmd.io/_uploads/B1MwQ1dAT.png) ## Extract Variable 讓選取到的 expression 變成變數 ```php= // before public function getFeedObject($title, $description) { global $wgSitename, $wgContLanguageCode, $wgFeedClasses, $wgTitle; if (!isset($wgFeedClasses[$this->format])) return false; return new $wgFeedClasses[$this->format] // 重構這一個 expression 變成變數 $feedTitle ("$wgSitename - {$title} [$wgContLanguageCode]", htmlspecialchars()); } // after public function getFeedObject($title, $description) { global $wgSitename, $wgContLanguageCode, $wgFeedClasses, $wgTitle; $feedTitle = "$wgSitename - {$title} [$wgContLanguageCode]"; if (!isset($wgFeedClasses[$this->format])) return false; return new $wgFeedClasses[$this->format] ($feedTitle, htmlspecialchars()); } ``` # Move 移動 class 和 class 相關成員(methods、fields、constants), function, constant, file, constant 且會自動修正所有 reference ## Move Class 移動 class 位置 ![截圖 2024-03-21 上午10.38.24](https://hackmd.io/_uploads/HJispMtC6.png) ## Move Method 移動 method 到目標 class 且會調整 reference 成目標 class ```php= // before class UploadController extends Controller { public function getFile() { // 取得檔案 } public function downloadImage() { $this->getFile(); } } // after class UploadController extends Controller { public function downloadImage() { // 下載檔案 if (self::IS_FILE) { FileController::getFile(); } } } class FileController extends Controller { public function getCoupon() { // 取得優惠券 } } ``` ## Move Constant 會把移動 constant 還有調整相關 reference 成目標 class ```php= // before class UploadController extends Controller { public const IS_FILE = true; public function uploadImage() { // 上傳檔案 if (self::IS_FILE) { } } } // after class UploadController extends Controller { public function uploadImage() { // 上傳檔案 if (CommonConstant::IS_FILE) { } } } class CommonConstant { public const IS_FILE = true; } ``` # Inline 與 Extract 相反,將 constant、variable、method 變回去 ## Inline Constant ```php= // before const CONSTANT = 5; function showConstant() { echo CONSTANT . "\n"; } // after function showConstant() { echo 5 . "\n"; } ``` ## Inline Variable ```php= // before function sum($a, $b) { $c = $a + $b; return $c; } // after function sum($a, $b) { return $a + $b; } ``` ## Inline Method ```php= // before function log($message) { echo $message; } log('Message'); // after echo 'Message'; ``` # 參考資源 https://www.jetbrains.com/help/phpstorm/refactoring-source-code.html