Skip to content

anilozmen/clean-code-php

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

PHP Temiz Kod

─░├žindekiler

  1. Giri┼č
  2. De─či┼čkenler
  3. Kar┼č─▒la┼čt─▒rma
  4. Fonksiyonlar
  5. Nesneler ve Veri Yap─▒lar─▒
  6. S─▒n─▒flar
  7. SOLID
  8. Kendinizi Tekrar Etmeyin (DRY)
  9. Çeviriler

Giri┼č

Yaz─▒l─▒m m├╝hendisli─či prensipleri,Robert C. Martin'in Temiz Kod 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.

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.

temiz-kod-javascript den ilham al─▒nm─▒┼čt─▒r.

├ço─ču geli┼čtirici hala PHP 5 kullan─▒yor olsa da, bu makaledeki ├Ârneklerin ├žo─ču sadece PHP 7.1+ ile ├žal─▒┼čmaktad─▒r.

De─či┼čkenler

Anlaml─▒ ve telaffuz edilebilir de─či┼čken isimleri kullan─▒n

K├Ât├╝:

$ymdstr = $moment->format('y-m-d');

─░yi:

$currentDate = $moment->format('y-m-d');

ÔČć yukar─▒ ├ž─▒k

Ayn─▒ t├╝rden de─či┼čkenler i├žin ayn─▒ kelimeleri kullan─▒n

K├Ât├╝:

getUserInfo();
getUserData();
getUserRecord();
getUserProfile();

─░yi:

getUser();

ÔČć yukar─▒ ├ž─▒k

Aranabilir isimler kullan─▒n (b├Âl├╝m 1)

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. ─░simleri aranabilir yap─▒n.

K├Ât├╝:

// 448 ne i├žin ?
$result = $serializer->serialize($data, 448);

─░yi:

$json = $serializer->serialize($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

Aranabilir isimler kullan─▒n (b├Âl├╝m 2)

K├Ât├╝:

// 4 ne i├žin?
if ($user->access & 4) {
    // ...
}

─░yi:

class User
{
    const ACCESS_READ = 1;
    const ACCESS_CREATE = 2;
    const ACCESS_UPDATE = 4;
    const ACCESS_DELETE = 8;
}

if ($user->access & User::ACCESS_UPDATE) {
    // d├╝zenle ...
}

ÔČć yukar─▒ ├ž─▒k

A├ž─▒klay─▒c─▒ de─či┼čkenler kullan─▒n

K├Ât├╝:

$address = 'One Infinite Loop, Cupertino 95014';
$cityZipCodeRegex = '/^[^,]+,\s*(.+?)\s*(\d{5})$/';
preg_match($cityZipCodeRegex, $address, $matches);

saveCityZipCode($matches[1], $matches[2]);

Fena De─čil:

Daha iyi ama hala regex'e son derece ba─čl─▒y─▒z.

$address = 'One Infinite Loop, Cupertino 95014';
$cityZipCodeRegex = '/^[^,]+,\s*(.+?)\s*(\d{5})$/';
preg_match($cityZipCodeRegex, $address, $matches);

[, $city, $zipCode] = $matches;
saveCityZipCode($city, $zipCode);

─░yi:

Alt ┼čablonlara ad vererek regex ba─č─▒ml─▒l─▒─č─▒n─▒ azalt─▒n.

$address = 'One Infinite Loop, Cupertino 95014';
$cityZipCodeRegex = '/^[^,]+,\s*(?<city>.+?)\s*(?<zipCode>\d{5})$/';
preg_match($cityZipCodeRegex, $address, $matches);

saveCityZipCode($matches['city'], $matches['zipCode']);

ÔČć yukar─▒ ├ž─▒k

├çok fazla i├ž i├že kullan─▒mdan ve geri d├Ând├╝rmeden ka├ž─▒n─▒n (b├Âl├╝m 1)

├çok fazla if-else ifadeleri kodun takip edilmesini zorla┼čt─▒r─▒r. Direkt olmak, dolayl─▒ olmaktan iyidir.

K├Ât├╝:

function isShopOpen($day): bool
{
    if ($day) {
        if (is_string($day)) {
            $day = strtolower($day);
            if ($day === 'friday') {
                return true;
            } elseif ($day === 'saturday') {
                return true;
            } elseif ($day === 'sunday') {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    } else {
        return false;
    }
}

─░yi:

function isShopOpen(string $day): bool
{
    if (empty($day)) {
        return false;
    }

    $openingDays = [
        'friday', 'saturday', 'sunday'
    ];

    return in_array(strtolower($day), $openingDays, true);
}

ÔČć yukar─▒ ├ž─▒k

├çok fazla i├ž i├že kullan─▒mdan ve geri d├Ând├╝rmeden ka├ž─▒n─▒n (b├Âl├╝m 2)

K├Ât├╝:

function fibonacci(int $n)
{
    if ($n < 50) {
        if ($n !== 0) {
            if ($n !== 1) {
                return fibonacci($n - 1) + fibonacci($n - 2);
            } else {
                return 1;
            }
        } else {
            return 0;
        }
    } else {
        return 'Not supported';
    }
}

─░yi:

function fibonacci(int $n): int
{
    if ($n === 0 || $n === 1) {
        return $n;
    }

    if ($n > 50) {
        throw new \Exception('Not supported');
    }

    return fibonacci($n - 1) + fibonacci($n - 2);
}

ÔČć yukar─▒ ├ž─▒k

Zihin Haritas─▒ndan Ka├ž─▒n─▒n

Okuyucuyu, kodunuzdaki de─či┼čkenin ne demek oldu─čunu terc├╝me etmek i├žin zorlamay─▒n. Direkt olmak, dolayl─▒ olmaktan iyidir.

K├Ât├╝:

$l = ['Austin', 'New York', 'San Francisco'];

for ($i = 0; $i < count($l); $i++) {
    $li = $l[$i];
    doStuff();
    doSomeOtherStuff();
    // ...
    // ...
    // ...
    // Bekle, yeniden `$li` ne i├žin?
    dispatch($li);
}

─░yi:

$locations = ['Austin', 'New York', 'San Francisco'];

foreach ($locations as $location) {
    doStuff();
    doSomeOtherStuff();
    // ...
    // ...
    // ...
    dispatch($location);
}

ÔČć yukar─▒ ├ž─▒k

Gereksiz ba─člam eklemeyin

S─▒n─▒f/Nesne isimleriniz bir ┼čey anlat─▒yorsa, bunu de─či┼čken ad─▒n─▒zda tekrarlamay─▒n.

K├Ât├╝:

class Car
{
    public $carMake;
    public $carModel;
    public $carColor;

    //...
}

─░yi:

class Car
{
    public $make;
    public $model;
    public $color;

    //...
}

ÔČć yukar─▒ ├ž─▒k

K─▒saltmalar veya ┼čartl─▒lar yerine varsay─▒lan arg├╝manlar─▒ kullan─▒n

─░yi De─čil:

Bu iyi de─čil ├ž├╝nk├╝ $breweryName, NULL olabilir.

function createMicrobrewery($breweryName = 'Hipster Brew Co.'): void
{
    // ...
}

Fena De─čil:

Bu d├╝┼č├╝nce bir ├Ânceki versiyondan daha anla┼č─▒l─▒r ama de─či┼čkenin de─čerini kontrol etse daha iyi olur.

function createMicrobrewery($name = null): void
{
    $breweryName = $name ?: 'Hipster Brew Co.';
    // ...
}

─░yi:

t├╝r ipucu kullanabilirsiniz ve $breweryName ├Â─česinin NULL olmad─▒─č─▒ndan emin olun.

function createMicrobrewery(string $breweryName = 'Hipster Brew Co.'): void
{
    // ...
}

ÔČć yukar─▒ ├ž─▒k

Kar┼č─▒la┼čt─▒rma

─░yi De─čil:

Basit kar┼č─▒la┼čt─▒rma harf dizinleri bir ifadeyi tam say─▒ya d├Ând├╝r├╝r.

$a = '42';
$b = 42;

if ($a != $b) {
   // ─░fade her zaman ge├žer.
}

$a != $b kar┼č─▒la┼čt─▒rmas─▒ FALSE de─čerini d├Ând├╝r├╝yor ama asl─▒nda TRUE! Harf dizini 42, tam say─▒ olan 42 den farkl─▒d─▒r.

─░yi:

Ayn─▒ kar┼č─▒la┼čt─▒rma t├╝r├╝ ve de─čeri kar┼č─▒la┼čt─▒r─▒r.

$a = '42';
$b = 42;

if ($a !== $b) {
    // ─░fade do─čruland─▒.
}

$a !== $b kar┼č─▒la┼čt─▒rmas─▒ TRUE de─čerini d├Ând├╝r├╝r.

ÔČć yukar─▒ ├ž─▒k

Fonksiyonlar

Fonksiyon Parametreleri (2 veya daha az ideal)

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.

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. Olmad─▒─č─▒ durumlarda ├žo─ču zaman y├╝ksek seviye bir nesne bir arg├╝man olarak yeterli olacakt─▒r.

K├Ât├╝:

function createMenu(string $title, string $body, string $buttonText, bool $cancellable): void
{
    // ...
}

─░yi:

class MenuConfig
{
    public $title;
    public $body;
    public $buttonText;
    public $cancellable = false;
}

$config = new MenuConfig();
$config->title = 'Foo';
$config->body = 'Bar';
$config->buttonText = 'Baz';
$config->cancellable = true;

function createMenu(MenuConfig $config): void
{
    // ...
}

ÔČć yukar─▒ ├ž─▒k

Fonksiyonlar bir ┼čey yapmal─▒

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.

K├Ât├╝:

function emailClients(array $clients): void
{
    foreach ($clients as $client) {
        $clientRecord = $db->find($client);
        if ($clientRecord->isActive()) {
            email($client);
        }
    }
}

─░yi:

function emailClients(array $clients): void
{
    $activeClients = activeClients($clients);
    array_walk($activeClients, 'email');
}

function activeClients(array $clients): array
{
    return array_filter($clients, 'isClientActive');
}

function isClientActive(int $client): bool
{
    $clientRecord = $db->find($client);

    return $clientRecord->isActive();
}

ÔČć yukar─▒ ├ž─▒k

Fonksiyon isimleri ne yapt─▒klar─▒n─▒ s├Âylemeli

K├Ât├╝:

class Email
{
    //...

    public function handle(): void
    {
        mail($this->to, $this->subject, $this->body);
    }
}

$message = new Email(...);
// Bu nedir? Mesaj i├žin `handle` ? ┼×imdi bir dosyaya m─▒ yaz─▒yoruz ?
$message->handle();

─░yi:

class Email 
{
    //...

    public function send(): void
    {
        mail($this->to, $this->subject, $this->body);
    }
}

$message = new Email(...);
// Temiz ve a├ž─▒k
$message->send();

ÔČć yukar─▒ ├ž─▒k

Fonksiyonlar sadece bir seviye soyutlama olmal─▒d─▒r

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.

K├Ât├╝:

function parseBetterJSAlternative(string $code): void
{
    $regexes = [
        // ...
    ];

    $statements = explode(' ', $code);
    $tokens = [];
    foreach ($regexes as $regex) {
        foreach ($statements as $statement) {
            // ...
        }
    }

    $ast = [];
    foreach ($tokens as $token) {
        // lex...
    }

    foreach ($ast as $node) {
        // parse...
    }
}

├çok K├Ât├╝:

Baz─▒ fonksiyonellikleri ger├žekle┼čtirdik ama parseBetterJSAlternative() fonksiyonu hala ├žok karma┼č─▒k ve test edilebilir de─čil.

function tokenize(string $code): array
{
    $regexes = [
        // ...
    ];

    $statements = explode(' ', $code);
    $tokens = [];
    foreach ($regexes as $regex) {
        foreach ($statements as $statement) {
            $tokens[] = /* ... */;
        }
    }

    return $tokens;
}

function lexer(array $tokens): array
{
    $ast = [];
    foreach ($tokens as $token) {
        $ast[] = /* ... */;
    }

    return $ast;
}

function parseBetterJSAlternative(string $code): void
{
    $tokens = tokenize($code);
    $ast = lexer($tokens);
    foreach ($ast as $node) {
        // parse...
    }
}

─░yi:

En iyi ├ž├Âz├╝m parseBetterJSAlternative() fonksiyonundaki ba─č─▒ml─▒l─▒klar─▒ ortadan kald─▒rmakt─▒r.

class Tokenizer
{
    public function tokenize(string $code): array
    {
        $regexes = [
            // ...
        ];

        $statements = explode(' ', $code);
        $tokens = [];
        foreach ($regexes as $regex) {
            foreach ($statements as $statement) {
                $tokens[] = /* ... */;
            }
        }

        return $tokens;
    }
}

class Lexer
{
    public function lexify(array $tokens): array
    {
        $ast = [];
        foreach ($tokens as $token) {
            $ast[] = /* ... */;
        }

        return $ast;
    }
}

class BetterJSAlternative
{
    private $tokenizer;
    private $lexer;

    public function __construct(Tokenizer $tokenizer, Lexer $lexer)
    {
        $this->tokenizer = $tokenizer;
        $this->lexer = $lexer;
    }

    public function parse(string $code): void
    {
        $tokens = $this->tokenizer->tokenize($code);
        $ast = $this->lexer->lexify($tokens);
        foreach ($ast as $node) {
            // parse...
        }
    }
}

ÔČć yukar─▒ ├ž─▒k

Bayraklar─▒, fonksiyon parametreleri olarak kullanmay─▒n.

Bayraklar, kullan─▒c─▒lar─▒n─▒za bu fonksiyonun birden fazla ┼čey yapaca─č─▒n─▒ s├Âyler. Fonksiyonlar bir ┼čey yapmal─▒d─▒r. E─čer bir boolean tabanl─▒ farkl─▒ kod yollar─▒n─▒ takip ediyorsan─▒z, fonksiyonlar─▒n─▒z─▒ b├Âl├╝n.

K├Ât├╝:

function createFile(string $name, bool $temp = false): void
{
    if ($temp) {
        touch('./temp/'.$name);
    } else {
        touch($name);
    }
}

─░yi:

function createFile(string $name): void
{
    touch($name);
}

function createTempFile(string $name): void
{
    touch('./temp/'.$name);
}

ÔČć yukar─▒ ├ž─▒k

Yan Etkilerden Ka├ž─▒n─▒n

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. 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.

┼×imdi, bir sebeple program─▒nda yan etkilere ihtiyac─▒n─▒z var. ├ľnceki ├Ârnekteki gibi, belki bir dosyaya yazman─▒z gerekebilir. 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.

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.

K├Ât├╝:

// Global de─či┼čkenler, a┼ča─č─▒daki fonksiyonlar─▒ referans al─▒r.
// Bu ismi kullanan ba┼čka fonksiyonumuz olsayd─▒, ┼čimdi bir dizi olurdu ve bozulurdu.
$name = 'Ryan McDermott';

function splitIntoFirstAndLastName(): void
{
    global $name;

    $name = explode(' ', $name);
}

splitIntoFirstAndLastName();

var_dump($name); // ['Ryan', 'McDermott'];

─░yi:

function splitIntoFirstAndLastName(string $name): array
{
    return explode(' ', $name);
}

$name = 'Ryan McDermott';
$newName = splitIntoFirstAndLastName($name);

var_dump($name); // 'Ryan McDermott';
var_dump($newName); // ['Ryan', 'McDermott'];

ÔČć yukar─▒ ├ž─▒k

Global Fonksiyonlar yazmay─▒n

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? config() gibi global fonksiyon yazabilirsiniz ama ayn─▒ ┼čeyi yapmaya ├žal─▒┼čan ba┼čka bir k├╝t├╝phaneyle ├žak─▒┼čabilir.

K├Ât├╝:

function config(): array
{
    return  [
        'foo' => 'bar',
    ]
}

─░yi:

class Configuration
{
    private $configuration = [];

    public function __construct(array $configuration)
    {
        $this->configuration = $configuration;
    }

    public function get(string $key): ?string
    {
        return isset($this->configuration[$key]) ? $this->configuration[$key] : null;
    }
}

Yap─▒land─▒rmay─▒ y├╝kleyin ve Configuration s─▒n─▒f─▒n─▒n ├Ârne─čini olu┼čturun.

$configuration = new Configuration([
    'foo' => 'bar',
]);

Ve ┼čimdi uygulaman─▒zda Configuration ├Ârne─čini kullanmal─▒s─▒n─▒z.

ÔČć yukar─▒ ├ž─▒k

Singleton desenini kullanmay─▒n

Singeton bir anti-pattern'dir. Brian Button'un yorumuyla:

  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 etraf─▒nda dola┼čmamakt─▒r.
  2. Tek Sorumluluk Prensibi (SRP)'ni ihlal ediyorlar : kendi kreasyonlar─▒n─▒ ve ya┼čam d├Âng├╝lerini kontrol ettikleri ger├že─čiyle.
  3. Bunlar do─čal olarak kodun s─▒k─▒ s─▒k─▒ya ba─članm─▒┼č olmas─▒na neden olurlar. Bir├žok durumda testi zorla┼čt─▒rmak i├žin onlar─▒ kand─▒r─▒r.
  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.

Problemin k├Âk├╝ hakk─▒nda Misko Hevery 'in ├žok g├╝zel d├╝┼č├╝nceleri var.

K├Ât├╝:

class DBConnection
{
    private static $instance;

    private function __construct(string $dsn)
    {
        // ...
    }

    public static function getInstance(): DBConnection
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }

        return self::$instance;
    }

    // ...
}

$singleton = DBConnection::getInstance();

─░yi:

class DBConnection
{
    public function __construct(string $dsn)
    {
        // ...
    }

     // ...
}

DBConnection s─▒n─▒f─▒n─▒n ├Ârne─čini olu┼čturun ve DSN ile yap─▒land─▒r─▒n.

$connection = new DBConnection($dsn);

Ve ┼čimdi uygulaman─▒zda DBConnection ├Ârne─čini kullanmal─▒s─▒n─▒z.

ÔČć yukar─▒ ├ž─▒k

Ko┼čullar─▒ kaps├╝lleyin

K├Ât├╝:

if ($article->state === 'published') {
    // ...
}

─░yi:

if ($article->isPublished()) {
    // ...
}

ÔČć yukar─▒ ├ž─▒k

Olumsuz ko┼čullardan ka├ž─▒n─▒n

K├Ât├╝:

function isDOMNodeNotPresent(\DOMNode $node): bool
{
    // ...
}

if (!isDOMNodeNotPresent($node))
{
    // ...
}

─░yi:

function isDOMNodePresent(\DOMNode $node): bool
{
    // ...
}

if (isDOMNodePresent($node)) {
    // ...
}

ÔČć yukar─▒ ├ž─▒k

Ko┼čullardan ka├ž─▒n─▒n

Bu imkans─▒z bir i┼č gibi g├Âr├╝n├╝yor. Bunu ilk duydu─čunda, bir├žok insan ┼č├Âyle der; "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.

K├Ât├╝:

class Airplane
{
    // ...

    public function getCruisingAltitude(): int
    {
        switch ($this->type) {
            case '777':
                return $this->getMaxAltitude() - $this->getPassengerCount();
            case 'Air Force One':
                return $this->getMaxAltitude();
            case 'Cessna':
                return $this->getMaxAltitude() - $this->getFuelExpenditure();
        }
    }
}

─░yi:

interface Airplane
{
    // ...

    public function getCruisingAltitude(): int;
}

class Boeing777 implements Airplane
{
    // ...

    public function getCruisingAltitude(): int
    {
        return $this->getMaxAltitude() - $this->getPassengerCount();
    }
}

class AirForceOne implements Airplane
{
    // ...

    public function getCruisingAltitude(): int
    {
        return $this->getMaxAltitude();
    }
}

class Cessna implements Airplane
{
    // ...

    public function getCruisingAltitude(): int
    {
        return $this->getMaxAltitude() - $this->getFuelExpenditure();
    }
}

ÔČć yukar─▒ ├ž─▒k

T├╝r kontrol├╝nden ka├ž─▒n─▒n (b├Âl├╝m 1)

PHP t├╝rlendirilmemi┼č, bu da fonksiyonlar─▒n─▒z─▒n herhangi bir t├╝rde arg├╝man─▒ alabilece─čini anlam─▒na geliyor. 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.

K├Ât├╝:

function travelToTexas($vehicle): void
{
    if ($vehicle instanceof Bicycle) {
        $vehicle->pedalTo(new Location('texas'));
    } elseif ($vehicle instanceof Car) {
        $vehicle->driveTo(new Location('texas'));
    }
}

─░yi:

function travelToTexas(Traveler $vehicle): void
{
    $vehicle->travelTo(new Location('texas'));
}

ÔČć yukar─▒ ├ž─▒k

T├╝r kontrol├╝nden ka├ž─▒n─▒n (b├Âl├╝m 2)

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─▒ 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. 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.

K├Ât├╝:

function combine($val1, $val2): int
{
    if (!is_numeric($val1) || !is_numeric($val2)) {
        throw new \Exception('Must be of type Number');
    }

    return $val1 + $val2;
}

─░yi:

function combine(int $val1, int $val2): int
{
    return $val1 + $val2;
}

ÔČć yukar─▒ ├ž─▒k

├ľl├╝ kodu kald─▒r─▒n

├ľ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.

K├Ât├╝:

function oldRequestModule(string $url): void
{
    // ...
}

function newRequestModule(string $url): void
{
    // ...
}

$request = newRequestModule($requestUrl);
inventoryTracker('apples', $request, 'www.inventory-awesome.io');

─░yi:

function requestModule(string $url): void
{
    // ...
}

$request = requestModule($requestUrl);
inventoryTracker('apples', $request, 'www.inventory-awesome.io');

ÔČć yukar─▒ ├ž─▒k

Nesneler ve Veri Yap─▒lar─▒

Nesne kaps├╝lleme kullan─▒n

PHP'de, metodlar i├žin public, protected ve private anahtar kelimeler ayarlayabilirsiniz. Bunu kullanarak bir nesne ├╝zerinde ├Âzellik de─či┼čikliklerini kontrol edebilirsiniz.

  • 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.
  • Bir set yaparken do─črulama ekleyerek basitle┼čtirir.
  • ─░├žsel temsili dahil eder.
  • Alma ve ayarlama yap─▒l─▒rken kaydetme(loglama) ve hata i┼člemeyi eklemek kolayd─▒r.
  • Bu s─▒n─▒f─▒ miras olarak al─▒rken, varsay─▒lan fonksiyonelli─či ge├žersiz k─▒labilirsiniz.
  • Nesnenin ├Âzelliklerini a─č─▒r y├╝kletebilirsiniz, bir sunucudan almay─▒ s├Âyleyelim. (Lazy Load)

Ek olarak, bu A├ž─▒k/Kapal─▒ prensibinin bir par├žas─▒d─▒r.

K├Ât├╝:

class BankAccount
{
    public $balance = 1000;
}

$bankAccount = new BankAccount();

// Ayakkab─▒ al...
$bankAccount->balance -= 100;

─░yi:

class BankAccount
{
    private $balance;

    public function __construct(int $balance = 1000)
    {
      $this->balance = $balance;
    }

    public function withdraw(int $amount): void
    {
        if ($amount > $this->balance) {
            throw new \Exception('Amount greater than available balance.');
        }

        $this->balance -= $amount;
    }

    public function deposit(int $amount): void
    {
        $this->balance += $amount;
    }

    public function getBalance(): int
    {
        return $this->balance;
    }
}

$bankAccount = new BankAccount();

// Ayakkab─▒ al...
$bankAccount->withdraw($shoesPrice);

// Bakiyeyi al
$balance = $bankAccount->getBalance();

ÔČć yukar─▒ ├ž─▒k

Nesnelerin private/protected ├╝yelere sahip olmas─▒n─▒ sa─člay─▒n

  • 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.
  • protected de─či┼čtiricileri, public kadar tehlikelidir ├ž├╝nk├╝ herhangi bir ├žocuk s─▒n─▒f─▒ kapsam─▒ndad─▒rlar. 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.
  • 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 olmayacaks─▒n).

