如何使用 PhpStorm 重構 Namespace?

   2016-09-08 0
核心提示:在 TDD 開發流程,為了第一個 綠燈 ,一開始可能在同一個 namespace 下只有一個 class,但隨著重構的進行,可能重構出更多的 class 與 interface,為了更加的 高內聚,低耦合 ,我們可能會將更相關的 class 與 interface 重構到其他 namespace,導致相依的 cl

在 TDD 開發流程,為了第一個 綠燈 ,一開始可能在同一個 namespace 下只有一個 class,但隨著重構的進行,可能重構出更多的 class 與 interface,為了更加的 高內聚,低耦合 ,我們可能會將更相關的 class 與 interface 重構到其他 namespace,導致相依的 class 也必須修改,在重構 namepsace 時,PhpStorm 可以幫我們將相依的 class 一併修改,非常方便。

Version

PHP 7.0.0

Laravel 5.2.37

實際案例

我們將以經典的 service + repository 模式為例,以 PostService 處理商業邏輯,以 PostRepository 處理資料庫邏輯,將全部 post 顯示在網頁上。

最後使用 PhpStorm 重構 PostServicePostRepository

單元測試

以 TDD 方式開發,因此必須先寫單元測試。

PostServiceTest.php 1 1 GitHub Commit : 單元測試 : 建立 PostServiceTest.php

tests/Unit/PostServiceTest.php
use App\Post;
use App\Services\PostService;
use Illuminate\Foundation\Testing\DatabaseMigrations;

class PostServiceTest extends TestCase
{

use DatabaseMigrations;

/** @test */
public function 顯示所有文章()
{

/** arrange */
$expected = [
['title' => 'title1', 'description' => 'desc1', 'content' => 'content1'],
['title' => 'title2', 'description' => 'desc2', 'content' => 'content2'],
['title' => 'title3', 'description' => 'desc3', 'content' => 'content3'],
];

collect($expected)->each(function ($value) {
Post::create($value);
});

/** act */
$actual = app(PostService::class)->displayAllPosts()->toArray();

/** assert */
$this->assertArraySubset($expected, $actual);
}
}

13 行

/** arrange */
$expected = [
['title' => 'title1', 'description' => 'desc1', 'content' => 'content1'],
['title' => 'title2', 'description' => 'desc2', 'content' => 'content2'],
['title' => 'title3', 'description' => 'desc3', 'content' => 'content3'],
];

collect($expected)->each(function ($value) {
Post::create($value);
});

由於單元測試是使用 SQLite in Memory 為資料庫,只要測試一結束,記憶體就會釋放,因此每次測試都要重新新增資料。

使用 Collection->each()$expected 中的資料透過 Post::create() 新增。

23 行

/** act */
$actual = app(PostService::class)->displayAllPosts()->toArray();

測試 PostService->displayAllPosts() 2 2 此時 PostServicedisplayAllPost() 都還沒建立,TDD 會等待測試亮 紅燈 時,才去新增 PostServicedisplayAllPost()

displayAllPosts() 回傳的是 Collection ,但 PHPUnit 無法對 Collection 做 assertion,必須先轉成 array。

26 行

/** assert */
$this->assertArraySubset($expected, $actual);

這裡不能使用 assertEquals() ,因為 posts table 還包含 created_atupdated_at 兩個欄位,若使用 assertEquals() 一定失敗,必須改用 assertArraySubset()

PostService

實際跑測試,會得到第 1 個 紅燈 ,PHPUnit 抱怨 PostServicedisplayAllPosts() 尚未建立,須趕快補上。

PostService.php 3 3 GitHub Commit : 建立 PostService

app/Services/PostService.php
namespace App\Services;

use App\Repositories\PostRepository;
use Illuminate\Database\Eloquent\Collection;

class PostService
{

/**
* @var PostRepository
*/

private $postRepository;

/**
* PostService constructor.
* @param PostRepository $postRepository
*/

public function __construct(PostRepository $postRepository)
{

$this->postRepository = $postRepository;
}

/**
* @return Collection
*/

public function displayAllPosts() : Collection
{

return $this->postRepository->getAllPosts();
}
}

第 8 行

/**
* @var PostRepository
*/

private $postRepository;

/**
* PostService constructor.
* @param PostRepository $postRepository
*/

public function __construct(PostRepository $postRepository)
{

$this->postRepository = $postRepository;
}

因為 PostService 須使用到 PostRepository ,使用 constructor injection 注入 PostRepository

22 行

/**
* @return Collection
*/

public function displayAllPosts() : Collection
{

return $this->postRepository->getAllPosts();
}

呼叫 PostRepositorygetAllPosts() , 回傳 Collection 4 4 此時 PostRepositorygetAllPosts() 都還沒建立,TDD 會等待測試亮 紅燈 時,才去新增 PostRepositorygetAllPosts()

