├── .gitattributes ├── .travis-build.php ├── .travis.yml ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | *.md linguist-documentation=false 2 | *.md linguist-language=PHP 3 | -------------------------------------------------------------------------------- /.travis-build.php: -------------------------------------------------------------------------------- 1 | setFlags(SplFileObject::DROP_NEW_LINE); 6 | 7 | $cliRedBackground = "\033[37;41m"; 8 | $cliReset = "\033[0m"; 9 | $exitStatus = 0; 10 | 11 | $indentationSteps = 3; 12 | $manIndex = 0; 13 | $linesWithSpaces = []; 14 | $tableOfContentsStarted = null; 15 | $currentTableOfContentsChapters = []; 16 | $chaptersFound = []; 17 | foreach ($readMeFile as $lineNumber => $line) { 18 | if (preg_match('/\s$/', $line)) { 19 | $linesWithSpaces[] = sprintf('%5s: %s', 1 + $lineNumber, $line); 20 | } 21 | if (preg_match('/^(?##+)\s(?.+)/', $line, $matches)) { 22 | if (null === $tableOfContentsStarted) { 23 | $tableOfContentsStarted = true; 24 | continue; 25 | } 26 | $tableOfContentsStarted = false; 27 | 28 | $chaptersFound[] = sprintf('%s [%s](#%s)', 29 | strlen($matches['depth']) === 2 30 | ? sprintf(' %s.', ++$manIndex) 31 | : ' *' 32 | , 33 | $matches['title'], 34 | preg_replace(['/ /', '/[^-\w]+/'], ['-', ''], strtolower($matches['title'])) 35 | ); 36 | } 37 | if ($tableOfContentsStarted === true && isset($line[0])) { 38 | $currentTableOfContentsChapters[] = $line; 39 | } 40 | } 41 | 42 | if (count($linesWithSpaces)) { 43 | fwrite(STDERR, sprintf("${cliRedBackground}The following lines end with a space character:${cliReset}\n%s\n\n", 44 | implode(PHP_EOL, $linesWithSpaces) 45 | )); 46 | $exitStatus = 1; 47 | } 48 | 49 | $currentTableOfContentsChaptersFilename = __DIR__ . '/current-chapters'; 50 | $chaptersFoundFilename = __DIR__ . '/chapters-found'; 51 | 52 | file_put_contents($currentTableOfContentsChaptersFilename, implode(PHP_EOL, $currentTableOfContentsChapters)); 53 | file_put_contents($chaptersFoundFilename, implode(PHP_EOL, $chaptersFound)); 54 | 55 | $tableOfContentsDiff = shell_exec(sprintf('diff --unified %s %s', 56 | escapeshellarg($currentTableOfContentsChaptersFilename), 57 | escapeshellarg($chaptersFoundFilename) 58 | )); 59 | 60 | @ unlink($currentTableOfContentsChaptersFilename); 61 | @ unlink($chaptersFoundFilename); 62 | 63 | if (!empty($tableOfContentsDiff)) { 64 | fwrite(STDERR, sprintf("${cliRedBackground}The table of contents is not aligned:${cliReset}\n%s\n\n", 65 | $tableOfContentsDiff 66 | )); 67 | $exitStatus = 1; 68 | } 69 | 70 | exit($exitStatus); 71 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | sudo: false 4 | 5 | php: 6 | - nightly 7 | 8 | script: php .travis-build.php 9 | 10 | notifications: 11 | email: false 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Ryan McDermott 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP Temiz Kod 2 | 3 | ## İçindekiler 4 | 5 | 1. [Giriş](#giriş) 6 | 2. [Değişkenler](#değişkenler) 7 | * [Anlamlı ve telaffuz edilebilir değişken isimleri kullanın](#anlamlı-ve-telaffuz-edilebilir-değişken-isimleri-kullanın) 8 | * [Aynı türden değişkenler için aynı kelimeleri kullanın](#aynı-türden-değişkenler-için-aynı-kelimeleri-kullanın) 9 | * [Aranabilir isimler kullanın (bölüm 1)](#aranabilir-isimler-kullanın-bölüm-1) 10 | * [Aranabilir isimler kullanın (bölüm 2)](#aranabilir-isimler-kullanın-bölüm-2) 11 | * [Açıklayıcı değişkenler kullanın](#açıklayıcı-değişkenler-kullanın) 12 | * [Çok fazla iç içe kullanımdan ve geri döndürmeden kaçının (bölüm 1)](#Çok-fazla-iç-içe-kullanımdan-ve-geri-döndürmeden-kaçının-bölüm-1) 13 | * [Çok fazla iç içe kullanımdan ve geri döndürmeden kaçının (bolum 2)](#Çok-fazla-iç-içe-kullanımdan-ve-geri-döndürmeden-kaçının-bölüm-1) 14 | * [Zihin Haritasından Kaçının](#zihin-haritasından-kaçının) 15 | * [Gereksiz bağlam eklemeyin](#gereksiz-bağlam-eklemeyin) 16 | * [Kısaltmalar veya şartlılar yerine varsayılan argümanları kullanın](#kısaltmalar-veya-şartlılar-yerine-varsayılan-argümanları-kullanın) 17 | 3. [Karşılaştırma](#karşılaştırma) 18 | * [Aynı karşılaştırmayı kullanın](#aynı-karşılaştırmayı-kullanın) 19 | 4. [Fonksiyonlar](#fonksiyonlar) 20 | * [Fonksiyon Parametreleri (2 veya daha az ideal)](#fonksiyon-parametreleri-2-veya-daha-az-ideal) 21 | * [Fonksiyonlar bir şey yapmalı](#fonksiyonlar-bir-şey-yapmalı) 22 | * [Fonksiyon isimleri ne yaptıklarını söylemeli](#fonksiyon-isimleri-ne-yaptıklarını-söylemeli) 23 | * [Fonksiyonlar sadece bir seviye soyutlama olmalıdır](#fonksiyonlar-sadece-bir-seviye-soyutlama-olmalıdır) 24 | * [Bayrakları, fonksiyon parametreleri olarak kullanmayın](#bayrakları-fonksiyon-parametreleri-olarak-kullanmayın) 25 | * [Yan Etkilerden Kaçının](#yan-etkilerden-kaçının) 26 | * [Global Fonksiyonlar yazmayın](#global-fonksiyonlar-yazmayın) 27 | * [Singleton desenini kullanmayın](#singleton-desenini-kullanmayın) 28 | * [Koşulları kapsülleyin](#koşulları-kapsülleyin) 29 | * [Olumsuz koşullardan kaçının](#olumsuz-koşullardan-kaçının) 30 | * [Koşullardan kaçının](#koşullardan-kaçının) 31 | * [Tür kontrolünden kaçının (bölüm 1)](#tür-kontrolünden-kaçının-bölüm-1) 32 | * [Tür kontrolünden kaçının (bölüm 2)](#tür-kontrolünden-kaçının-bölüm-2) 33 | * [Ölü Kodu kaldırın](#Ölü-kodu-kaldırın) 34 | 5. [Nesneler ve Veri Yapıları](#nesneler-ve-veri-yapıları) 35 | * [Nesne kapsülleme kullanın](#nesne-kapsülleme-kullanın) 36 | * [Nesnelerin `private/protected` üyelere sahip olmasını sağlayın](#nesnelerin-privateprotected-üyelere-sahip-olmasını-sağlayın) 37 | 6. [Sınıflar](#sınıflar) 38 | * [Kalıtım üzerinden birleşimi tercih edin](#kalıtım-üzerinden-birleşimi-tercih-edin) 39 | * [Akıcı (`Fluent`) arayüzlerden kaçının](#akıcı-fluent-arayüzlerden-kaçının) 40 | * [`final` sınıflarını tercih edin](#final-sınıflarını-tercih-edin) 41 | 7. [SOLID](#solid) 42 | * [Tek Sorumluluk Prensibi (SRP)](#tek-sorumluluk-prensibi-srp) 43 | * [Açık/Kapalı Prensibi (OCP)](#açıkkapalı-prensibi-ocp) 44 | * [Liskov'un Yerine Geçme Prensibi (LSP)](#liskovun-yerine-geçme-prensibi-lsp) 45 | * [Arayüz Ayırma Prensibi (ISP)](#arayüz-ayırma-prensibi-isp) 46 | * [Bağlılığı Tersine Çevirme Prensibi (DIP)](#bağlılığı-tersine-Çevirme-prensibi-dip) 47 | 8. [Kendinizi Tekrar Etmeyin (DRY)](#kendinizi-tekrar-etmeyin-dry) 48 | 9. [Çeviriler](#Çeviriler) 49 | 50 | ## Giriş 51 | 52 | Yazılım mühendisliği prensipleri,Robert C. Martin'in [*Temiz Kod*](https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882) kitabından, PHP için uyarlanmıştır. Bu bir stil kılavuzu değildir. PHP’de okunabilir, yeniden kullanılabilir ve düzenlenebilir yazılımlar üretmek için bir kılavuzdur. 53 | 54 | Buradaki her prensibe tamamen uyulmamalıdır, ve evrensel olarak daha az kabul edilecek. Bunlar ilke ve başka birşey değildir, ama bunlar *Temiz Kod* yazarlarının uzun yıllara dayanan kolektif deneyimlerine göre kodlanmıştır. 55 | 56 | [temiz-kod-javascript](https://github.com/ryanmcdermott/clean-code-javascript) den ilham alınmıştır. 57 | 58 | Çoğu geliştirici hala PHP 5 kullanıyor olsa da, bu makaledeki örneklerin çoğu sadece PHP 7.1+ ile çalışmaktadır. 59 | 60 | ## Değişkenler 61 | 62 | ### Anlamlı ve telaffuz edilebilir değişken isimleri kullanın 63 | 64 | **Kötü:** 65 | 66 | ```php 67 | $ymdstr = $moment->format('y-m-d'); 68 | ``` 69 | 70 | **İyi:** 71 | 72 | ```php 73 | $currentDate = $moment->format('y-m-d'); 74 | ``` 75 | 76 | **[⬆ yukarı çık](#İçindekiler)** 77 | 78 | ### Aynı türden değişkenler için aynı kelimeleri kullanın 79 | 80 | **Kötü:** 81 | 82 | ```php 83 | getUserInfo(); 84 | getUserData(); 85 | getUserRecord(); 86 | getUserProfile(); 87 | ``` 88 | 89 | **İyi:** 90 | 91 | ```php 92 | getUser(); 93 | ``` 94 | 95 | **[⬆ yukarı çık](#İçindekiler)** 96 | 97 | ### Aranabilir isimler kullanın (bölüm 1) 98 | 99 | Yazacağımızdan daha fazla kod okuyacağız. Önemli olan okunabilir ve aranabilir kod yazmamızdır. Değişkenleri anlamlı *isimlendirmezsek* programımızı anlamaya çalışan okuyucularımıza zarar verebiliriz. 100 | İsimleri aranabilir yapın. 101 | 102 | **Kötü:** 103 | 104 | ```php 105 | // 448 ne için ? 106 | $result = $serializer->serialize($data, 448); 107 | ``` 108 | 109 | **İyi:** 110 | 111 | ```php 112 | $json = $serializer->serialize($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); 113 | ``` 114 | 115 | ### Aranabilir isimler kullanın (bölüm 2) 116 | 117 | **Kötü:** 118 | 119 | ```php 120 | // 4 ne için? 121 | if ($user->access & 4) { 122 | // ... 123 | } 124 | ``` 125 | 126 | **İyi:** 127 | 128 | ```php 129 | class User 130 | { 131 | const ACCESS_READ = 1; 132 | const ACCESS_CREATE = 2; 133 | const ACCESS_UPDATE = 4; 134 | const ACCESS_DELETE = 8; 135 | } 136 | 137 | if ($user->access & User::ACCESS_UPDATE) { 138 | // düzenle ... 139 | } 140 | ``` 141 | 142 | **[⬆ yukarı çık](#İçindekiler)** 143 | 144 | ### Açıklayıcı değişkenler kullanın 145 | 146 | **Kötü:** 147 | 148 | ```php 149 | $address = 'One Infinite Loop, Cupertino 95014'; 150 | $cityZipCodeRegex = '/^[^,]+,\s*(.+?)\s*(\d{5})$/'; 151 | preg_match($cityZipCodeRegex, $address, $matches); 152 | 153 | saveCityZipCode($matches[1], $matches[2]); 154 | ``` 155 | 156 | **Fena Değil:** 157 | 158 | Daha iyi ama hala regex'e son derece bağlıyız. 159 | 160 | ```php 161 | $address = 'One Infinite Loop, Cupertino 95014'; 162 | $cityZipCodeRegex = '/^[^,]+,\s*(.+?)\s*(\d{5})$/'; 163 | preg_match($cityZipCodeRegex, $address, $matches); 164 | 165 | [, $city, $zipCode] = $matches; 166 | saveCityZipCode($city, $zipCode); 167 | ``` 168 | 169 | **İyi:** 170 | 171 | Alt şablonlara ad vererek regex bağımlılığını azaltın. 172 | 173 | ```php 174 | $address = 'One Infinite Loop, Cupertino 95014'; 175 | $cityZipCodeRegex = '/^[^,]+,\s*(?<city>.+?)\s*(?<zipCode>\d{5})$/'; 176 | preg_match($cityZipCodeRegex, $address, $matches); 177 | 178 | saveCityZipCode($matches['city'], $matches['zipCode']); 179 | ``` 180 | 181 | **[⬆ yukarı çık](#İçindekiler)** 182 | 183 | ### Çok fazla iç içe kullanımdan ve geri döndürmeden kaçının (bölüm 1) 184 | 185 | Çok fazla if-else ifadeleri kodun takip edilmesini zorlaştırır. Direkt olmak, dolaylı olmaktan iyidir. 186 | 187 | **Kötü:** 188 | 189 | ```php 190 | function isShopOpen($day): bool 191 | { 192 | if ($day) { 193 | if (is_string($day)) { 194 | $day = strtolower($day); 195 | if ($day === 'friday') { 196 | return true; 197 | } elseif ($day === 'saturday') { 198 | return true; 199 | } elseif ($day === 'sunday') { 200 | return true; 201 | } else { 202 | return false; 203 | } 204 | } else { 205 | return false; 206 | } 207 | } else { 208 | return false; 209 | } 210 | } 211 | ``` 212 | 213 | **İyi:** 214 | 215 | ```php 216 | function isShopOpen(string $day): bool 217 | { 218 | if (empty($day)) { 219 | return false; 220 | } 221 | 222 | $openingDays = [ 223 | 'friday', 'saturday', 'sunday' 224 | ]; 225 | 226 | return in_array(strtolower($day), $openingDays, true); 227 | } 228 | ``` 229 | 230 | **[⬆ yukarı çık](#İçindekiler)** 231 | 232 | ### Çok fazla iç içe kullanımdan ve geri döndürmeden kaçının (bölüm 2) 233 | 234 | **Kötü:** 235 | 236 | ```php 237 | function fibonacci(int $n) 238 | { 239 | if ($n < 50) { 240 | if ($n !== 0) { 241 | if ($n !== 1) { 242 | return fibonacci($n - 1) + fibonacci($n - 2); 243 | } else { 244 | return 1; 245 | } 246 | } else { 247 | return 0; 248 | } 249 | } else { 250 | return 'Not supported'; 251 | } 252 | } 253 | ``` 254 | 255 | **İyi:** 256 | 257 | ```php 258 | function fibonacci(int $n): int 259 | { 260 | if ($n === 0 || $n === 1) { 261 | return $n; 262 | } 263 | 264 | if ($n > 50) { 265 | throw new \Exception('Not supported'); 266 | } 267 | 268 | return fibonacci($n - 1) + fibonacci($n - 2); 269 | } 270 | ``` 271 | 272 | **[⬆ yukarı çık](#İçindekiler)** 273 | 274 | ### Zihin Haritasından Kaçının 275 | 276 | Okuyucuyu, kodunuzdaki değişkenin ne demek olduğunu tercüme etmek için zorlamayın. Direkt olmak, dolaylı olmaktan iyidir. 277 | 278 | **Kötü:** 279 | 280 | ```php 281 | $l = ['Austin', 'New York', 'San Francisco']; 282 | 283 | for ($i = 0; $i < count($l); $i++) { 284 | $li = $l[$i]; 285 | doStuff(); 286 | doSomeOtherStuff(); 287 | // ... 288 | // ... 289 | // ... 290 | // Bekle, yeniden `$li` ne için? 291 | dispatch($li); 292 | } 293 | ``` 294 | 295 | **İyi:** 296 | 297 | ```php 298 | $locations = ['Austin', 'New York', 'San Francisco']; 299 | 300 | foreach ($locations as $location) { 301 | doStuff(); 302 | doSomeOtherStuff(); 303 | // ... 304 | // ... 305 | // ... 306 | dispatch($location); 307 | } 308 | ``` 309 | 310 | **[⬆ yukarı çık](#İçindekiler)** 311 | 312 | ### Gereksiz bağlam eklemeyin 313 | 314 | Sınıf/Nesne isimleriniz bir şey anlatıyorsa, bunu değişken adınızda tekrarlamayın. 315 | 316 | **Kötü:** 317 | 318 | ```php 319 | class Car 320 | { 321 | public $carMake; 322 | public $carModel; 323 | public $carColor; 324 | 325 | //... 326 | } 327 | ``` 328 | 329 | **İyi:** 330 | 331 | ```php 332 | class Car 333 | { 334 | public $make; 335 | public $model; 336 | public $color; 337 | 338 | //... 339 | } 340 | ``` 341 | 342 | **[⬆ yukarı çık](#İçindekiler)** 343 | 344 | ### Kısaltmalar veya şartlılar yerine varsayılan argümanları kullanın 345 | 346 | **İyi Değil:** 347 | 348 | Bu iyi değil çünkü `$breweryName`, `NULL` olabilir. 349 | 350 | ```php 351 | function createMicrobrewery($breweryName = 'Hipster Brew Co.'): void 352 | { 353 |    // ... 354 | } 355 | ``` 356 | 357 | **Fena Değil:** 358 | 359 | Bu düşünce bir önceki versiyondan daha anlaşılır ama değişkenin değerini kontrol etse daha iyi olur. 360 | 361 | ```php 362 | function createMicrobrewery($name = null): void 363 | { 364 |    $breweryName = $name ?: 'Hipster Brew Co.'; 365 | // ... 366 | } 367 | ``` 368 | 369 | **İyi:** 370 | 371 | 372 | [tür ipucu](http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration) kullanabilirsiniz ve `$breweryName` öğesinin `NULL` olmadığından emin olun. 373 | 374 | 375 | ```php 376 | function createMicrobrewery(string $breweryName = 'Hipster Brew Co.'): void 377 | { 378 |    // ... 379 | } 380 | ``` 381 | 382 | **[⬆ yukarı çık](#İçindekiler)** 383 | 384 | ## Karşılaştırma 385 | 386 | ### [Aynı karşılaştırmayı](http://php.net/manual/en/language.operators.comparison.php) kullanın. 387 | 388 | **İyi Değil:** 389 | 390 | Basit karşılaştırma harf dizinleri bir ifadeyi tam sayıya döndürür. 391 | 392 | ```php 393 | $a = '42'; 394 | $b = 42; 395 | 396 | if ($a != $b) { 397 | // İfade her zaman geçer. 398 | } 399 | ``` 400 | `$a != $b` karşılaştırması `FALSE` değerini döndürüyor ama aslında `TRUE`! 401 | Harf dizini `42`, tam sayı olan `42` den farklıdır. 402 | 403 | **İyi:** 404 | 405 | Aynı karşılaştırma türü ve değeri karşılaştırır. 406 | 407 | ```php 408 | $a = '42'; 409 | $b = 42; 410 | 411 | if ($a !== $b) { 412 | // İfade doğrulandı. 413 | } 414 | ``` 415 | 416 | `$a !== $b` karşılaştırması `TRUE` değerini döndürür. 417 | 418 | **[⬆ yukarı çık](#İçindekiler)** 419 | 420 | 421 | ## Fonksiyonlar 422 | 423 | ### Fonksiyon Parametreleri (2 veya daha az ideal) 424 | 425 | Fonksiyon parametrelerinin miktarını sınırlamak inanılmaz derecede önemlidir çünkü fonksiyonunuzu test etmeyi kolaylaştırır. Üç *leads* ten fazlasının olması, her bir ayrı argümana sahip tonlarca farklı durumu test etmeniz gereken bir kombinatoryal patlamaya yol açar. 426 | 427 | 428 | Sıfır argümanlar ideal durumdur. Bir veya iki argüman iyidir fakat üç argümandan kaçınılmalıdır. Bundan daha fazlası birleştirilmelidir. Genellikle iki argümandan fazlası varsa fonksiyonunuz çok fazlasını yapmaya çalışır. 429 | Olmadığı durumlarda çoğu zaman yüksek seviye bir nesne bir argüman olarak yeterli olacaktır. 430 | 431 | **Kötü:** 432 | 433 | ```php 434 | function createMenu(string $title, string $body, string $buttonText, bool $cancellable): void 435 | { 436 | // ... 437 | } 438 | ``` 439 | 440 | **İyi:** 441 | 442 | ```php 443 | class MenuConfig 444 | { 445 | public $title; 446 | public $body; 447 | public $buttonText; 448 | public $cancellable = false; 449 | } 450 | 451 | $config = new MenuConfig(); 452 | $config->title = 'Foo'; 453 | $config->body = 'Bar'; 454 | $config->buttonText = 'Baz'; 455 | $config->cancellable = true; 456 | 457 | function createMenu(MenuConfig $config): void 458 | { 459 | // ... 460 | } 461 | ``` 462 | 463 | **[⬆ yukarı çık](#İçindekiler)** 464 | 465 | ### Fonksiyonlar bir şey yapmalı 466 | 467 | Bu, yazılım mühendisliğinde açık ara en önemli kuraldır. Fonksiyonlar bir şeyden fazlasını yaptığında bunları oluşturmak, test etmek ve akıl yürütmek daha zordur. Bir fonksiyonu sadece bir eyleme ayırdığında, kolayca düzenlenebilir ve kodunuz daha temiz okunacaktır. Eğer bu kılavuzdan bunda başka bir şey almazsanız bile, birçok geliştiriciden önde olacaksınız. 468 | 469 | 470 | **Kötü:** 471 | ```php 472 | function emailClients(array $clients): void 473 | { 474 | foreach ($clients as $client) { 475 | $clientRecord = $db->find($client); 476 | if ($clientRecord->isActive()) { 477 | email($client); 478 | } 479 | } 480 | } 481 | ``` 482 | 483 | **İyi:** 484 | 485 | ```php 486 | function emailClients(array $clients): void 487 | { 488 | $activeClients = activeClients($clients); 489 | array_walk($activeClients, 'email'); 490 | } 491 | 492 | function activeClients(array $clients): array 493 | { 494 | return array_filter($clients, 'isClientActive'); 495 | } 496 | 497 | function isClientActive(int $client): bool 498 | { 499 | $clientRecord = $db->find($client); 500 | 501 | return $clientRecord->isActive(); 502 | } 503 | ``` 504 | 505 | **[⬆ yukarı çık](#İçindekiler)** 506 | 507 | ### Fonksiyon isimleri ne yaptıklarını söylemeli 508 | 509 | **Kötü:** 510 | 511 | ```php 512 | class Email 513 | { 514 | //... 515 | 516 | public function handle(): void 517 | { 518 | mail($this->to, $this->subject, $this->body); 519 | } 520 | } 521 | 522 | $message = new Email(...); 523 | // Bu nedir? Mesaj için `handle` ? Şimdi bir dosyaya mı yazıyoruz ? 524 | $message->handle(); 525 | ``` 526 | 527 | **İyi:** 528 | 529 | ```php 530 | class Email 531 | { 532 | //... 533 | 534 | public function send(): void 535 | { 536 | mail($this->to, $this->subject, $this->body); 537 | } 538 | } 539 | 540 | $message = new Email(...); 541 | // Temiz ve açık 542 | $message->send(); 543 | ``` 544 | 545 | **[⬆ yukarı çık](#İçindekiler)** 546 | 547 | ### Fonksiyonlar sadece bir seviye soyutlama olmalıdır 548 | 549 | Birden fazla soyutlama seviyeniz olduğu zaman fonksiyonunuz genellikle çok fazla şey yapıyordur. Fonksiyonları ayırmak tekrar kullanılabilirlik ve daha kolay test edilebilirlik sağlar. 550 | 551 | 552 | **Kötü:** 553 | 554 | ```php 555 | function parseBetterJSAlternative(string $code): void 556 | { 557 | $regexes = [ 558 | // ... 559 | ]; 560 | 561 | $statements = explode(' ', $code); 562 | $tokens = []; 563 | foreach ($regexes as $regex) { 564 | foreach ($statements as $statement) { 565 | // ... 566 | } 567 | } 568 | 569 | $ast = []; 570 | foreach ($tokens as $token) { 571 | // lex... 572 | } 573 | 574 | foreach ($ast as $node) { 575 | // parse... 576 | } 577 | } 578 | ``` 579 | 580 | **Çok Kötü:** 581 | 582 | Bazı fonksiyonellikleri gerçekleştirdik ama `parseBetterJSAlternative()` fonksiyonu hala çok karmaşık ve test edilebilir değil. 583 | 584 | ```php 585 | function tokenize(string $code): array 586 | { 587 | $regexes = [ 588 | // ... 589 | ]; 590 | 591 | $statements = explode(' ', $code); 592 | $tokens = []; 593 | foreach ($regexes as $regex) { 594 | foreach ($statements as $statement) { 595 | $tokens[] = /* ... */; 596 | } 597 | } 598 | 599 | return $tokens; 600 | } 601 | 602 | function lexer(array $tokens): array 603 | { 604 | $ast = []; 605 | foreach ($tokens as $token) { 606 | $ast[] = /* ... */; 607 | } 608 | 609 | return $ast; 610 | } 611 | 612 | function parseBetterJSAlternative(string $code): void 613 | { 614 | $tokens = tokenize($code); 615 | $ast = lexer($tokens); 616 | foreach ($ast as $node) { 617 | // parse... 618 | } 619 | } 620 | ``` 621 | 622 | **İyi:** 623 | 624 | En iyi çözüm `parseBetterJSAlternative()` fonksiyonundaki bağımlılıkları ortadan kaldırmaktır. 625 | 626 | ```php 627 | class Tokenizer 628 | { 629 | public function tokenize(string $code): array 630 | { 631 | $regexes = [ 632 | // ... 633 | ]; 634 | 635 | $statements = explode(' ', $code); 636 | $tokens = []; 637 | foreach ($regexes as $regex) { 638 | foreach ($statements as $statement) { 639 | $tokens[] = /* ... */; 640 | } 641 | } 642 | 643 | return $tokens; 644 | } 645 | } 646 | 647 | class Lexer 648 | { 649 | public function lexify(array $tokens): array 650 | { 651 | $ast = []; 652 | foreach ($tokens as $token) { 653 | $ast[] = /* ... */; 654 | } 655 | 656 | return $ast; 657 | } 658 | } 659 | 660 | class BetterJSAlternative 661 | { 662 | private $tokenizer; 663 | private $lexer; 664 | 665 | public function __construct(Tokenizer $tokenizer, Lexer $lexer) 666 | { 667 | $this->tokenizer = $tokenizer; 668 | $this->lexer = $lexer; 669 | } 670 | 671 | public function parse(string $code): void 672 | { 673 | $tokens = $this->tokenizer->tokenize($code); 674 | $ast = $this->lexer->lexify($tokens); 675 | foreach ($ast as $node) { 676 | // parse... 677 | } 678 | } 679 | } 680 | ``` 681 | 682 | **[⬆ yukarı çık](#İçindekiler)** 683 | 684 | ### Bayrakları, fonksiyon parametreleri olarak kullanmayın. 685 | 686 | 687 | Bayraklar, kullanıcılarınıza bu fonksiyonun birden fazla şey yapacağını söyler. 688 | Fonksiyonlar bir şey yapmalıdır. Eğer bir `boolean` tabanlı farklı kod yollarını takip ediyorsanız, fonksiyonlarınızı bölün. 689 | 690 | 691 | **Kötü:** 692 | 693 | ```php 694 | function createFile(string $name, bool $temp = false): void 695 | { 696 | if ($temp) { 697 | touch('./temp/'.$name); 698 | } else { 699 | touch($name); 700 | } 701 | } 702 | ``` 703 | 704 | **İyi:** 705 | 706 | ```php 707 | function createFile(string $name): void 708 | { 709 | touch($name); 710 | } 711 | 712 | function createTempFile(string $name): void 713 | { 714 | touch('./temp/'.$name); 715 | } 716 | ``` 717 | 718 | **[⬆ yukarı çık](#İçindekiler)** 719 | 720 | ### Yan Etkilerden Kaçının 721 | 722 | Bir fonksiyon, bir değeri almak ve başka değer veya değerleri geri döndürmek dışında bir şey yaparsa bir yan etki üretir. 723 | Bir yan etki bir dosyaya yazılabilir, global değişkenleri değiştirebilir veya bir yabancıya bütün paranızı yanlışlıkla bağlayabilir. 724 | 725 | Şimdi, bir sebeple programında yan etkilere ihtiyacınız var. Önceki örnekteki gibi, belki bir dosyaya yazmanız gerekebilir. 726 | Yapmak istediğiniz şey, yaptığınızı merkezileştirmektir. Belirli bir dosyaya birkaç fonksiyon ve sınıflar yazılmasına gerek yoktur. Bunu yapan bir servis var. Bir ve sadece bir tane. 727 | 728 | Ana nokta, herhangi bir yapıya sahip olmayan nesneler arasındaki paylaşım durumu gibi ortak tuzaklardan kaçınmaktır. Herhangi bir şeye göre yazılabilen ve yan etkilerin meydana geldiği yeri merkezileştirmeyen değişebilen veri türleri kullanılmalıdır. Eğer bunu yapabiliyorsanız diğer programcıların büyük çoğunluğundan daha mutlu olacaksınız. 729 | 730 | **Kötü:** 731 | 732 | ```php 733 | // Global değişkenler, aşağıdaki fonksiyonları referans alır. 734 | // Bu ismi kullanan başka fonksiyonumuz olsaydı, şimdi bir dizi olurdu ve bozulurdu. 735 | $name = 'Ryan McDermott'; 736 | 737 | function splitIntoFirstAndLastName(): void 738 | { 739 | global $name; 740 | 741 | $name = explode(' ', $name); 742 | } 743 | 744 | splitIntoFirstAndLastName(); 745 | 746 | var_dump($name); // ['Ryan', 'McDermott']; 747 | ``` 748 | 749 | **İyi:** 750 | 751 | ```php 752 | function splitIntoFirstAndLastName(string $name): array 753 | { 754 | return explode(' ', $name); 755 | } 756 | 757 | $name = 'Ryan McDermott'; 758 | $newName = splitIntoFirstAndLastName($name); 759 | 760 | var_dump($name); // 'Ryan McDermott'; 761 | var_dump($newName); // ['Ryan', 'McDermott']; 762 | ``` 763 | 764 | **[⬆ yukarı çık](#İçindekiler)** 765 | 766 | ### Global Fonksiyonlar yazmayın 767 | 768 | Global kirletme birçok dilde kötü bir uygulama yöntemidir. Çünkü başka bir kütüphane ile çakışabilir ve API'nızın kullanıcısı ürününüzden istisna elde edene kadar bilemezdiniz. Hadi bir örnek düşünelim: Eğer konfigürasyon dizisine sahip olmak isteseniz ne olurdu? 769 | `config()` gibi global fonksiyon yazabilirsiniz ama aynı şeyi yapmaya çalışan başka bir kütüphaneyle çakışabilir. 770 | 771 | **Kötü:** 772 | 773 | ```php 774 | function config(): array 775 | { 776 | return [ 777 | 'foo' => 'bar', 778 | ] 779 | } 780 | ``` 781 | 782 | **İyi:** 783 | 784 | ```php 785 | class Configuration 786 | { 787 | private $configuration = []; 788 | 789 | public function __construct(array $configuration) 790 | { 791 | $this->configuration = $configuration; 792 | } 793 | 794 | public function get(string $key): ?string 795 | { 796 | return isset($this->configuration[$key]) ? $this->configuration[$key] : null; 797 | } 798 | } 799 | ``` 800 | 801 | Yapılandırmayı yükleyin ve `Configuration` sınıfının örneğini oluşturun. 802 | 803 | ```php 804 | $configuration = new Configuration([ 805 | 'foo' => 'bar', 806 | ]); 807 | ``` 808 | 809 | Ve şimdi uygulamanızda `Configuration` örneğini kullanmalısınız. 810 | 811 | **[⬆ yukarı çık](#İçindekiler)** 812 | 813 | ### Singleton desenini kullanmayın 814 | 815 | Singeton bir [anti-pattern'dir](https://en.wikipedia.org/wiki/Singleton_pattern). Brian Button'un yorumuyla: 816 | 1. Genellikle **global örnek** kullanırlar, neden bu kadar kötü ki? Çünkü bunları arayüzlerde göstermek yerine uygulamanızın kodlarında **bağımlılıkları saklıyorsunuz**. Global bir şeyler yapmak, [kod kokusu](https://en.wikipedia.org/wiki/Code_smell) etrafında dolaşmamaktır. 817 | 2. [Tek Sorumluluk Prensibi (SRP)](#single-responsibility-principle-srp)'ni ihlal ediyorlar : 818 | **kendi kreasyonlarını ve yaşam döngülerini kontrol ettikleri** gerçeğiyle. 819 | 3. Bunlar doğal olarak kodun sıkı sıkıya [bağlanmış](https://en.wikipedia.org/wiki/Coupling_%28computer_programming%29) olmasına neden olurlar. Birçok durumda testi zorlaştırmak için onları kandırır. 820 | 4. Uygulamanın yaşam süresi kadar durum taşıyorlar. Başka bir test yaptıktan sonra birim testleri için büyük bir hiç olan **testlerin sıralı olması gereken bir durumla karşılaşabilirsiniz.** Neden? Çünkü her birim testi diğerlerinden bağımsız olmalıdır. 821 | 822 | 823 | [Problemin kökü](http://misko.hevery.com/2008/08/25/root-cause-of-singletons/) hakkında [Misko Hevery](http://misko.hevery.com/about/) 'in çok güzel düşünceleri var. 824 | 825 | **Kötü:** 826 | 827 | ```php 828 | class DBConnection 829 | { 830 | private static $instance; 831 | 832 | private function __construct(string $dsn) 833 | { 834 | // ... 835 | } 836 | 837 | public static function getInstance(): DBConnection 838 | { 839 | if (self::$instance === null) { 840 | self::$instance = new self(); 841 | } 842 | 843 | return self::$instance; 844 | } 845 | 846 | // ... 847 | } 848 | 849 | $singleton = DBConnection::getInstance(); 850 | ``` 851 | 852 | **İyi:** 853 | 854 | ```php 855 | class DBConnection 856 | { 857 | public function __construct(string $dsn) 858 | { 859 | // ... 860 | } 861 | 862 | // ... 863 | } 864 | ``` 865 | 866 | `DBConnection` sınıfının örneğini oluşturun ve [DSN](http://php.net/manual/en/pdo.construct.php#refsect1-pdo.construct-parameters) ile yapılandırın. 867 | 868 | 869 | ```php 870 | $connection = new DBConnection($dsn); 871 | ``` 872 | 873 | Ve şimdi uygulamanızda `DBConnection` örneğini kullanmalısınız. 874 | 875 | **[⬆ yukarı çık](#İçindekiler)** 876 | 877 | ### Koşulları kapsülleyin 878 | 879 | **Kötü:** 880 | 881 | ```php 882 | if ($article->state === 'published') { 883 | // ... 884 | } 885 | ``` 886 | 887 | **İyi:** 888 | 889 | ```php 890 | if ($article->isPublished()) { 891 | // ... 892 | } 893 | ``` 894 | 895 | **[⬆ yukarı çık](#İçindekiler)** 896 | 897 | ### Olumsuz koşullardan kaçının 898 | 899 | **Kötü:** 900 | 901 | ```php 902 | function isDOMNodeNotPresent(\DOMNode $node): bool 903 | { 904 | // ... 905 | } 906 | 907 | if (!isDOMNodeNotPresent($node)) 908 | { 909 | // ... 910 | } 911 | ``` 912 | 913 | **İyi:** 914 | 915 | ```php 916 | function isDOMNodePresent(\DOMNode $node): bool 917 | { 918 | // ... 919 | } 920 | 921 | if (isDOMNodePresent($node)) { 922 | // ... 923 | } 924 | ``` 925 | 926 | **[⬆ yukarı çık](#İçindekiler)** 927 | 928 | ### Koşullardan kaçının 929 | 930 | Bu imkansız bir iş gibi görünüyor. Bunu ilk duyduğunda, birçok insan şöyle der; 931 | "Bir `if` koşulu olmadan nasıl bir şey yapayım ki?" Bunun cevabı ise çoğu durumda aynı işi gerçekleştirmek için polimorfizm(`polymorphism`) kullanabilmenizdir. Genellikle ikinci soru ise; "tamam bu harika ama neden bunu yapmak isterdim?" Bunun cevabı öğrendiğimiz bir önceki temiz kod kavramıdır: bir fonksiyon sadece bir şey yapmalı. `if` koşuluna sahip sınıflar ve fonksiyonlarınız olduğu zaman, kullanıcılarınıza fonksiyonunuzun birden fazla şey yaptığınız söylersiniz. Unutmayın, sadece bir şey yapın. 932 | 933 | **Kötü:** 934 | 935 | ```php 936 | class Airplane 937 | { 938 | // ... 939 | 940 | public function getCruisingAltitude(): int 941 | { 942 | switch ($this->type) { 943 | case '777': 944 | return $this->getMaxAltitude() - $this->getPassengerCount(); 945 | case 'Air Force One': 946 | return $this->getMaxAltitude(); 947 | case 'Cessna': 948 | return $this->getMaxAltitude() - $this->getFuelExpenditure(); 949 | } 950 | } 951 | } 952 | ``` 953 | 954 | **İyi:** 955 | 956 | ```php 957 | interface Airplane 958 | { 959 | // ... 960 | 961 | public function getCruisingAltitude(): int; 962 | } 963 | 964 | class Boeing777 implements Airplane 965 | { 966 | // ... 967 | 968 | public function getCruisingAltitude(): int 969 | { 970 | return $this->getMaxAltitude() - $this->getPassengerCount(); 971 | } 972 | } 973 | 974 | class AirForceOne implements Airplane 975 | { 976 | // ... 977 | 978 | public function getCruisingAltitude(): int 979 | { 980 | return $this->getMaxAltitude(); 981 | } 982 | } 983 | 984 | class Cessna implements Airplane 985 | { 986 | // ... 987 | 988 | public function getCruisingAltitude(): int 989 | { 990 | return $this->getMaxAltitude() - $this->getFuelExpenditure(); 991 | } 992 | } 993 | ``` 994 | 995 | **[⬆ yukarı çık](#İçindekiler)** 996 | 997 | ### Tür kontrolünden kaçının (bölüm 1) 998 | 999 | PHP türlendirilmemiş, bu da fonksiyonlarınızın herhangi bir türde argümanı alabileceğini anlamına geliyor. 1000 | Bu özgürlük bazen sizi zora sokabilir ve fonksiyonlarınızda tür kontrolü yapmak cazip hale gelir. Bunu yapmaktan kaçınmanın bir çok yolu vardır. Dikkate alınacak ilk şey tutarlı API'lardır. 1001 | 1002 | **Kötü:** 1003 | 1004 | ```php 1005 | function travelToTexas($vehicle): void 1006 | { 1007 | if ($vehicle instanceof Bicycle) { 1008 | $vehicle->pedalTo(new Location('texas')); 1009 | } elseif ($vehicle instanceof Car) { 1010 | $vehicle->driveTo(new Location('texas')); 1011 | } 1012 | } 1013 | ``` 1014 | 1015 | **İyi:** 1016 | 1017 | ```php 1018 | function travelToTexas(Traveler $vehicle): void 1019 | { 1020 | $vehicle->travelTo(new Location('texas')); 1021 | } 1022 | ``` 1023 | 1024 | **[⬆ yukarı çık](#İçindekiler)** 1025 | 1026 | ### Tür kontrolünden kaçının (bölüm 2) 1027 | 1028 | Dizeler, tamsayılar ve diziler gibi basit ilkel değerler ile çalışıyorsanız ve PHP 7+ kullanıyorsanız ve polimorfizmi kullanamıyorsanız ama yine de tür kontrolü yapmanız gerektiğini düşünüyorsanız, [tür beyanı](http://php.net/manual/en/functions.arguments.php#functions.arguments.type-declaration) veya strict(katı) modunu dikkate almalısınız. Standart PHP sözdiziminin üstünde size statik yazım sağlar. Manuel tür kontrolü ile ilgili problem, aldığınız sahte "tür-güvenliği" nin kaybolan okunabilirliği telafi etmemesi için ekstra gereksiz kelime gerektirmesidir. 1029 | PHP'nizi temiz tutun, iyi testler yazın ve iyi bir kod incelemesine sahip olun. Aksi taktirde, tüm bunları katı tür beyanı yada katı(strict) mod ile yapın. 1030 | 1031 | 1032 | **Kötü:** 1033 | 1034 | ```php 1035 | function combine($val1, $val2): int 1036 | { 1037 | if (!is_numeric($val1) || !is_numeric($val2)) { 1038 | throw new \Exception('Must be of type Number'); 1039 | } 1040 | 1041 | return $val1 + $val2; 1042 | } 1043 | ``` 1044 | 1045 | **İyi:** 1046 | 1047 | ```php 1048 | function combine(int $val1, int $val2): int 1049 | { 1050 | return $val1 + $val2; 1051 | } 1052 | ``` 1053 | 1054 | **[⬆ yukarı çık](#İçindekiler)** 1055 | 1056 | ### Ölü kodu kaldırın 1057 | 1058 | Ölü kod, tekrarlanan kod kadar kötüdür. Kod tabanınızda tutmak için bir sebep yok. Eğer çağrılmıyorsa ondan kurtulun! Hala ihtiyacınız varsa versiyon geçmişinizde hala güvende olacak. 1059 | 1060 | **Kötü:** 1061 | 1062 | ```php 1063 | function oldRequestModule(string $url): void 1064 | { 1065 | // ... 1066 | } 1067 | 1068 | function newRequestModule(string $url): void 1069 | { 1070 | // ... 1071 | } 1072 | 1073 | $request = newRequestModule($requestUrl); 1074 | inventoryTracker('apples', $request, 'www.inventory-awesome.io'); 1075 | ``` 1076 | 1077 | **İyi:** 1078 | 1079 | ```php 1080 | function requestModule(string $url): void 1081 | { 1082 | // ... 1083 | } 1084 | 1085 | $request = requestModule($requestUrl); 1086 | inventoryTracker('apples', $request, 'www.inventory-awesome.io'); 1087 | ``` 1088 | 1089 | **[⬆ yukarı çık](#İçindekiler)** 1090 | 1091 | 1092 | ## Nesneler ve Veri Yapıları 1093 | 1094 | ### Nesne kapsülleme kullanın 1095 | 1096 | PHP'de, metodlar için `public`, `protected` ve `private` anahtar kelimeler ayarlayabilirsiniz. Bunu kullanarak bir nesne üzerinde özellik değişikliklerini kontrol edebilirsiniz. 1097 | 1098 | * Nesne özelliği elde etmenin ötesinde daha fazlasını yapmak istediğinizde, kod tabanınızdaki her erişimciyi aramanıza ve değiştirmenize gerek yoktur. 1099 | * Bir `set` yaparken doğrulama ekleyerek basitleştirir. 1100 | * İçsel temsili dahil eder. 1101 | * Alma ve ayarlama yapılırken kaydetme(loglama) ve hata işlemeyi eklemek kolaydır. 1102 | * Bu sınıfı miras olarak alırken, varsayılan fonksiyonelliği geçersiz kılabilirsiniz. 1103 | * Nesnenin özelliklerini ağır yükletebilirsiniz, bir sunucudan almayı söyleyelim. ([Lazy Load](https://en.wikipedia.org/wiki/Lazy_loading)) 1104 | 1105 | 1106 | Ek olarak, bu [Açık/Kapalı](#openclosed-principle-ocp) prensibinin bir parçasıdır. 1107 | 1108 | **Kötü:** 1109 | 1110 | ```php 1111 | class BankAccount 1112 | { 1113 | public $balance = 1000; 1114 | } 1115 | 1116 | $bankAccount = new BankAccount(); 1117 | 1118 | // Ayakkabı al... 1119 | $bankAccount->balance -= 100; 1120 | ``` 1121 | 1122 | **İyi:** 1123 | 1124 | ```php 1125 | class BankAccount 1126 | { 1127 | private $balance; 1128 | 1129 | public function __construct(int $balance = 1000) 1130 | { 1131 | $this->balance = $balance; 1132 | } 1133 | 1134 | public function withdraw(int $amount): void 1135 | { 1136 | if ($amount > $this->balance) { 1137 | throw new \Exception('Amount greater than available balance.'); 1138 | } 1139 | 1140 | $this->balance -= $amount; 1141 | } 1142 | 1143 | public function deposit(int $amount): void 1144 | { 1145 | $this->balance += $amount; 1146 | } 1147 | 1148 |    public function getBalance(): int 1149 | { 1150 | return $this->balance; 1151 | } 1152 | } 1153 | 1154 | $bankAccount = new BankAccount(); 1155 | 1156 | // Ayakkabı al... 1157 | $bankAccount->withdraw($shoesPrice); 1158 | 1159 | // Bakiyeyi al 1160 | $balance = $bankAccount->getBalance(); 1161 | ``` 1162 | 1163 | **[⬆ yukarı çık](#İçindekiler)** 1164 | 1165 | ### Nesnelerin private/protected üyelere sahip olmasını sağlayın 1166 | 1167 | * `public` metodları ve özellikleri değişiklikler için çok tehlikelidir çünkü bazı dış kodlar bunlara kolaylıkla güvenebilir ve hangi kodun onlara bağlı olduğunu kontrol edemezsiniz. **Sınıftaki değişiklikler, sınıfın tüm kullanıcıları için tehlikelidir.** 1168 | * `protected` değiştiricileri, `public` kadar tehlikelidir çünkü herhangi bir çocuk sınıfı kapsamındadırlar. 1169 | Bu public ve protected arasındaki farkın yalnızca erişim mekanizmasında olduğunu ama kapsülleme garantisinin aynı kaldığı anlamına gelir. **Sınıftaki değişiklikler tüm alt sınıflar için tehlikelidir.** 1170 | * `private` değiştiricileri kodun **sadece tek bir sınıfın sınırları içinde değiştirilmesinin tehlikeli olduğunu** garanti eder (değişiklikler için güvendesiniz ve [Jenga etkisinde](http://www.urbandictionary.com/define.php?term=Jengaphobia&defid=2494196) olmayacaksın). 1171 | 1172 | Bu sebeple, varsayılan olarak `private` kullanın ve harici sınıflara erişim sağlamanız gerektiğinde `public/protected` kullanın. 1173 | 1174 | Daha fazla bilgi için, bu konuda [Fabien Potencier](https://github.com/fabpot)'ın yazdığı [blog yazısını](http://fabien.potencier.org/pragmatism-over-theory-protected-vs-private.html) okuyabilirsiniz. 1175 | 1176 | 1177 | **Kötü:** 1178 | 1179 | ```php 1180 | class Employee 1181 | { 1182 | public $name; 1183 | 1184 | public function __construct(string $name) 1185 | { 1186 | $this->name = $name; 1187 | } 1188 | } 1189 | 1190 | $employee = new Employee('John Doe'); 1191 | echo 'Employee name: '.$employee->name; // Çalışan Adı: John Doe 1192 | ``` 1193 | 1194 | **İyi:** 1195 | 1196 | ```php 1197 | class Employee 1198 | { 1199 | private $name; 1200 | 1201 | public function __construct(string $name) 1202 | { 1203 | $this->name = $name; 1204 | } 1205 | 1206 | public function getName(): string 1207 | { 1208 | return $this->name; 1209 | } 1210 | } 1211 | 1212 | $employee = new Employee('John Doe'); 1213 | echo 'Employee name: '.$employee->getName(); // Çalışan Adı: John Doe 1214 | ``` 1215 | 1216 | **[⬆ yukarı çık](#İçindekiler)** 1217 | 1218 | ## Sınıflar 1219 | 1220 | ### Kalıtım üzerinden birleşimi tercih edin 1221 | 1222 | Gang of Four(Dörtlü Çete)'un ünlü [*Tasarım Desenleri*](https://en.wikipedia.org/wiki/Design_Patterns)'nde belirtildiği gibi, yapabileceğiniz yerlerde kompozisyonu kalıtıma tercih etmelisiniz. Kalıtımın kullanılması için pek çok iyi sebep ve kompozisyon kullanmak için birçok iyi sebep vardır. Bu ilkenin ana noktası, eğer aklınız içgüdüsel olarak kalıtıma giderse, kompozisyonun problemini daha iyi modellemeyi düşünmeye çalışın. Bazı durumlarda yapabilir. 1223 | 1224 | O zaman merak ediyor olabilirsiniz, "kalıtımımı ne zaman kullanmalıyım?" Bu senin probleminize bağlı ama kalıtımın kompozisyondan daha anlamlı olduğu zamanın iyi bir listesidir: 1225 | 1226 | 1. Kalıtımınız "bir" ilişkiyi temsil eder ve ilişkinin "bir" ilişkisi yoktur (Human->Animal vs. User->UserDetails). 1227 | 2. Temel sınıflardan kodu tekrar kullanabilirsiniz (İnsanlar tüm hayvanlar gibi hareket edebilir). 1228 | 3. Bir temel sınıfı değiştirerek türetilmiş sınıflarda global değişiklikler yapmak istersiniz (Hareket ettikleri zaman tüm hayvanların kalori giderlerini değiştirin). 1229 | 1230 | 1231 | **Kötü:** 1232 | 1233 | ```php 1234 | class Employee 1235 | { 1236 | private $name; 1237 | private $email; 1238 | 1239 | public function __construct(string $name, string $email) 1240 | { 1241 | $this->name = $name; 1242 | $this->email = $email; 1243 | } 1244 | 1245 | // ... 1246 | } 1247 | 1248 | // Kötü çünkü Employees vergi verileri "var". 1249 | // EmployeeTaxData bir Employee türü değil. 1250 | 1251 | class EmployeeTaxData extends Employee 1252 | { 1253 | private $ssn; 1254 | private $salary; 1255 | 1256 | public function __construct(string $name, string $email, string $ssn, string $salary) 1257 | { 1258 | parent::__construct($name, $email); 1259 | 1260 | $this->ssn = $ssn; 1261 | $this->salary = $salary; 1262 | } 1263 | 1264 | // ... 1265 | } 1266 | ``` 1267 | 1268 | **İyi:** 1269 | 1270 | ```php 1271 | class EmployeeTaxData 1272 | { 1273 | private $ssn; 1274 | private $salary; 1275 | 1276 | public function __construct(string $ssn, string $salary) 1277 | { 1278 | $this->ssn = $ssn; 1279 | $this->salary = $salary; 1280 | } 1281 | 1282 | // ... 1283 | } 1284 | 1285 | class Employee 1286 | { 1287 | private $name; 1288 | private $email; 1289 | private $taxData; 1290 | 1291 | public function __construct(string $name, string $email) 1292 | { 1293 | $this->name = $name; 1294 | $this->email = $email; 1295 | } 1296 | 1297 | public function setTaxData(string $ssn, string $salary) 1298 | { 1299 | $this->taxData = new EmployeeTaxData($ssn, $salary); 1300 | } 1301 | 1302 | // ... 1303 | } 1304 | ``` 1305 | 1306 | **[⬆ yukarı çık](#İçindekiler)** 1307 | 1308 | ### Akıcı (Fluent) arayüzlerden kaçının 1309 | 1310 | [Akıcı arayüz](https://en.wikipedia.org/wiki/Fluent_interface), [Metod Zincirleme](https://en.wikipedia.org/wiki/Method_chaining) kullanarak kaynak kodun okunabilirliği arttırmaya çalışan nesne tabanlı bir API'dir. 1311 | 1312 | 1313 | Bazı bağlamlar olsa da kodun (Örneğin [PHPUnit Mock Builder](https://phpunit.de/manual/current/en/test-doubles.html) 1314 | veya [Doctrine Query Builder](http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/query-builder.html)) ayrıntılarını azalttığı sıklıkla yapıcı madde olsa da, sıklıkla bir bedeli vardır: 1315 | 1316 | 1317 | 1. [Kapsüllemeyi](https://en.wikipedia.org/wiki/Encapsulation_%28object-oriented_programming%29) bozar. 1318 | 2. [Dekoratörleri](https://en.wikipedia.org/wiki/Decorator_pattern) bozar. 1319 | 3. Testte [sahte nesne](https://en.wikipedia.org/wiki/Mock_object) kullanmak daha zordur. 1320 | 4. Okuması zor olan farklı işlemler yapar. 1321 | 1322 | Daha fazla bilgi için, bu konuda [Marco Pivetta](https://github.com/Ocramius) 'nın yazdığı [blog yazısını](https://ocramius.github.io/blog/fluent-interfaces-are-evil/) okuyabilirsiniz. 1323 | 1324 | **Kötü:** 1325 | 1326 | ```php 1327 | class Car 1328 | { 1329 | private $make = 'Honda'; 1330 | private $model = 'Accord'; 1331 | private $color = 'white'; 1332 | 1333 | public function setMake(string $make): self 1334 | { 1335 | $this->make = $make; 1336 | 1337 | // NOT: Bunu zincirleme için döndüyor. 1338 | return $this; 1339 | } 1340 | 1341 | public function setModel(string $model): self 1342 | { 1343 | $this->model = $model; 1344 | 1345 | // NOT: Bunu zincirleme için döndüyor. 1346 | return $this; 1347 | } 1348 | 1349 | public function setColor(string $color): self 1350 | { 1351 | $this->color = $color; 1352 | 1353 | // NOT: Bunu zincirleme için döndüyor. 1354 | return $this; 1355 | } 1356 | 1357 | public function dump(): void 1358 | { 1359 | var_dump($this->make, $this->model, $this->color); 1360 | } 1361 | } 1362 | 1363 | $car = (new Car()) 1364 | ->setColor('pink') 1365 | ->setMake('Ford') 1366 | ->setModel('F-150') 1367 | ->dump(); 1368 | ``` 1369 | 1370 | **İyi:** 1371 | 1372 | ```php 1373 | class Car 1374 | { 1375 | private $make = 'Honda'; 1376 | private $model = 'Accord'; 1377 | private $color = 'white'; 1378 | 1379 | public function setMake(string $make): void 1380 | { 1381 | $this->make = $make; 1382 | } 1383 | 1384 | public function setModel(string $model): void 1385 | { 1386 | $this->model = $model; 1387 | } 1388 | 1389 | public function setColor(string $color): void 1390 | { 1391 | $this->color = $color; 1392 | } 1393 | 1394 | public function dump(): void 1395 | { 1396 | var_dump($this->make, $this->model, $this->color); 1397 | } 1398 | } 1399 | 1400 | $car = new Car(); 1401 | $car->setColor('pink'); 1402 | $car->setMake('Ford'); 1403 | $car->setModel('F-150'); 1404 | $car->dump(); 1405 | ``` 1406 | 1407 | **[⬆ yukarı çık](#İçindekiler)** 1408 | 1409 | ### final sınıflarını tercih edin 1410 | 1411 | `final` mümkün olduğunda kullanılmalıdır: 1412 | 1413 | 1. Kontrolsüz kalıtım zincirini önler. 1414 | 2. [Kompozisyon](#prefer-composition-over-inheritance)u teşvik eder. 1415 | 3. [Tek Sorumluluk Desenini](#single-responsibility-principle-srp) teşvik der. 1416 | 4. Geliştiricilerin, protected metodlara erişmek için sınıfı geliştirmesi yerine public metodlarınızı kullanmasını teşvik eder. 1417 | 5. Sınıfını kullanmayan uygulamalarda bozulma olmadan kodunu değiştirmene izin verir. 1418 | 1419 | Tek şart sınıfınızın arayüz kullanmasıdır ve başka hiçbir metod tanımlanmamasıdır. 1420 | 1421 | Daha fazla bilgi için, bu konuda [Marco Pivetta (Ocramius)](https://ocramius.github.io/) 'nın yazdığı [blog yazısını](https://ocramius.github.io/blog/when-to-declare-classes-final/) okuyabilirsiniz. 1422 | 1423 | 1424 | **Kötü:** 1425 | 1426 | ```php 1427 | final class Car 1428 | { 1429 | private $color; 1430 | 1431 | public function __construct($color) 1432 | { 1433 | $this->color = $color; 1434 | } 1435 | 1436 | /** 1437 | * @return string The color of the vehicle 1438 | */ 1439 | public function getColor() 1440 | { 1441 | return $this->color; 1442 | } 1443 | } 1444 | ``` 1445 | 1446 | **İyi:** 1447 | 1448 | ```php 1449 | interface Vehicle 1450 | { 1451 | /** 1452 | * @return string The color of the vehicle 1453 | */ 1454 | public function getColor(); 1455 | } 1456 | 1457 | final class Car implements Vehicle 1458 | { 1459 | private $color; 1460 | 1461 | public function __construct($color) 1462 | { 1463 | $this->color = $color; 1464 | } 1465 | 1466 | /** 1467 | * {@inheritdoc} 1468 | */ 1469 | public function getColor() 1470 | { 1471 | return $this->color; 1472 | } 1473 | } 1474 | ``` 1475 | 1476 | **[⬆ yukarı çık](#İçindekiler)** 1477 | 1478 | ## SOLID 1479 | 1480 | **SOLID**, Robert Martin'in bahsettiği ilk beş prensip için Michael Feathers tarafından ortaya çıkarılmış bir mnemonik kısaltmadır. 1481 | 1482 | 1483 | * [S: Tek Sorumluluk Prensibi (SRP)](#single-responsibility-principle-srp) 1484 | * [O: Açık/Kapalı Prensibi (OCP)](#openclosed-principle-ocp) 1485 | * [L: Liskov'un Yerine Geçme Prensibi (LSP)](#liskov-substitution-principle-lsp) 1486 | * [I: Arayüz Ayırma Prensibi (ISP)](#interface-segregation-principle-isp) 1487 | * [D: Bağlılığı Tersine Çevirme Prensibi (DIP)](#dependency-inversion-principle-dip) 1488 | 1489 | ### Tek Sorumluluk Prensibi (SRP) 1490 | 1491 | Temiz Kodda belirtildiği gibi, "Bir sınıfın değişmesi için asla birden fazla sebep olmamalıdır". Bir sınıfı, uçuşunuzda sadece bir bavul alabildiğiniz gibi tek fonksiyonellikle sıkıştırmak daha caziptir. Bununla ilgili bir sorun, sınıfınızın kavramsal olarak birleşemeyeceği ve değişmesi için birçok sebep vereceğidir. Bir sınıfı değiştirmek için gereken süreyi en aza indirmek önemlidir. Bu önemlidir çünkü bir sınıfta çok fazla fonksiyonellik varsa ve bir parçasını değiştirirsen, kod tabanınızda bulunan diğer bağımlı modülleri nasıl etkileyeceğini kestirmek zordur. 1492 | 1493 | **Kötü:** 1494 | 1495 | ```php 1496 | class UserSettings 1497 | { 1498 | private $user; 1499 | 1500 | public function __construct(User $user) 1501 | { 1502 | $this->user = $user; 1503 | } 1504 | 1505 | public function changeSettings(array $settings): void 1506 | { 1507 | if ($this->verifyCredentials()) { 1508 | // ... 1509 | } 1510 | } 1511 | 1512 | private function verifyCredentials(): bool 1513 | { 1514 | // ... 1515 | } 1516 | } 1517 | ``` 1518 | 1519 | **İyi:** 1520 | 1521 | ```php 1522 | class UserAuth 1523 | { 1524 | private $user; 1525 | 1526 | public function __construct(User $user) 1527 | { 1528 | $this->user = $user; 1529 | } 1530 | 1531 | public function verifyCredentials(): bool 1532 | { 1533 | // ... 1534 | } 1535 | } 1536 | 1537 | class UserSettings 1538 | { 1539 | private $user; 1540 | private $auth; 1541 | 1542 | public function __construct(User $user) 1543 | { 1544 | $this->user = $user; 1545 | $this->auth = new UserAuth($user); 1546 | } 1547 | 1548 | public function changeSettings(array $settings): void 1549 | { 1550 | if ($this->auth->verifyCredentials()) { 1551 | // ... 1552 | } 1553 | } 1554 | } 1555 | ``` 1556 | 1557 | **[⬆ yukarı çık](#İçindekiler)** 1558 | 1559 | ### Açık/Kapalı Prensibi (OCP) 1560 | 1561 | Bertrand Meyer'in belirttiği gibi, "yazılım varlıkları (sınıflar, modüller, fonksiyonlar vb.) ilaveye açık olmalı ama değişiklik için kapatılmalıdır." Bu ne anlama geliyor? Bu prensip temel olarak kullanıcıların mevcut kodu değiştirmeden yeni fonksiyonlar eklemelerine izin vermeniz gerektiğini belirtir. 1562 | 1563 | **Kötü:** 1564 | 1565 | ```php 1566 | abstract class Adapter 1567 | { 1568 | protected $name; 1569 | 1570 | public function getName(): string 1571 | { 1572 | return $this->name; 1573 | } 1574 | } 1575 | 1576 | class AjaxAdapter extends Adapter 1577 | { 1578 | public function __construct() 1579 | { 1580 | parent::__construct(); 1581 | 1582 | $this->name = 'ajaxAdapter'; 1583 | } 1584 | } 1585 | 1586 | class NodeAdapter extends Adapter 1587 | { 1588 | public function __construct() 1589 | { 1590 | parent::__construct(); 1591 | 1592 | $this->name = 'nodeAdapter'; 1593 | } 1594 | } 1595 | 1596 | class HttpRequester 1597 | { 1598 | private $adapter; 1599 | 1600 | public function __construct(Adapter $adapter) 1601 | { 1602 | $this->adapter = $adapter; 1603 | } 1604 | 1605 | public function fetch(string $url): Promise 1606 | { 1607 | $adapterName = $this->adapter->getName(); 1608 | 1609 | if ($adapterName === 'ajaxAdapter') { 1610 | return $this->makeAjaxCall($url); 1611 | } elseif ($adapterName === 'httpNodeAdapter') { 1612 | return $this->makeHttpCall($url); 1613 | } 1614 | } 1615 | 1616 | private function makeAjaxCall(string $url): Promise 1617 | { 1618 | // request and return promise 1619 | } 1620 | 1621 | private function makeHttpCall(string $url): Promise 1622 | { 1623 | // request and return promise 1624 | } 1625 | } 1626 | ``` 1627 | 1628 | **İyi:** 1629 | 1630 | ```php 1631 | interface Adapter 1632 | { 1633 | public function request(string $url): Promise; 1634 | } 1635 | 1636 | class AjaxAdapter implements Adapter 1637 | { 1638 | public function request(string $url): Promise 1639 | { 1640 | // request and return promise 1641 | } 1642 | } 1643 | 1644 | class NodeAdapter implements Adapter 1645 | { 1646 | public function request(string $url): Promise 1647 | { 1648 | // request and return promise 1649 | } 1650 | } 1651 | 1652 | class HttpRequester 1653 | { 1654 | private $adapter; 1655 | 1656 | public function __construct(Adapter $adapter) 1657 | { 1658 | $this->adapter = $adapter; 1659 | } 1660 | 1661 | public function fetch(string $url): Promise 1662 | { 1663 | return $this->adapter->request($url); 1664 | } 1665 | } 1666 | ``` 1667 | 1668 | **[⬆ yukarı çık](#İçindekiler)** 1669 | 1670 | ### Liskov'un Yerine Geçme Prensibi (LSP) 1671 | 1672 | Bu çok basit bir kavram için korkutucu bir terimdir. "Eğer S, T'nin bir alt türüyse, o zaman T tipi nesneler bu programın istenen özelliklerinden herhangi birini değiştirmeden S tipi (Örneğin, S türündeki nesneler T türündeki nesnelerin yerine geçebilir) nesnelerle değiştirilebilir (uygunluk, yapılan görev, vb.)." Bu daha da korkunç bir açıklamadır. 1673 | 1674 | Bunun için en iyi açıklama, bir ebeveyn ve bir çocuk sınıfınız varsa yanlış sonuçlar almadan, çocuk sınıfı ve temel sınıfı dönüşümlü olarak değiştirilebilir. Bu hala kafa karıştırıcı olabilir. Bu yüzden klasik, Kare-Dikdörtgen örneğine bir bakalım. Matematiksel olarak kare bir dikdörtgendir ama kalıtım aracığıyla ama bunu ilişkiyi kullanarak modelliyorsanız, kısa sürede başınız ağrıyabilir. 1675 | 1676 | **Kötü:** 1677 | 1678 | ```php 1679 | class Rectangle 1680 | { 1681 | protected $width = 0; 1682 | protected $height = 0; 1683 | 1684 | public function setWidth(int $width): void 1685 | { 1686 | $this->width = $width; 1687 | } 1688 | 1689 | public function setHeight(int $height): void 1690 | { 1691 | $this->height = $height; 1692 | } 1693 | 1694 | public function getArea(): int 1695 | { 1696 | return $this->width * $this->height; 1697 | } 1698 | } 1699 | 1700 | class Square extends Rectangle 1701 | { 1702 | public function setWidth(int $width): void 1703 | { 1704 | $this->width = $this->height = $width; 1705 | } 1706 | 1707 | public function setHeight(int $height): void 1708 | { 1709 | $this->width = $this->height = $height; 1710 | } 1711 | } 1712 | 1713 | function printArea(Rectangle $rectangle): void 1714 | { 1715 | $rectangle->setWidth(4); 1716 | $rectangle->setHeight(5); 1717 | 1718 | // BAD: Will return 25 for Square. Should be 20. 1719 | echo sprintf('%s has area %d.', get_class($rectangle), $rectangle->getArea()).PHP_EOL; 1720 | } 1721 | 1722 | $rectangles = [new Rectangle(), new Square()]; 1723 | 1724 | foreach ($rectangles as $rectangle) { 1725 | printArea($rectangle); 1726 | } 1727 | ``` 1728 | 1729 | **İyi:** 1730 | 1731 | En iyi yöntem dörtgenlerini ayırmak ve iki şekil için de daha genel bir alt türü ayrıştırmaktır. 1732 | 1733 | Kare ve dikdörtgen görüntüde benzer olsa da aslında farklılardır. Bir kare, eşkenar dikdörtgene daha benzerdir, bir dikdörtgen de paralelkenara daha benzerdir ama alt tür değillerdir. Bir kare, bir dikdörtgen bir eşkenar dikdörtgen ve bir paralelkenar kendi özellikleri olan farklı şekillerdir. Fakat benzerlerdir. 1734 | 1735 | 1736 | ```php 1737 | interface Shape 1738 | { 1739 | public function getArea(): int; 1740 | } 1741 | 1742 | class Rectangle implements Shape 1743 | { 1744 | private $width = 0; 1745 | private $height = 0; 1746 | 1747 | public function __construct(int $width, int $height) 1748 | { 1749 | $this->width = $width; 1750 | $this->height = $height; 1751 | } 1752 | 1753 | public function getArea(): int 1754 | { 1755 | return $this->width * $this->height; 1756 | } 1757 | } 1758 | 1759 | class Square implements Shape 1760 | { 1761 | private $length = 0; 1762 | 1763 | public function __construct(int $length) 1764 | { 1765 | $this->length = $length; 1766 | } 1767 | 1768 | public function getArea(): int 1769 | { 1770 |        return $this->length ** 2; 1771 |    } 1772 | } 1773 | 1774 | function printArea(Shape $shape): void 1775 | { 1776 | echo sprintf('%s has area %d.', get_class($shape), $shape->getArea()).PHP_EOL; 1777 | } 1778 | 1779 | $shapes = [new Rectangle(4, 5), new Square(5)]; 1780 | 1781 | foreach ($shapes as $shape) { 1782 | printArea($shape); 1783 | } 1784 | ``` 1785 | 1786 | **[⬆ yukarı çık](#İçindekiler)** 1787 | 1788 | ### Arayüz Ayırma Prensibi (ISP) 1789 | 1790 | ISP, "Müşteriler kullanmadıkları arayüzlere bağlı olmaya zorlanmamalıdır." der. 1791 | 1792 | Bu prensibi gösteren iyi bir örneğe bakarsak, büyük ayarlama nesnelerine ihtiyaç duyan sınıflar sınıflar vardır. Müşterinin, çok fazla sayıda seçenek kurmaya ihtiyacı olmaması yararlıdır. Çünkü genelde o ayarlamaların hepsine ihtiyaçları olmayacaktır. Onları opsiyonel yapmak "şişman arayüz" olmasını engeller. 1793 | 1794 | **Kötü:** 1795 | 1796 | ```php 1797 | interface Employee 1798 | { 1799 | public function work(): void; 1800 | 1801 | public function eat(): void; 1802 | } 1803 | 1804 | class HumanEmployee implements Employee 1805 | { 1806 | public function work(): void 1807 | { 1808 | // ....çalışıyor 1809 | } 1810 | 1811 | public function eat(): void 1812 | { 1813 | // ...... öğle arasında yemek yiyor 1814 | } 1815 | } 1816 | 1817 | class RobotEmployee implements Employee 1818 | { 1819 | public function work(): void 1820 | { 1821 | //.... çok daha fazla çalışıyor 1822 | } 1823 | 1824 | public function eat(): void 1825 | { 1826 | //.... robot yemek yemez ama bu metodu uygulamak zorundadır 1827 | } 1828 | } 1829 | ``` 1830 | 1831 | **İyi:** 1832 | 1833 | Her işçi bir çalışan değil ama her çalışan bir işçidir. 1834 | 1835 | ```php 1836 | interface Workable 1837 | { 1838 | public function work(): void; 1839 | } 1840 | 1841 | interface Feedable 1842 | { 1843 | public function eat(): void; 1844 | } 1845 | 1846 | interface Employee extends Feedable, Workable 1847 | { 1848 | } 1849 | 1850 | class HumanEmployee implements Employee 1851 | { 1852 | public function work(): void 1853 | { 1854 | // ....çalışıyor 1855 | } 1856 | 1857 | public function eat(): void 1858 | { 1859 | //.... öğle arasında yemek yiyor 1860 | } 1861 | } 1862 | 1863 | // robot sadece çalışabilir 1864 | class RobotEmployee implements Workable 1865 | { 1866 | public function work(): void 1867 | { 1868 | // ....çalışıyor 1869 | } 1870 | } 1871 | ``` 1872 | 1873 | **[⬆ yukarı çık](#İçindekiler)** 1874 | 1875 | ### Bağlılığı Tersine Çevirme Prensibi (DIP) 1876 | 1877 | Bu prensip iki temel öğeyi barındırır: 1878 | 1. Yüksek seviyeli modüller, düşük seviyeli modüllere bağlı olmamalıdır. İkisi de soyutlamaya bağlı olmalıdır. 1879 | 2. Soyutlamalar, detaylara bağlı olmamalıdır. Detaylar, soyutlamalara bağlı olmalıdır. 1880 | 1881 | Bunu başta anlamak zordur ama PHP frameworkleri(Symfony gibi) ile çalıştıysanız, Dependency Injection (DI) formunda bu prensibin uygulandığını görmüşsünüzdür. Aynı konseptler olmadıklarında DIP düşük seviyeli modüllerinin detaylarını bilerek yüksek seviyeli modülleri saklar ve ayarlar. Bunu DI üzerinden tamamlayabilir. Bunun en büyük yararlarından biri de modüller arasındaki eşleşmeyi azaltır. Eşleşme çok kötü bir geliştirme desenidir çünkü kodunuzu yeniden düzenlemeyi zorlaştırır. 1882 | 1883 | **Kötü:** 1884 | 1885 | ```php 1886 | class Employee 1887 | { 1888 | public function work(): void 1889 | { 1890 | // ....çalışıyor 1891 | } 1892 | } 1893 | 1894 | class Robot extends Employee 1895 | { 1896 | public function work(): void 1897 | { 1898 | //.... çok daha fazla çalışıyor 1899 | } 1900 | } 1901 | 1902 | class Manager 1903 | { 1904 | private $employee; 1905 | 1906 | public function __construct(Employee $employee) 1907 | { 1908 | $this->employee = $employee; 1909 | } 1910 | 1911 | public function manage(): void 1912 | { 1913 | $this->employee->work(); 1914 | } 1915 | } 1916 | ``` 1917 | 1918 | **İyi:** 1919 | 1920 | ```php 1921 | interface Employee 1922 | { 1923 | public function work(): void; 1924 | } 1925 | 1926 | class Human implements Employee 1927 | { 1928 | public function work(): void 1929 | { 1930 | // ....çalışıyor 1931 | } 1932 | } 1933 | 1934 | class Robot implements Employee 1935 | { 1936 | public function work(): void 1937 | { 1938 | //.... çok daha fazla çalışıyor 1939 | } 1940 | } 1941 | 1942 | class Manager 1943 | { 1944 | private $employee; 1945 | 1946 | public function __construct(Employee $employee) 1947 | { 1948 | $this->employee = $employee; 1949 | } 1950 | 1951 | public function manage(): void 1952 | { 1953 | $this->employee->work(); 1954 | } 1955 | } 1956 | ``` 1957 | 1958 | **[⬆ yukarı çık](#İçindekiler)** 1959 | 1960 | ## Kendinizi Tekrar Etmeyin (DRY) 1961 | 1962 | [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) prensibini gözlemlemeye çalışın. 1963 | 1964 | Tekrarlanan kodlardan kaçınmak için mutlaka en iyisini yapın. Tekrarlanan kod kötüdür çünkü bir mantığı değiştirmek gerekirse bir şeyi değiştirmek için birden fazla yer olduğu anlamına geliyor. 1965 | 1966 | Bir restoran işlettiğinizi düşünün ve malzeme takibini yapıyorsunuz: tüm domates, soğan, sarımsak, baharat, ve benzerlerinin. Bu işte birden çok liste kullanırsanız içinde domates olan bir yemek servis ettiğinizde tüm listeleri güncellemeniz gerekir. Sadece bir listeniz olursa, güncelleyecek sadece bir yer olur. 1967 | 1968 | 1969 | Genelde tekrarlanan kod vardır çünkü iki veya daha fazla çok az farklı şey vardır. Birçok ortak yönleri vardır ama farklılıkları, oldukça benzer şeyleri yapan iki veya daha fazla ayrı fonksiyonunuzun olmasına sizi zorlar. Tekrarlayan kodları kaldırmak, bir dizi farklı şeyleri sadece bir fonksiyon/modül/sınıf ile halledebilen soyutlamalar oluşturmak demektir. 1970 | 1971 | 1972 | Soyutlamayı doğru yapmak çok önemlidir. Bu yüzden [Sınıflar](#classes) bölümündeki SOLID prensiplerini izlemelisiniz. Kötü soyutlamalar, tekrarlanan kodlardan daha kötü olabilir, o yüzden dikkat edin! Söylediğim gibi, iyi bir soyutlama yapabiliyorsanız, yapın! Kendinizi tekrar etmeyin, yoksa bir şeyi değiştirmek istediğiniz zaman kendinizi birçok yeri güncellerken bulursunuz. 1973 | 1974 | **Kötü:** 1975 | 1976 | ```php 1977 | function showDeveloperList(array $developers): void 1978 | { 1979 | foreach ($developers as $developer) { 1980 | $expectedSalary = $developer->calculateExpectedSalary(); 1981 | $experience = $developer->getExperience(); 1982 | $githubLink = $developer->getGithubLink(); 1983 | $data = [ 1984 | $expectedSalary, 1985 | $experience, 1986 | $githubLink 1987 | ]; 1988 | 1989 | render($data); 1990 | } 1991 | } 1992 | 1993 | function showManagerList(array $managers): void 1994 | { 1995 | foreach ($managers as $manager) { 1996 | $expectedSalary = $manager->calculateExpectedSalary(); 1997 | $experience = $manager->getExperience(); 1998 | $githubLink = $manager->getGithubLink(); 1999 | $data = [ 2000 | $expectedSalary, 2001 | $experience, 2002 | $githubLink 2003 | ]; 2004 | 2005 | render($data); 2006 | } 2007 | } 2008 | ``` 2009 | 2010 | **İyi:** 2011 | 2012 | ```php 2013 | function showList(array $employees): void 2014 | { 2015 | foreach ($employees as $employee) { 2016 | $expectedSalary = $employee->calculateExpectedSalary(); 2017 | $experience = $employee->getExperience(); 2018 | $githubLink = $employee->getGithubLink(); 2019 | $data = [ 2020 | $expectedSalary, 2021 | $experience, 2022 | $githubLink 2023 | ]; 2024 | 2025 | render($data); 2026 | } 2027 | } 2028 | ``` 2029 | 2030 | **Çok İyi:** 2031 | 2032 | Kodun kompakt bir versiyonunu kullanmak iyidir. 2033 | 2034 | ```php 2035 | function showList(array $employees): void 2036 | { 2037 | foreach ($employees as $employee) { 2038 | render([ 2039 | $employee->calculateExpectedSalary(), 2040 | $employee->getExperience(), 2041 | $employee->getGithubLink() 2042 | ]); 2043 | } 2044 | } 2045 | ``` 2046 | 2047 | **[⬆ yukarı çık](#İçindekiler)** 2048 | 2049 | ## Çeviriler 2050 | 2051 | Başka diller de mevcuttur: 2052 | 2053 | * :cn: **Çince:** 2054 | * [php-cpm/clean-code-php](https://github.com/php-cpm/clean-code-php) 2055 | * :ru: **Rusça:** 2056 | * [peter-gribanov/clean-code-php](https://github.com/peter-gribanov/clean-code-php) 2057 | * :es: **İspanyolca:** 2058 | * [fikoborquez/clean-code-php](https://github.com/fikoborquez/clean-code-php) 2059 | * :brazil: **Portekizce:** 2060 | * [fabioars/clean-code-php](https://github.com/fabioars/clean-code-php) 2061 | * [jeanjar/clean-code-php](https://github.com/jeanjar/clean-code-php/tree/pt-br) 2062 | * :thailand: **Tayca:** 2063 | * [panuwizzle/clean-code-php](https://github.com/panuwizzle/clean-code-php) 2064 | * :fr: **Fransızca:** 2065 | * [errorname/clean-code-php](https://github.com/errorname/clean-code-php) 2066 | * :vietnam: **Vietnamca** 2067 | * [viethuongdev/clean-code-php](https://github.com/viethuongdev/clean-code-php) 2068 | * :kr: **Korece:** 2069 | * [yujineeee/clean-code-php](https://github.com/yujineeee/clean-code-php) 2070 | * :tr: **Türkçe:** 2071 | * [anilozmen/clean-code-php](https://github.com/anilozmen/clean-code-php) 2072 | 2073 | **[⬆ yukarı çık](#İçindekiler)** 2074 | --------------------------------------------------------------------------------