Məzmuna keç
Educora
Orta20 dəq7 / 10

İnterfeyslər, trait-lər, enum-lar və Composer

İnterfeyslər və abstrakt siniflərlə müqavilələr qur, kodu trait-lərlə təkrar istifadə et, enum-larla sabit qiymətlər dəstini təsvir et və layihəni ad fəzaları və Composer ilə təşkil et.

Özünü yoxla
Bu dərsdə öyrənəcəksən
  • İnterfeys və abstrakt sinif yazmaq və onları tip kimi istifadə etmək
  • Trait-lərlə metodları siniflər arasında paylaşmaq və enum ilə sabit qiymətlər dəsti yaratmaq
  • Ad fəzalarından, Composer-dən və PSR-4 avtomatik yükləməsindən istifadə etmək

Onlayn mağazada müştəri kartla, nağd və ya mobil pul kisəsi ilə ödəyə bilər. Sifarişi rəsmiləşdirən kod üçün ödənişin necə edildiyi vacib deyil — vacib olan budur ki, ödəniş üsulunun pay metodu olsun. Bu cür «müqaviləni» PHP-də interfeys təsvir edir. Bu dərsdə böyük layihələri səliqəli saxlayan alətlərlə tanış olacaqsan.

İnterfeyslər və abstrakt siniflər

İnterfeys gövdəsiz metodların siyahısıdır. Sinif implements ilə interfeysi reallaşdırır və onun bütün metodlarını yazmağa borcludur; bir sinif bir neçə interfeysi reallaşdıra bilər. Parametrin tipi kimi interfeys yazsan, funksiya onu reallaşdıran istənilən obyekti qəbul edəcək.

PHP
<?php

interface PaymentMethod
{
    public function pay(float $amount): string;
}

class CardPayment implements PaymentMethod
{
    public function __construct(private string $last4) {}

    public function pay(float $amount): string
    {
        return "Paid $amount AZN by card *{$this->last4}";
    }
}

class CashPayment implements PaymentMethod
{
    public function pay(float $amount): string
    {
        return "Paid $amount AZN in cash";
    }
}

function checkout(PaymentMethod $method, float $total): void
{
    echo $method->pay($total), "\n";
}

checkout(new CardPayment("4821"), 35.5);
checkout(new CashPayment(), 12);
Gözlənilən nəticə
Paid 35.5 AZN by card *4821
Paid 12 AZN in cash

Abstrakt sinif interfeys ilə adi sinif arasındadır: orada həm hazır metodlar, həm də abstract elan edilmiş, gövdəsiz metodlar ola bilər. Abstrakt sinfin obyektini new ilə yaratmaq olmaz — yalnız ondan törəmə sinif yaratmaq olar. Aşağıda describe metodu bütün fiqurlar üçün ortaqdır, area isə hər fiqurda özünəməxsusdur.

PHP
<?php

abstract class Shape
{
    abstract public function area(): float;

    public function describe(): string
    {
        return static::class . " with area " . round($this->area(), 2);
    }
}

class Circle extends Shape
{
    public function __construct(private float $r) {}
    public function area(): float { return M_PI * $this->r ** 2; }
}

class Rectangle extends Shape
{
    public function __construct(private float $w, private float $h) {}
    public function area(): float { return $this->w * $this->h; }
}

foreach ([new Circle(2), new Rectangle(3, 4.5)] as $shape) {
    echo $shape->describe(), "\n";
}
Gözlənilən nəticə
Circle with area 12.57
Rectangle with area 13.5

Trait-lər

Sinfin yalnız bir valideyni ola bilər. Bəs eyni metodlar bir-biri ilə əlaqəsi olmayan bir neçə sinifdə lazımdırsa? Onda trait yaradılır — sinfin içinə use ilə «yapışdırılan» metod və xassələr toplusu. Laravel bu üsuldan geniş istifadə edir, məsələn, HasFactory və Notifiable trait-ləri.

PHP
<?php

trait HasTimestamps
{
    private ?string $createdAt = null;

    public function touch(string $date): void
    {
        $this->createdAt = $date;
    }

    public function createdAt(): string
    {
        return $this->createdAt ?? "never";
    }
}

class Post
{
    use HasTimestamps;

    public function __construct(public string $title) {}
}

class Comment
{
    use HasTimestamps;
}

$post = new Post("Hello PHP");
$post->touch("2026-09-01");
echo $post->title, ": ", $post->createdAt(), "\n";
echo (new Comment())->createdAt(), "\n";
Gözlənilən nəticə
Hello PHP: 2026-09-01
never