Bu sebeple, varsay─▒lan olarak private kullan─▒n ve harici s─▒n─▒flara eri┼čim sa─člaman─▒z gerekti─činde public/protected kullan─▒n.

Daha fazla bilgi i├žin, bu konuda Fabien Potencier'─▒n yazd─▒─č─▒ blog yaz─▒s─▒n─▒ okuyabilirsiniz.

K├Ât├╝:

class Employee
{
    public $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }
}

$employee = new Employee('John Doe');
echo 'Employee name: '.$employee->name; // ├çal─▒┼čan Ad─▒: John Doe

─░yi:

class Employee
{
    private $name;

    public function __construct(string $name)
    {
        $this->name = $name;
    }

    public function getName(): string
    {
        return $this->name;
    }
}

$employee = new Employee('John Doe');
echo 'Employee name: '.$employee->getName(); // ├çal─▒┼čan Ad─▒: John Doe

ÔČć yukar─▒ ├ž─▒k

S─▒n─▒flar

Kal─▒t─▒m ├╝zerinden birle┼čimi tercih edin

Gang of Four(D├Ârtl├╝ ├çete)'un ├╝nl├╝ Tasar─▒m Desenleri'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.

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:

  1. Kal─▒t─▒m─▒n─▒z "bir" ili┼čkiyi temsil eder ve ili┼čkinin "bir" ili┼čkisi yoktur (Human->Animal vs. User->UserDetails).
  2. Temel s─▒n─▒flardan kodu tekrar kullanabilirsiniz (─░nsanlar t├╝m hayvanlar gibi hareket edebilir).
  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).

K├Ât├╝:

class Employee 
{
    private $name;
    private $email;

    public function __construct(string $name, string $email)
    {
        $this->name = $name;
        $this->email = $email;
    }

    // ...
}

// K├Ât├╝ ├ž├╝nk├╝ Employees vergi verileri "var".
// EmployeeTaxData bir Employee t├╝r├╝ de─čil.

class EmployeeTaxData extends Employee 
{
    private $ssn;
    private $salary;
    
    public function __construct(string $name, string $email, string $ssn, string $salary)
    {
        parent::__construct($name, $email);

        $this->ssn = $ssn;
        $this->salary = $salary;
    }

    // ...
}

─░yi:

class EmployeeTaxData 
{
    private $ssn;
    private $salary;

    public function __construct(string $ssn, string $salary)
    {
        $this->ssn = $ssn;
        $this->salary = $salary;
    }

    // ...
}

class Employee 
{
    private $name;
    private $email;
    private $taxData;

    public function __construct(string $name, string $email)
    {
        $this->name = $name;
        $this->email = $email;
    }

    public function setTaxData(string $ssn, string $salary)
    {
        $this->taxData = new EmployeeTaxData($ssn, $salary);
    }

    // ...
}

ÔČć yukar─▒ ├ž─▒k

Ak─▒c─▒ (Fluent) aray├╝zlerden ka├ž─▒n─▒n