為什麼 PostService 只有呼叫 PostRepository 而已?

實務上 PostService 除了呼叫 PostRepository 外,還會有自己的商業邏輯要寫,本文因為重點在 namespace 重構 ,所以簡化了 PostService ,關於 Service 模式,詳細請參考 如何使用 Service 模式?

PostRepository

實際跑測試,會得到第 2 個 紅燈 ,PHPUnit 抱怨 PostRepositorygetAllPosts() 尚未建立,須趕快補上。

PostRepository.php 5 5 GitHub Commit : 建立 PostRepository

app/Repositories/PostRepository.php
namespace App\Repositories;

use App\Post;
use Illuminate\Database\Eloquent\Collection;

class PostRepository
{

/**
* @return Collection
*/

public function getAllPosts() : Collection
{

return Post::all();
}
}

為簡化起見,回傳 post table 所有資料。

如何使用 PhpStorm 重構 Namespace?

得到第 1 個 綠燈 ,完成 PostServicePostRepository

整合測試

單元測試目的是寫出 service 與 repository,我們要繼續寫整合測試,將 route、controller 與 view 補上。

PostApplicationTest.php 6 6 GitHub Commit : 整合測試 : 建立 PostApplicationTest

tests/Unit/PostServiceTest.php
use App\Post;
use Illuminate\Foundation\Testing\DatabaseMigrations;

class PostApplicationTest extends TestCase
{

use DatabaseMigrations;

/** @test */
public function 顯示所有文章()
{

/** arrange */
$expected = [
['title' => 'title1', 'description' => 'desc1', 'content' => 'content1'],
['title' => 'title2', 'description' => 'desc2', 'content' => 'content2'],
['title' => 'title3', 'description' => 'desc3', 'content' => 'content3'],
];

collect($expected)->each(function ($value) {
Post::create($value);
});

/** act */
$this->visit('/post');

/** assert */
collect($expected)->each(function ($value) {
$this->see($value['title']);
$this->see($value['description']);
$this->see($value['content']);
});
}
}

第 9 行

/** arrange */
$expected = [
['title' => 'title1', 'description' => 'desc1', 'content' => 'content1'],
['title' => 'title2', 'description' => 'desc2', 'content' => 'content2'],
['title' => 'title3', 'description' => 'desc3', 'content' => 'content3'],
];

collect($expected)->each(function ($value) {
Post::create($value);
});

由於單元測試是使用 SQLite in Memory 為資料庫,只要測試一結束,記憶體就會釋放,因此每次測試都要重新新增資料。

使用 Collection->each()$expected 中的資料透過 Post::create() 新增。

22 行

/** act */
$this->visit('/post');

實際測試 /post URI。 7 7 此時 route 都還沒建立,TDD 會等待測試亮 紅燈 時,才去新增 route。

27 行

/** assert */
collect($expected)->each(function ($value) {
$this->see($value['title']);
$this->see($value['description']);
$this->see($value['content']);
});

期望在網頁上看到 titledescriptioncontent 等資料。

使用 Collection->each()$expected 中的資料透過 $this->see() 做 assertion。 8 8 此時 view 都還沒建立,TDD 會等待測試亮 紅燈 時,才去新增 view。

Routes

實際跑測試,會得到第 1 個 紅燈 ,PHPUnit 抱怨找不到 http://localhost/post ,因為 route 尚未建立,須趕快補上。

routes.php 9 9 GitHub Commit : 建立 routes

app/Http/routes.php
Route::get('/', function () {
return view('welcome');
});

Route::get('/post', [
'as' => 'post',
'uses' => 'PostController@index'
]);

新增 route /post ,並指定其 controller 為 PostController@index 10 10 此時 PostController 都還沒建立,TDD 會等待測試亮 紅燈 時,才去新增 PostController

PostController

實際跑測試,會得到第 2 個 紅燈 ,PHPUnit 抱怨 PostController 尚未建立,須趕快補上。

PostController.php 11 11 GitHub Commit : 建立 PostController

app/Http/Controllers/PostController.php
namespace App\Http\Controllers;

use App\Http\Requests;
use App\Services\PostService;

class PostController extends Controller
{

/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/

public function index()
{

$data['posts'] = app(PostService::class)->displayAllPosts();
return view('post.index', $data);
}
}

使用 app() 建立 PostService ,並呼叫其 displayAllPosts()

回傳 post.index view。 12 12 此時 post.index view 都還沒建立,TDD 會等待測試亮 紅燈 時,才去新增 post.index view。

Post.Index Blade

實際跑測試,會得到第 3 個 紅燈 ,PHPUnit 抱怨 post.index view 尚未建立,須趕快補上。