Enum-lar

Sifarişin statusu yalnız bir neçə qiymətdən biri ola bilər. PHP 8.1-dən belə dəstləri enum (sadalanan tip) ilə təsvir edirlər. Qiyməti olan (backed) enum-da hər halın ->name (adı) və ->value (qiyməti) var. from() qiymətə görə halı tapır (tapmasa, xəta atır), tryFrom() isə tapmasa null qaytarır. Enum-ların metodları da ola bilər.

PHP
<?php

enum OrderStatus: string
{
    case Pending = 'pending';
    case Paid = 'paid';
    case Shipped = 'shipped';

    public function label(): string
    {
        return match ($this) {
            self::Pending => 'Waiting for payment',
            self::Paid => 'Paid, packing',
            self::Shipped => 'On the way',
        };
    }
}

$status = OrderStatus::from('paid');
echo $status->name, " / ", $status->value, "\n";
echo $status->label(), "\n";
var_dump(OrderStatus::tryFrom('lost'));
echo count(OrderStatus::cases()), "\n";
var_dump($status === OrderStatus::Paid);
Gözlənilən nəticə
Paid / paid
Paid, packing
NULL
3
bool(true)
Köhnə: sətir sabitləri
class OrderStatus
{
    const PENDING = 'pending';
    const PAID = 'paid';
}

function setStatus(string $status) { /* ... */ }

setStatus('payed'); // typo, no error
Müasir: enum (PHP 8.1)
enum OrderStatus: string
{
    case Pending = 'pending';
    case Paid = 'paid';
}

function setStatus(OrderStatus $status) { /* ... */ }

setStatus(OrderStatus::Paid); // typos are impossible
Sabitlərlə istənilən sətir, hətta hərf səhvi də keçir. Enum tipi isə yalnız öz hallarını qəbul edir.

Ad fəzaları və Composer

Layihə böyüdükcə adlar toqquşur: həm sənin, həm də yüklədiyin kitabxananın User sinfi ola bilər. Ad fəzası (namespace) qovluq kimi işləyir: namespace App\Models; elanından sonra sinfin tam adı App\Models\User olur, başqa faylda isə onu use ilə qoşursan. Composer PHP-nin paket meneceridir: kitabxanaları Packagist saytından yükləyir və siniflərin avtomatik yüklənməsini (autoloading) qurur.

JSON
{
    "require": {
        "php": ">=8.2"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}
composer.json: App\ ad fəzası src/ qovluğuna bağlanır
PHP
<?php

declare(strict_types=1);

namespace App\Models;

final class User
{
    public function __construct(public readonly string $name) {}
}
src/Models/User.php — ad fəzası qovluq yoluna uyğundur
PHP
<?php

require __DIR__ . '/vendor/autoload.php';

use App\Models\User;

$user = new User("Aysel");
echo $user->name, "\n";
Gözlənilən nəticə
Aysel
index.php — require_once sətirləri artıq lazım deyil
  1. 1
    Layihəni yarat

    composer init əmri suallar verir və composer.json faylını yaradır.

  2. 2
    Autoload-u qur

    autoload bölməsini əlavə et və composer dump-autoload əmrini icra et — vendor/autoload.php yaranacaq.

  3. 3
    Kitabxana əlavə et

    composer require monolog/monolog jurnal yazan məşhur kitabxananı vendor/ qovluğuna yükləyir və composer.json-a qeyd edir.

  4. 4
    vendor-u Git-ə əlavə etmə

    vendor/ qovluğu .gitignore-a yazılır; başqa kompüterdə composer install hər şeyi composer.lock-dakı versiyalarla bərpa edir.

Əsas fikirlər

  • İnterfeys müqavilədir: implements edən sinif bütün metodlarını yazmalıdır; sinif bir neçə interfeysi reallaşdıra bilər.
  • Abstrakt sinfin obyekti yaradılmır; o, ortaq kodu və abstract metodları törəmə siniflərə verir.
  • Trait use ilə metodları bir neçə sinfə əlavə edir və tək valideyn məhdudiyyətini yüngülləşdirir.
  • Enum (PHP 8.1) sabit qiymətlər dəstidir: from, tryFrom, cases, ->name və ->value ilə işləyir.
  • Ad fəzaları adların toqquşmasının qarşısını alır; Composer paketləri yükləyir və PSR-4 ilə sinifləri avtomatik qoşur.

Özünü yoxla

10 sual. Hər düzgün cavab XP qazandırır.

1 / 10
Bir PHP sinfi neçə interfeysi reallaşdıra bilər?