Ak─▒c─▒ aray├╝z, Metod Zincirleme kullanarak kaynak kodun okunabilirli─či artt─▒rmaya ├žal─▒┼čan nesne tabanl─▒ bir API'dir.

Baz─▒ ba─člamlar olsa da kodun (├ľrne─čin PHPUnit Mock Builder veya Doctrine Query Builder) ayr─▒nt─▒lar─▒n─▒ azaltt─▒─č─▒ s─▒kl─▒kla yap─▒c─▒ madde olsa da, s─▒kl─▒kla bir bedeli vard─▒r:

  1. Kaps├╝llemeyi bozar.
  2. Dekorat├Ârleri bozar.
  3. Testte sahte nesne kullanmak daha zordur.
  4. Okumas─▒ zor olan farkl─▒ i┼člemler yapar.

Daha fazla bilgi i├žin, bu konuda Marco Pivetta 'n─▒n yazd─▒─č─▒ blog yaz─▒s─▒n─▒ okuyabilirsiniz.

K├Ât├╝:

class Car
{
    private $make = 'Honda';
    private $model = 'Accord';
    private $color = 'white';

    public function setMake(string $make): self
    {
        $this->make = $make;

        // NOT: Bunu zincirleme i├žin d├Ând├╝yor.
        return $this;
    }

