Skip to content

vimesd/phptricks

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 

Repository files navigation

Приемы для повышения чистоты кода PHP



Старайтесь делать отступы как можно меньше

До

class DiscountApplier
{
    private DiscountCalculator $calculator;

    public function __construct(DiscountCalculator $calculator)
    {
        $this->calculator = $calculator;
    }

    public function apply(Basket $basket): void
    {
        if ($basket->hasItems()) {
            $discount = 0.0;

            foreach ($basket->getItems() as $basketItem) {
                if ($basketItem->isTaxable()) {
                    if ($basketItem->getPrice() > 0) {
                        $discount += $this->calculator->getDiscount($basketItem);
                    }
                }
            }

            $basket->applyDiscount($discount);
        }
    }
}

После

class DiscountApplier
{
    private DiscountCalculator $calculator;

    public function __construct(DiscountCalculator $calculator)
    {
        $this->calculator = $calculator;
    }

    public function apply(Basket $basket): void
    {
        if (!$basket->hasItems()) {
            return;
        }

        $discount = 0.0;

        foreach ($this->getDiscountableItems($basket) as $basketItem) {
            $discount += $this->calculator->getDiscount($basketItem);
        }

        $basket->applyDiscount($discount);
    }

    /**
     * @return iterable<BasketItem>
     */
    private function getDiscountableItems(Basket $basket): iterable
    {   
        foreach ($basket->getItems() as $basketItem) {
            if (!$basketItem->isTaxable() || $basketItem->getPrice() === 0) {
                continue;
            }

            yield $basketItem;
        }
    }
}

Удаляйте ненужные блоки в условиях

До

function mapOrderStatusToLabel(Order $order): string
{
    if ($order->isComplete()) {
        return 'Completed';
    } elseif ($order->isPending()) {
        return 'In transport';
    } else {
        return 'New';
    }
}

После

function mapOrderStatusToLabel(Order $order): string
{
    if ($order->isComplete()) {
        return 'Completed';
    }

    if ($order->isPending()) {
        return 'In transport';
    }

    return 'New';
}

Меняйте местами условия, чтобы уменьшить отступы

До

function act(bool $success)
{
    if ($success) {
        // towering block of code
        // towering block of code
        // towering block of code
        // towering block of code
        // towering block of code
        // towering block of code
        // towering block of code
    } else {
        // one liner
    }
}

После

function act(bool $success)
{
    if (!$success) {
        // one liner
        return;
    }

    // towering block of code
    // towering block of code
    // towering block of code
    // towering block of code
    // towering block of code
    // towering block of code
    // towering block of code
}

Используйте switch вместо if там, где это возможно

До

function mapOrderStatusToLabel(Order $order): string
{
    $label = 'unknown';

    if ('complete' === $order->getStatus()) {
        $label = 'Completed';
    }

    if ('pending' === $order->getStatus()) {
        $label = 'In transport';
    }

    if ('new' === $order->getStatus()) {
        $label = 'New';
    }

    return $label';
}

После

function mapOrderStatusToLabel(Order $order): string
{
    switch ($order->getStatus()) {
        case 'complete':
            return 'Completed';

        case 'pending':
        case 'in_transport':
            return 'In transport';

        case 'new':
            return 'New';

        default:
            return 'unknown';
    }
}

Разбивать сложные уравнения для краткости

До

function getTotalWithTax(Payment $payment, int $taxPercent): float
{
    // is the order correct at all?

    return (float) (int) $payment->getTotal() * (1 + $taxPercent / 100);
}

После

function getTotalWithTax(Payment $payment, int $taxPercent): float
{
    // descriptive variables with intermediary values for easier debugging
    $paymentAmount = (int) $payment->getAmount();
    $taxCoefficient = 1 + ($taxPercent / 100);

    $totalWithTax = $paymentAmount * $taxCoefficient;

    return (float) $totalWithTax;
}

Расставлять условия в логическом порядке в операторах if

До

if ($httpApi->hasAccess($user) && $user->isActive() && $isSuccess) {
    // all conditions must be met in order for this condition to execute
    // in case of 'and' we should keep the heaviest conditions last
    // and the fastest to execute in front
}

После

if ($isSuccess && $user->isActive() && $httpApi->hasAccess($user)) {
    // if $isSuccess is false
    // other conditions will not be evaluated
}

Предпочитайте именованные методы флагам

До

class UserRepository
{
    public function getUsers(?bool $includingDeleted = false): array
    {
    }
}

После

class UserRepository
{
    public function getUsers(): array
    {
    }

    public function getUsersIncludingDeleted(): array
    {
    }
}

Используйте деструктуризацию массива

До

$workers = [
  ['id' => 1, 'name' => 'John Doe'],
  ['id' => 3, 'name' => 'Jane Doe'],
  ['id' => 4, 'name' => 'Monica Trullo'],
  ['id' => 5, 'name' => 'Jonathan Bank'],
];

foreach ($workers as $worker) {
  $workerId = $worker['id'];
  $workerName = $worker['name'];

  // …
}

После

$workers = [
  ['id' => 1, 'name' => 'John Doe'],
  ['id' => 3, 'name' => 'Jane Doe'],
  ['id' => 4, 'name' => 'Monica Trullo'],
  ['id' => 5, 'name' => 'Jonathan Bank'],
];

foreach ($workers as ['id' => $workerId, 'name' => $workerName]) {
  // …
}

array_column для маппинга данных

До

$userAvatars = [];
foreach ($users as $user) {
    $userAvatars[$user['id']] = $user['avatar'];
}

После

$userAvatars = array_column($users, 'avatar', 'id');

Не используйте array_merge в циклах

На каждой итерации PHP копирует массив в другой временный массив, что приводит к временному выделению памяти. С каждой последующей итерацией объем используемой памяти увеличивается.

До

$result = array();
foreach ($sources as $source) {
    $result = array_merge($result, $source);
}

После

$result = array_merge(...$sources);

Не используйте isset() для проверки существования элемента массива

До

$moneyInTheBank = [
    'John' => 10,
    'Alex' => 0,
    'Jenna' => 69,
    'Olivia' => null
];

if (!isset($moneyInTheBank['Olivia'])) {
    $moneyInTheBank['Olivia'] = 20;
}

echo $moneyInTheBank['Olivia'];

// outputs 20

После

$moneyInTheBank = [
    'John' => 10,
    'Alex' => 0,
    'Jenna' => 69,
    'Olivia' => null
];

if (!array_key_exists('Olivia', $moneyInTheBank)) {
    $moneyInTheBank['Olivia'] = 20;
}

echo $moneyInTheBank['Olivia'];

// outputs NULL

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors