本篇文章给大家带来了关于php的相关知识,其中主要跟大家聊一聊什么是重构?怎么更好的重构PHP代码?感兴趣的朋友下面一起来看一下吧,希望对大家有帮助。

重构指的是在不改变原有功能的情况下,修改或者重新编写代码。
下面的例子中,我将向你展示如何更好地编写代码。
#1 - 表现力
这可能只是一个简单的技巧,但编写富有表现力的代码可以大大改进我们的代码。总是让代码自我解释,这样未来的你或其他开发人员都能知道代码中发生了什么。
不过也有开发人员表示,命名是编程中最困难的事情之一。这就是为什么这不像听起来那么容易的原因之一。
示例 #1 - 命名
之前
1 2 3 | $status = $user ->status('pending');
|
登录后复制
之后
1 2 3 4 | $isUserPending = $user ->isStatus('pending');
|
登录后复制
示例 #2 - 命名
之前
1 2 | return $factory ->getTargetClass();
|
登录后复制
之后
1 2 3 | return $factory ->getTargetClassPath();
|
登录后复制
示例 #3 - 提取
之前
1 2 3 4 5 6 7 | public function setCodeExamples(string $exampleBefore , string $exampleAfter )
{
$this ->exampleBefore = file_get_contents (base_path(" $exampleBefore .md"));
$this ->exampleAfter = file_get_contents (base_path(" $exampleAfter .md"));
}
|
登录后复制
之后
1 2 3 4 5 6 7 8 9 10 11 | public function setCodeExamples(string $exampleBefore , string $exampleAfter )
{
$this ->exampleBefore = $this ->getCodeExample( $exampleBefore );
$this ->exampleAfter = $this ->getCodeExample( $exampleAfter );
}
private function getCodeExample(string $exampleName ): string
{
return file_get_contents (base_path(" $exampleName .md"));
}
|
登录后复制
示例 #4 - 提取
之前
1 2 3 | User::whereNotNull('subscribed')->where('status', 'active');
|
登录后复制
之后
示例 #5 - 提取
这是我之前项目的一个例子。我们用命令行导入用户。 ImportUsersCommand 类中含有一个 handle 方法,用来处理任务。
之前
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | protected function handle()
{
$url = $this ->option('url') ?: $this ->ask('Please provide the URL for the import:');
$importResponse = $this ->http->get( $url );
$bar = $this ->output->createProgressBar( $importResponse -> count ());
$bar ->start();
$this ->userRepository->truncate();
collect( $importResponse ->results)->each( function ( array $attributes ) use ( $bar ) {
$this ->userRepository->create( $attributes );
$bar ->advance();
});
$bar ->finish();
$this ->output->newLine();
$this ->info('Thanks. Users have been imported.');
if ( $this ->option('with-backup')) {
$this ->storage
->disk('backups')
->put( date ('Y-m-d').'-import.json', $response ->body());
$this ->info('Backup was stored successfully.');
}
}
|
登录后复制
之后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | protected function handle(): void
{
$url = $this ->option('url') ?: $this ->ask('Please provide the URL for the import:');
$importResponse = $this ->http->get( $url );
$this ->importUsers( $importResponse ->results);
$this ->saveBackupIfAsked( $importResponse );
}
protected function importUsers( $userData ): void
{
$bar = $this ->output->createProgressBar( count ( $userData ));
$bar ->start();
$this ->userRepository->truncate();
collect( $userData )->each( function ( array $attributes ) use ( $bar ) {
$this ->userRepository->create( $attributes );
$bar ->advance();
});
$bar ->finish();
$this ->output->newLine();
$this ->info('Thanks. Users have been imported.');
}
protected function saveBackupIfAsked(Response $response ): void
{
if ( $this ->option('with-backup')) {
$this ->storage
->disk('backups')
->put( date ('Y-m-d').'-import.json', $response ->body());
$this ->info('Backup was stored successfully.');
}
}
|
登录后复制
#2 - 提前返回
提前返回指的是,我们尝试通过将结构分解为特定 case 来避免嵌套的做法。这样,我们得到了更线性的代码,更易于阅读和了解。不要害怕使用多个 return 语句。
示例 #1
之前
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public function calculateScore(User $user ): int
{
if ( $user ->inactive) {
$score = 0;
} else {
if ( $user ->hasBonus) {
$score = $user ->score + $this ->bonus;
} else {
$score = $user ->score;
}
}
return $score ;
}
|
登录后复制
之后
1 2 3 4 5 6 7 8 9 10 11 12 | public function calculateScore(User $user ): int
{
if ( $user ->inactive) {
return 0;
}
if ( $user ->hasBonus) {
return $user ->score + $this ->bonus;
}
return $user ->score;
}
|
登录后复制
示例 #2
之前
1 2 3 4 5 6 7 8 9 10 | public function sendInvoice(Invoice $invoice ): void
{
if ( $user ->notificationChannel === 'Slack')
{
$this ->notifier->slack( $invoice );
} else {
$this ->notifier->email( $invoice );
}
}
|
登录后复制
之后
1 2 3 4 5 6 7 8 9 10 | public function sendInvoice(Invoice $invoice ): bool
{
if ( $user ->notificationChannel === 'Slack')
{
return $this ->notifier->slack( $invoice );
}
return $this ->notifier->email( $invoice );
}
|
登录后复制
Note: 有时你会听到 “防卫语句” 这样的术语,它是通过提前返回实现。
#3 - 重构成集合 Collection
在 PHP 中,我们在很多不同数据中都用到了数组。处理及转换这些数组可用功能非常有限,并且没有提供良好的体验。(array_walk, usort, etc)
要处理这个问题,有一个 Collection 类的概念,可用于帮你处理数组。最为人所知的是 Laravel 中的实现,其中的 collection 类提供了许多有用的特性,用来处理数组。
注意: 以下例子, 我将使用 Laravel 的 collect () 辅助函数,不过在其他框架或库中的使用方式也很相似。
示例 #1
之前
1 2 3 4 5 6 7 | $score = 0;
foreach ( $this ->playedGames as $game ) {
$score += $game ->score;
}
return $score ;
|
登录后复制
之后
1 2 3 4 | return collect( $this ->playedGames)
->sum('score');
|
登录后复制
示例 #2
之前
1 2 3 4 5 6 7 8 9 10 11 12 | $users = [
[ 'id' => 801, 'name' => 'Peter', 'score' => 505, 'active' => true],
[ 'id' => 844, 'name' => 'Mary', 'score' => 704, 'active' => true],
[ 'id' => 542, 'name' => 'Norman', 'score' => 104, 'active' => false],
];
$users = array_filter ( $users , fn ( $user ) => $user ['active']);
usort( $users , fn( $a , $b ) => $a ['score'] < $b ['score']);
$userHighScoreTitles = array_map (fn( $user ) => $user ['name'] . '(' . $user ['score'] . ')', $users );
return $userHighScoreTitles ;
|
登录后复制
之后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $users = [
[ 'id' => 801, 'name' => 'Peter', 'score' => 505, 'active' => true],
[ 'id' => 844, 'name' => 'Mary', 'score' => 704, 'active' => true],
[ 'id' => 542, 'name' => 'Norman', 'score' => 104, 'active' => false],
];
return collect( $users )
->filter(fn( $user ) => $user ['active'])
->sortBy('score')
->map(fn( $user ) => "{ $user ['name']} ({ $user ['score']})"
->values()
->toArray();
|
登录后复制
#4 - 一致性
每一行代码都会增加少量的视觉噪音。代码越多,阅读起来就越困难。这就是为什么制定规则很重要。保持类似的东西一致将帮助您识别代码和模式。这将导致更少的噪声和更可读的代码。
示例 #1
之前
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | class UserController
{
public function find( $userId )
{
}
}
class InvoicesController
{
public function find( $user_id ) {
}
}
|
登录后复制
之后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class UserController
{
public function find( $userId )
{
}
}
class InvoiceController
{
public function find( $userId )
{
}
}
|
登录后复制
示例 #2
之前
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class PdfExporter
{
public function handle(Collection $items ): void
{
}
}
class CsvExporter
{
public function export(Collection $items ): void
{
}
}
$pdfExport ->handle();
$csvExporter ->export();
|
登录后复制
之后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | interface Exporter
{
public function export(Collection $items ): void;
}
class PdfExporter implements Exporter
{
public function export(Collection $items ): void
{
}
}
class CsvExporter implements Exporter
{
public function export(Collection $items ): void
{
}
}
$pdfExport ->export();
$csvExporter ->export();
|
登录后复制
重构 ❤️ 测试
我已经提到过重构不会改变代码的功能。这在运行测试时很方便,因为它们也应该在重构之后工作。这就是为什么我只有在有测试的时候才开始重构代码。他们将确保我不会无意中更改代码的行为。所以别忘了写测试,甚至去 TDD。
推荐学习:《PHP视频教程》
以上是教你如何更好地重构PHP代码的详细内容。更多信息请关注PHP中文网其他相关文章!