index.blade.php 13 13 GitHub Commit : 建立 post.index view

<!DOCTYPE html>
<html>
<head>
<title>Posts</title>
</head>
<body>
@foreach($posts as $post)
<div>
<h2>{{ $post->title }}</h2>
<h2>{{ $post->description }}</h2>
<h2>{{ $post->content }}</h2>
</div>
<hr>
@endforeach
</body>
</html>

簡單使用 @foreach 與 binding 將資料顯示。

如何使用 PhpStorm 重構 Namespace?

得到第 1 個 綠燈 ,完成 routesPostControllerpost.index view。

重構 PostService

到目前為止,已經 綠燈 達成需求,但發現將 PostService 放在 app/Services 下似乎不妥,想將 PostServie 重構放在 app/Services/Post 目錄下。

根據 PSR-4 ,PHP 的 namespace 必須與目錄相同,也就是說除了將 PostService 放到 app/Services/Post 目錄下外,以下程式碼必須修改 :

  • PostService 的 namespace 必須修改。
  • 單元測試的 PostServiceTestuse 必須修改。
  • Controller 的 PostControlleruse 必須修改。

本文只是很簡單的範例,已經要改 3 個地方,實務上會更複雜,要改的地方會更多,還可能沒改到或改錯。

這時候就要使用 PhpStorm 的重構了。

如何使用 PhpStorm 重構 Namespace?

將滑鼠游標放在要重構的 PostService 的 class 名稱上,按熱鍵 ? + T,選擇 Move

如何使用 PhpStorm 重構 Namespace?

顯示 Move Class 對話框。

  • Move Class PostService to namespace 填入新的 namespace : App\Services\Post ,PhpStorm 會自動在 Target destination directory 加上 Post 目錄。
  • Search in comments and stringsSearch for text occurrences 都打勾。
  • 按下 Preview 可以先看一下 PhpStorm 將做哪些重構,按 Refactor 則直接重構。

如何使用 PhpStorm 重構 Namespace?

PhpStorm 預告將對 PostControllerPostServiceTestPostService 做重構,與我們的預期相同。

若發現 PhpStorm 失去水準判斷錯誤,可以將其選擇按右鍵將其 ExcludedRemove 掉。

最後按 Do Refactor 開始重構。

如何使用 PhpStorm 重構 Namespace?

重構完趕快跑單元測試與整合測試,確認 PhpStorm 沒有改壞。

重構 PostRepository

前一個例子,是將 PostService 單一 class 重構其 namespace,實務上還有另外一種應用,是將一個目錄下所有 class 重構成另外一個 namespace。

目前想將 app/Repositories 下所有的 class 重構到 app/Repositories/Post 目錄下。

根據 PSR-4 ,PHP 的 namespace 必須與目錄相同,也就是說除了將 PostRepository 放到 app/Repositories/Post 目錄下外,以下程式碼必須修改 :

  • PostRepository 的 namespace 必須修改。
  • Service 的 PostServiceuse 必須修改。

若目錄下有很多 class,要改的地方會更多,還可能沒改到或改錯。

這時候就要使用 PhpStorm 的重構了。

如何使用 PhpStorm 重構 Namespace?

選擇要重構目錄下的其中一個檔案開啟,本例 app/Repositories 目錄下只有 PostRepository

將滑鼠游標放在要重構的 PostRepository 的 namespace 名稱上,按熱鍵 ? + T,選擇 Move

如何使用 PhpStorm 重構 Namespace?

顯示 Move Namespace 對話框。

  • New Namespace name 填入新的 namespace : App\Repositories\Post ,PhpStorm 會自動在 Target destination directory 加上 Post 目錄。
  • Search in comments and stringsSearch for text occurrences 都打勾。
  • 按下 Preview 可以先看一下 PhpStorm 將做哪些重構,按 Refactor 則直接重構。

如何使用 PhpStorm 重構 Namespace?

PhpStorm 預告將對 PostRepositoryPostService 做重構,與我們的預期相同。

若發現 PhpStorm 失去水準判斷錯誤,可以將其選擇按右鍵將其 ExcludedRemove 掉。

最後按 Do Refactor 開始重構。

如何使用 PhpStorm 重構 Namespace?

重構完趕快跑單元測試與整合測試,確認 PhpStorm 沒有改壞。

Conclusion

  • 重構單一 class,是將游標放在 class 名稱上。
  • 重構一目錄下所有 class,是將游標放在 namespace 名稱上。
  • Laravel 5 大量使用 namespace 後,只要改 namespace 就是大家永遠的痛,透過 PhpStorm 的重構,與自己寫的單元測試與整合測試保護後,再也不用害怕改 namespace 了。

Sample Code

完整的範例可以在我的 GitHub 上找到。

 
标签: PhpStorm
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与乐学笔记(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

  • PHP 设置调试工具XDebug PHPStorm IDE
    PHP 设置调试工具XDebug PHPStorm IDE
    先下载PHP扩展Xdebughttps://xdebug.org, 可以复制自己的phpinfo粘贴到https://xdebug.org/wizard.php中, 会生成需要下载的版本, php.ini的设置语句.下载好之后放入php目录的ext文件夹中, 然后设置php.ini, 在最后加上zend_extension = C:\path\php\ext\php_x
  • PHPStorm+Xdebug断点调试PHP
    PHPStorm+Xdebug断点调试PHP
    前言:何为DEBUG?相信很多程序员都知道debug这个单词,也明白它的意思,但是对于这词的由来,恐怕少有人知道。关于debug的由来,要追溯到1937年。1937年,美国青年霍德华.艾肯找到IBM公司为其投资200万美元研制计算机,第一台成品艾肯把它取名为:马克1号(m
  • PhpStorm 2017.1 EAP 171.2272 发布
    PhpStorm 2017.1 EAP 171.2272 发布
    PhpStorm 2017.1 EAP 171.2272发布了。PHPStorm 是 JetBrains 公司开发的一个轻量级且便捷的PHP IDE,其旨在提供用户效率,可深刻理解用户的编码,提供智能代码补全,快速导航以及即时错误检查。如果你之前已经安装了2017.1phpStorm EAP (171.2152),你很快
    02-05 PhpStorm
  • Mac PHPStorm 使用心得
    PHPStorm 是什么?「 PHPStorm 」 是一个轻量级且便捷的 PHP IDE。其旨在提供用户效率、可深刻理解用户的编码、提供智能代码补全、快速导航以及即时错误检查。PHPStorm 使用心得 (一)全局搜索(command + shift + F)显示类中的方法 (command + 7)函数追踪
  • [实践OK]使用WebStorm/Phpstorm实现remote host
    主要是设置自动保存到远程这个选项:勾选 [V]Tools-deployment-Automatic UploadPhpStorm Save and Upload on ctrl+s, 'Tools - Deployment-config' mark as default serve...Just set server configuration on 'Tools - Deployment-config' mark as default
  • PhpStorm v2016.3发布,工具框架更新,PHP编辑新体验!
    PhpStorm v2016.3发布,工具框架更新,PHP编辑
    下载最新版PhpStorm试用 工具和框架 Remote Interpreters中支持Docker 加入Docker,在PhpStorm中可以添加远程PHP解释器。 PHPSpec 支持 2016.3版本中加入PHPSpec支持。 PHPUnit, Behat, PHPSpec自动识别和配置 现在将会收到提示,建议自动配置PHPUnit, Behat,
    11-10 PhpStormPHP
  • Phpstorm配置phpunit对php进行单元测试
    Phpstorm配置phpunit对php进行单元测试
    在 phpstorm 中配置 php 项目的单元测试,项目使用 Composer 进行管理,为了避免在项目中直接引入 phpunit 相关代码包,使项目的 vendor 目录变得臃肿,这里采用全局安装方式安装了 phpunit 代码包。 composer global require phpunit/phpunit=5.0.* 安装完成
  • 如何修改 PhpStorm 預設的 Class Template?
    如何修改 PhpStorm 預設的 Class Template?
    當使用 PhpStorm 建立 class 時,預設會產生 Created by PhpStorm 的註解,並包含 作者 、 日期 、 時間 等資訊,有的人喜歡,有的人不喜歡,若你不希望每次建立 class 時都有這個檔頭,可以自行修改;除此之外,在 PHP 7 為了讓強行別檢查發揮作用,我們會在
    10-07 PhpStormPHP
  • Mac OS X下PhpStorm+MAMP PRO+Xdebug+FireFox集成开发和断点调试环境配置
    Mac OS X下PhpStorm+MAMP PRO+Xdebug+FireFox集
    一、环境及软件1、macbook pro2、Phpstorm3、MAMP PRO4、FireFox二、环境搭建1、PhpStorm导入项目下载PhpStorm并安装,网上随便找个注册码即可破解,安装后打开界面选择ToolBar → VCS → Checkout from Version Control → Git,填写Git Repository URL,选
  • 远程连接MySQL以及PHPStorm远程开发你的php项目
    远程连接MySQL以及PHPStorm远程开发你的php项目
    在上一篇博文中介绍了如何在完整地搭建LAMP环境。其中提到了新建一个可以在任意IP地址远程连接MySQL的用户,今天这篇博文就详细介绍下如何在你的电脑上远程连接mysql,并且介绍如何用phpstorm来远程开发你的php项目。 我的开发环境是MAC,所以我这篇博文里面
点击排行