    public function setModel(string $model): self
    {
        $this->model = $model;

        // NOT: Bunu zincirleme i├žin d├Ând├╝yor.
        return $this;
    }

    public function setColor(string $color): self
    {
        $this->color = $color;

        // NOT: Bunu zincirleme i├žin d├Ând├╝yor.
        return $this;
    }

    public function dump(): void
    {
        var_dump($this->make, $this->model, $this->color);
    }
}

$car = (new Car())
  ->setColor('pink')
  ->setMake('Ford')
  ->setModel('F-150')
  ->dump();

─░yi:

class Car
{
    private $make = 'Honda';
    private $model = 'Accord';
    private $color = 'white';

    public function setMake(string $make): void
    {
        $this->make = $make;
    }

    public function setModel(string $model): void
    {
        $this->model = $model;
    }

    public function setColor(string $color): void
    {
        $this->color = $color;
    }

    public function dump(): void
    {
        var_dump($this->make, $this->model, $this->color);
    }
}

$car = new Car();
$car->setColor('pink');
$car->setMake('Ford');
$car->setModel('F-150');
$car->dump();

ÔČć yukar─▒ ├ž─▒k

final s─▒n─▒flar─▒n─▒ tercih edin

final m├╝mk├╝n oldu─čunda kullan─▒lmal─▒d─▒r:

  1. Kontrols├╝z kal─▒t─▒m zincirini ├Ânler.
  2. Kompozisyonu te┼čvik eder.
  3. Tek Sorumluluk Desenini te┼čvik der.
  4. Geli┼čtiricilerin, protected metodlara eri┼čmek i├žin s─▒n─▒f─▒ geli┼čtirmesi yerine public metodlar─▒n─▒z─▒ kullanmas─▒n─▒ te┼čvik eder.
  5. S─▒n─▒f─▒n─▒ kullanmayan uygulamalarda bozulma olmadan kodunu de─či┼čtirmene izin verir.

Tek ┼čart s─▒n─▒f─▒n─▒z─▒n aray├╝z kullanmas─▒d─▒r ve ba┼čka hi├žbir metod tan─▒mlanmamas─▒d─▒r.

Daha fazla bilgi i├žin, bu konuda Marco Pivetta (Ocramius) 'n─▒n yazd─▒─č─▒ blog yaz─▒s─▒n─▒ okuyabilirsiniz.

K├Ât├╝:

final class Car
{
    private $color;
    
    public function __construct($color)
    {
        $this->color = $color;
    }
    
    /**
     * @return string The color of the vehicle
     */
    public function getColor() 
    {
        return $this->color;
    }
}

─░yi:

interface Vehicle
{
    /**
     * @return string The color of the vehicle
     */
    public function getColor();
}

final class Car implements Vehicle
{
    private $color;
    
    public function __construct($color)
    {
        $this->color = $color;
    }
    
    /**
     * {@inheritdoc}
     */
    public function getColor() 
    {
        return $this->color;
    }
}

ÔČć yukar─▒ ├ž─▒k

SOLID

SOLID, Robert Martin'in bahsetti─či ilk be┼č prensip i├žin Michael Feathers taraf─▒ndan ortaya ├ž─▒kar─▒lm─▒┼č bir mnemonik k─▒saltmad─▒r.

Tek Sorumluluk Prensibi (SRP)

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.

K├Ât├╝:

class UserSettings
{
    private $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }

    public function changeSettings(array $settings): void
    {
        if ($this->verifyCredentials()) {
            // ...
        }
    }

    private function verifyCredentials(): bool
    {
        // ...
    }
}

─░yi:

class UserAuth 
{
    private $user;

    public function __construct(User $user)
    {
        $this->user = $user;
    }
    
    public function verifyCredentials(): bool
    {
        // ...
    }
}

class UserSettings 
{
    private $user;
    private $auth;

    public function __construct(User $user) 
    {
        $this->user = $user;
        $this->auth = new UserAuth($user);
    }

    public function changeSettings(array $settings): void
    {
        if ($this->auth->verifyCredentials()) {
            // ...
        }
    }
}

ÔČć yukar─▒ ├ž─▒k

A├ž─▒k/Kapal─▒ Prensibi (OCP)

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.

K├Ât├╝:

abstract class Adapter
{
    protected $name;

    public function getName(): string
    {
        return $this->name;
    }
}

class AjaxAdapter extends Adapter
{
    public function __construct()
    {
        parent::__construct();

        $this->name = 'ajaxAdapter';
    }
}

class NodeAdapter extends Adapter
{
    public function __construct()
    {
        parent::__construct();

        $this->name = 'nodeAdapter';
    }
}

class HttpRequester
{
    private $adapter;

    public function __construct(Adapter $adapter)
    {
        $this->adapter = $adapter;
    }

    public function fetch(string $url): Promise
    {
        $adapterName = $this->adapter->getName();

        if ($adapterName === 'ajaxAdapter') {
            return $this->makeAjaxCall($url);
        } elseif ($adapterName === 'httpNodeAdapter') {
            return $this->makeHttpCall($url);
        }
    }

    private function makeAjaxCall(string $url): Promise
    {
        // request and return promise
    }

    private function makeHttpCall(string $url): Promise
    {
        // request and return promise
    }
}

─░yi:

interface Adapter
{
    public function request(string $url): Promise;
}

class AjaxAdapter implements Adapter
{
    public function request(string $url): Promise
    {
        // request and return promise
    }
}

class NodeAdapter implements Adapter
{
    public function request(string $url): Promise
    {
        // request and return promise
    }
}

class HttpRequester
{
    private $adapter;

    public function __construct(Adapter $adapter)
    {
        $this->adapter = $adapter;
    }

    public function fetch(string $url): Promise
    {
        return $this->adapter->request($url);
    }
}

ÔČć yukar─▒ ├ž─▒k

Liskov'un Yerine Ge├žme Prensibi (LSP)

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.

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.

K├Ât├╝:

class Rectangle
{
    protected $width = 0;
    protected $height = 0;

    public function setWidth(int $width): void
    {
        $this->width = $width;
    }

    public function setHeight(int $height): void
    {
        $this->height = $height;
    }

    public function getArea(): int
    {
        return $this->width * $this->height;
    }
}

class Square extends Rectangle
{
    public function setWidth(int $width): void
    {
        $this->width = $this->height = $width;
    }

    public function setHeight(int $height): void
    {
        $this->width = $this->height = $height;
    }
}

function printArea(Rectangle $rectangle): void
{
    $rectangle->setWidth(4);
    $rectangle->setHeight(5);
 
    // BAD: Will return 25 for Square. Should be 20.
    echo sprintf('%s has area %d.', get_class($rectangle), $rectangle->getArea()).PHP_EOL;
}

$rectangles = [new Rectangle(), new Square()];

foreach ($rectangles as $rectangle) {
    printArea($rectangle);
}

─░yi:

En iyi y├Ântem d├Ârtgenlerini ay─▒rmak ve iki ┼čekil i├žin de daha genel bir alt t├╝r├╝ ayr─▒┼čt─▒rmakt─▒r.

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.

interface Shape
{
    public function getArea(): int;
}

class Rectangle implements Shape
{
    private $width = 0;
    private $height = 0;

    public function __construct(int $width, int $height)
    {
        $this->width = $width;
        $this->height = $height;
    }

    public function getArea(): int
    {
        return $this->width * $this->height;
    }
}

class Square implements Shape
{
    private $length = 0;

    public function __construct(int $length)
    {
        $this->length = $length;
    }

    public function getArea(): int
    {
        return $this->length ** 2;
    }
}

function printArea(Shape $shape): void
{
    echo sprintf('%s has area %d.', get_class($shape), $shape->getArea()).PHP_EOL;
}

$shapes = [new Rectangle(4, 5), new Square(5)];

