Maison >développement back-end >tutoriel php >Apprenez à mieux refactoriser le code PHP
Cet article vous apporte des connaissances pertinentes sur PHP. Il vous parle principalement de ce qu'est le refactoring ? Comment mieux refactoriser le code PHP ? Les amis intéressés peuvent jeter un œil ci-dessous. J'espère que cela sera utile à tout le monde.
La refactorisation fait référence à la modification ou à la réécriture du code sans changer la fonctionnalité d'origine.
Dans l'exemple ci-dessous, je vais vous montrer comment mieux écrire du code.
#1 - Expressif
Ce n'est peut-être qu'une simple astuce, mais écrire du code expressif peut grandement améliorer notre code. Rendez toujours le code explicite afin que vous ou d'autres développeurs puissiez savoir ce qui se passe dans le code.
Cependant, certains développeurs ont déclaré que nommer est l'une des choses les plus difficiles en programmation. C’est l’une des raisons pour lesquelles ce n’est pas aussi facile qu’il y paraît. # 3 - Extraire
Avant
// ❌ 这个方法是用来做什么的,方法名表达并不清晰 // ❌ 是设置状态还是检查状态呢? $status = $user->status('pending');Après
// ✅ 通过添加 is,使方法名表达的意图更清晰 // ✅ 检测用户状态是否与给定状态相等 // ✅ 同时新变量名让我们可以推断它是布尔值 $isUserPending = $user->isStatus('pending');
Exemple n°4 - Extraction
Avant
// ❌ 这个类返回的是什么?类名?类全名?还是类路径? return $factory->getTargetClass();Après
// ✅ 我们获取的是类路径 // ✅ 如果用户想要类名?则找错了方法 return $factory->getTargetClassPath();
Exemple n°5 - Extraction
Ceci est un exemple de mon projet précédent. Nous utilisons la ligne de commande pour importer des utilisateurs. La classe ImportUsersCommand contient une méthode handle pour gérer les tâches.
Avant// ❌ 重复的代码 ( "file_get_contents", "base_path" 方法以及文件扩展) // ❌ 此刻,我们不去关心如何获得code examples 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")); }Après
public function setCodeExamples(string $exampleBefore, string $exampleAfter) { // ✅ 代码直接说明了我们的意图:获取code example(不关注如何获取) $this->exampleBefore = $this->getCodeExample($exampleBefore); $this->exampleAfter = $this->getCodeExample($exampleAfter); } // ✅ 这个新方法可多次调用 private function getCodeExample(string $exampleName): string { return file_get_contents(base_path("$exampleName.md")); }
#2 - Retour anticipé
Le retour anticipé fait référence à la pratique où l'on essaie d'éviter la nidification en décomposant la structure en cas précis. De cette façon, nous obtenons un code plus linéaire, plus facile à lire et à comprendre. N'ayez pas peur d'utiliser plusieurs instructions return.Exemple n°1
Avant
// ❌ 多重 where 语句,使阅读变得困难 // ❌ 意图究竟是什么呢? User::whereNotNull('subscribed')->where('status', 'active');Après
// ✅ 这个新的scope方法说明了发生了什么事 // ✅ 如果我们需要了解更多细节,可以进入这个scope方法内部去了解 // ✅ "subscribed" scope 方法可在其他地方使用 User::subscribed();Exemple n°2 Avant
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.'); } }Après
protected function handle(): void { // ✅ handle方法是你访问该类首先会查看的方法 // ✅ 现在可以很容易就对这个方法做了些什么有个粗略的了解 $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.'); } // ✅ 不要害怕使用多行代码 // ✅ 这个例子中它让我们核心的 handle 方法更为简洁 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.'); } }Remarque : Parfois, vous entendrez le terme « déclaration défensive » qui est renvoyé par retour anticipé accomplir.
#3 - Restructurer en une collection
En PHP, nous utilisons des tableaux dans de nombreuses données différentes. Les fonctionnalités disponibles pour gérer et convertir ces tableaux sont très limitées et n'offrent pas une bonne expérience. (array_walk, usort, etc)
Pour résoudre ce problème, il existe un concept de classe Collection qui peut être utilisé pour vous aider à gérer les tableaux. L'implémentation la plus connue se trouve dans Laravel, où la classe collection fournit de nombreuses fonctionnalités utiles pour travailler avec des tableaux. Remarque : dans les exemples suivants, j'utiliserai la fonction d'assistance collect () de Laravel, mais elle peut être utilisée de manière similaire dans d'autres frameworks ou bibliothèques.Exemple #1
Avantpublic function calculateScore(User $user): int { if ($user->inactive) { $score = 0; } else { // ❌ 怎么又有一个 "if"? if ($user->hasBonus) { $score = $user->score + $this->bonus; } else { // ❌ 由于存在多个层级,大费眼神 ? $score = $user->score; } } return $score; }Après
public function calculateScore(User $user): int { // ✅ 边缘用例提前检测 if ($user->inactive) { return 0; } // ✅ 每个用例都有自己的代码块,使得更容易跟进 if ($user->hasBonus) { return $user->score + $this->bonus; } return $user->score; }
Exemple #2
Avantpublic function sendInvoice(Invoice $invoice): void { if($user->notificationChannel === 'Slack') { $this->notifier->slack($invoice); } else { // ❌ 即使是简单的ELSE都影响代码的可读性 $this->notifier->email($invoice); } }Après
public function sendInvoice(Invoice $invoice): bool { // ✅ 每个条件都易读 if($user->notificationChannel === 'Slack') { return $this->notifier->slack($invoice); } // ✅ 不用再考虑ELSE 指向哪里 return $this->notifier->email($invoice); }
#4 -
Chaque ligne de code ajoute une petite quantité de bruit visuel . Plus il y a de code, plus il est difficile à lire. C'est pourquoi il est important d'avoir des règles. Garder des choses comme celle-ci cohérentes vous aidera à reconnaître les codes et les modèles. Cela se traduira par moins de bruit et un code plus lisible.Exemple #1
Avant// ❌ 这里我们有一个临时变量 $score = 0; // ❌ 用循环没有问题,不过可读性还是有改善空间 foreach($this->playedGames as $game) { $score += $game->score; } return $score;Après
// ✅ 集合是带有方法的对象 // ✅ sum 方法使之更具表现力 return collect($this->playedGames) ->sum('score');Exemple #2Avant
$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], ]; // 请求结果: 只显示活跃用户,以 score 排序 ["Mary(704)","Peter(505)"] $users = array_filter($users, fn ($user) => $user['active']); // ❌ usort 进行排序处理的又是哪一个对象呢?它是如何实现? usort($users, fn($a, $b) => $a['score'] < $b['score']); // ❌ 所有的转换都是分离的,不过都是users相关的 $userHighScoreTitles = array_map(fn($user) => $user['name'] . '(' . $user['score'] . ')', $users); return $userHighScoreTitles;Après
$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], ]; // 请求结果: 只显示活跃用户,以 score 排序 ["Mary(704)","Peter(505)"] // ✅ 只传入一次users return collect($users) // ✅ 我们通过管道将其传入所有方法 ->filter(fn($user) => $user['active']) ->sortBy('score') ->map(fn($user) => "{$user['name']} ({$user['score']})" ->values() // ✅ 最后返回数组 ->toArray();
Refactor❤️ Test
J'ai déjà mentionné ça refactor ing ne change pas le code Fonction. Ceci est pratique lors de l’exécution de tests, car ils devraient également fonctionner après la refactorisation. C'est pourquoi je ne commence à refactoriser le code que lorsque j'ai des tests. Ils veilleront à ce que je ne modifie pas par inadvertance le comportement du code. Alors n'oubliez pas d'écrire des tests et même d'opter pour TDD. Apprentissage recommandé : "Tutoriel vidéo PHP"
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!