foreach ($shapes as $shape) {
    printArea($shape);
}

ÔČć yukar─▒ ├ž─▒k

Aray├╝z Ay─▒rma Prensibi (ISP)

ISP, "M├╝┼čteriler kullanmad─▒klar─▒ aray├╝zlere ba─čl─▒ olmaya zorlanmamal─▒d─▒r." der.

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.

K├Ât├╝:

interface Employee
{
    public function work(): void;

    public function eat(): void;
}

class HumanEmployee implements Employee
{
    public function work(): void
    {
        // ....├žal─▒┼č─▒yor
    }

    public function eat(): void
    {
        // ...... ├Â─čle aras─▒nda yemek yiyor
    }
}

class RobotEmployee implements Employee
{
    public function work(): void
    {
        //.... ├žok daha fazla ├žal─▒┼č─▒yor
    }

    public function eat(): void
    {
        //.... robot yemek yemez ama bu metodu uygulamak zorundad─▒r
    }
}

─░yi:

Her i┼č├ži bir ├žal─▒┼čan de─čil ama her ├žal─▒┼čan bir i┼č├židir.

interface Workable
{
    public function work(): void;
}

interface Feedable
{
    public function eat(): void;
}

interface Employee extends Feedable, Workable
{
}

class HumanEmployee implements Employee
{
    public function work(): void
    {
        // ....├žal─▒┼č─▒yor
    }

    public function eat(): void
    {
        //.... ├Â─čle aras─▒nda yemek yiyor
    }
}

// robot sadece ├žal─▒┼čabilir
class RobotEmployee implements Workable
{
    public function work(): void
    {
        // ....├žal─▒┼č─▒yor
    }
}

ÔČć yukar─▒ ├ž─▒k

Ba─čl─▒l─▒─č─▒ Tersine ├çevirme Prensibi (DIP)

Bu prensip iki temel ├Â─čeyi bar─▒nd─▒r─▒r:

  1. Y├╝ksek seviyeli mod├╝ller, d├╝┼č├╝k seviyeli mod├╝llere ba─čl─▒ olmamal─▒d─▒r. ─░kisi de soyutlamaya ba─čl─▒ olmal─▒d─▒r.
  2. Soyutlamalar, detaylara ba─čl─▒ olmamal─▒d─▒r. Detaylar, soyutlamalara ba─čl─▒ olmal─▒d─▒r.

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.

K├Ât├╝:

class Employee
{
    public function work(): void
    {
        // ....├žal─▒┼č─▒yor
    }
}

class Robot extends Employee
{
    public function work(): void
    {
        //.... ├žok daha fazla ├žal─▒┼č─▒yor
    }
}

class Manager
{
    private $employee;

    public function __construct(Employee $employee)
    {
        $this->employee = $employee;
    }

    public function manage(): void
    {
        $this->employee->work();
    }
}

─░yi:

interface Employee
{
    public function work(): void;
}

class Human implements Employee
{
    public function work(): void
    {
        // ....├žal─▒┼č─▒yor
    }
}

class Robot implements Employee
{
    public function work(): void
    {
        //.... ├žok daha fazla ├žal─▒┼č─▒yor
    }
}

class Manager
{
    private $employee;

    public function __construct(Employee $employee)
    {
        $this->employee = $employee;
    }

    public function manage(): void
    {
        $this->employee->work();
    }
}

ÔČć yukar─▒ ├ž─▒k

Kendinizi Tekrar Etmeyin (DRY)

DRY prensibini g├Âzlemlemeye ├žal─▒┼č─▒n.

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.

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.

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.

Soyutlamay─▒ do─čru yapmak ├žok ├Ânemlidir. Bu y├╝zden S─▒n─▒flar 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.

K├Ât├╝:

function showDeveloperList(array $developers): void
{
    foreach ($developers as $developer) {
        $expectedSalary = $developer->calculateExpectedSalary();
        $experience = $developer->getExperience();
        $githubLink = $developer->getGithubLink();
        $data = [
            $expectedSalary,
            $experience,
            $githubLink
        ];

        render($data);
    }
}

function showManagerList(array $managers): void
{
    foreach ($managers as $manager) {
        $expectedSalary = $manager->calculateExpectedSalary();
        $experience = $manager->getExperience();
        $githubLink = $manager->getGithubLink();
        $data = [
            $expectedSalary,
            $experience,
            $githubLink
        ];

        render($data);
    }
}

─░yi:

function showList(array $employees): void
{
    foreach ($employees as $employee) {
        $expectedSalary = $employee->calculateExpectedSalary();
        $experience = $employee->getExperience();
        $githubLink = $employee->getGithubLink();
        $data = [
            $expectedSalary,
            $experience,
            $githubLink
        ];

        render($data);
    }
}

Çok İyi:

Kodun kompakt bir versiyonunu kullanmak iyidir.

function showList(array $employees): void
{
    foreach ($employees as $employee) {
        render([
            $employee->calculateExpectedSalary(),
            $employee->getExperience(),
            $employee->getGithubLink()
        ]);
    }
}

ÔČć yukar─▒ ├ž─▒k

Çeviriler

Ba┼čka diller de mevcuttur:

ÔČć yukar─▒ ├ž─▒k

About

­čŤü Clean Code concepts adapted for PHP

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • PHP 100.0%