0%

🏗️ OOP – Klases un objekti PHP

Objektorientēta programmēšana (OOP) organizē kodu ap "objektiem" – datu un metožu kolekcijām. PHP piedāvā pilnvērtīgu OOP atbalstu.

php

Klases un objekti

Klase ir "zīmējums" (blueprint), no kura tiek radīti objekti.

Teksts
<?php
// Klases definēšana
class Automašīna {
    // Īpašības (properties)
    public string $marka;
    public string $modelis;
    public int $gads;
    protected int $ātrums = 0;   // protected - pieejama tikai šajā klasē un apakšklasēs
    private float $degvielasTanks; // private - pieejama tikai šajā klasē

    // Konstruktors - izsaucas, veidojot objektu
    public function __construct(string $marka, string $modelis, int $gads) {
        $this->marka   = $marka;
        $this->modelis = $modelis;
        $this->gads    = $gads;
        $this->degvielasTanks = 50.0;
    }

    // Metodes
    public function apraksts(): string {
        return "{$this->gads}. gada {$this->marka} {$this->modelis}";
    }

    public function paātrināt(int $par): void {
        $this->ātrums += $par;
        echo "Paātrināts! Pašreizējais ātrums: {$this->ātrums} km/h<br>";
    }

    public function bremzēt(): void {
        $this->ātrums = max(0, $this->ātrums - 20);
        echo "Bremzēts. Ātrums: {$this->ātrums} km/h<br>";
    }

    public function iegūtĀtrumu(): int {
        return $this->ātrums;
    }
}

// Objekta izveide (instantiation)
$auto = new Automašīna("Toyota", "Corolla", 2022);
$auto2 = new Automašīna("BMW", "3-Series", 2021);

echo $auto->apraksts() . "<br>";   // 2022. gada Toyota Corolla
echo $auto2->apraksts() . "<br>;   // 2021. gada BMW 3-Series

$auto->paātrināt(40);
$auto->paātrināt(20);
$auto->bremzēt();
echo "Ātrums: " . $auto->iegūtĀtrumu() . "<br>";
?>

Konstruktors un destruktors

Teksts
<?php
class DatubāzesSavienojums {

    private static int $savienojumuSkaits = 0;
    private string $host;

    // PHP 8+ - Constructor Property Promotion
    // Automātiski izveido un piešķir īpašības
    public function __construct(
        private string $nosaukums,
        private int    $ports = 3306,
        bool           $autoConnect = true
    ) {
        $this->host = "localhost";
        self::$savienojumuSkaits++;
        echo "Izveidots savienojums #{" . self::$savienojumuSkaits . "} ar " . $this->nosaukums . "<br>";

        if ($autoConnect) {
            $this->savienot();
        }
    }

    private function savienot(): void {
        echo "Savienots ar {$this->nosaukums}:{$this->ports}<br>";
    }

    // Destruktors - izsaucas, iznīcinot objektu (garbage collection)
    public function __destruct() {
        echo "Savienojums ar {$this->nosaukums} slēgts.<br>";
        self::$savienojumuSkaits--;
    }

    public static function iegūtSkaitu(): int {
        return self::$savienojumuSkaits;
    }
}

$db1 = new DatubāzesSavienojums("mana_db");
$db2 = new DatubāzesSavienojums("cita_db", 5432);
echo "Aktīvo savienojumu skaits: " . DatubāzesSavienojums::iegūtSkaitu() . "<br>";
// Kad skripts beidzas, __destruct automātiski tiek izsaukts katram objektam
?>

Piekļuves modificētāji un Getter/Setter

Teksts
<?php
class BankasKonts {

    private float $bilance;
    private array $transakcijas = [];

    public function __construct(private string $numurs, float $sākotnējā = 0) {
        if ($sākotnējā < 0) {
            throw new InvalidArgumentException("Sākotnējā bilance nevar būt negatīva!");
        }
        $this->bilance = $sākotnējā;
    }

    // Getter - lasīt privātu īpašību
    public function iegūtBilanci(): float {
        return $this->bilance;
    }

    public function iegūtNumuru(): string {
        return $this->numurs;
    }

    // Setter ar validāciju
    public function iemaksāt(float $summa): void {
        if ($summa <= 0) {
            throw new InvalidArgumentException("Iemaksas summai jābūt pozitīvai!");
        }
        $this->bilance += $summa;
        $this->transakcijas[] = [
            "veids"  => "iemaksa",
            "summa"  => $summa,
            "laiks"  => date("H:i:s")
        ];
    }

    public function izmaksāt(float $summa): void {
        if ($summa > $this->bilance) {
            throw new RuntimeException("Nepietiek naudas! Bilance: {$this->bilance}");
        }
        $this->bilance -= $summa;
        $this->transakcijas[] = [
            "veids" => "izmaksa",
            "summa" => $summa,
            "laiks" => date("H:i:s")
        ];
    }

    public function transakcijuVēsture(): array {
        return $this->transakcijas;
    }

    // Magic method: __toString
    public function __toString(): string {
        return "Konts {$this->numurs}: " . number_format($this->bilance, 2) . " EUR";
    }
}

$konts = new BankasKonts("LV12345678", 1000.00);
$konts->iemaksāt(500.00);
$konts->izmaksāt(200.00);
echo $konts . "<br>";  // Konts LV12345678: 1300.00 EUR

foreach ($konts->transakcijuVēsture() as $t) {
    echo "{$t["laiks"]}: {$t["veids"]} {$t["summa"]} EUR<br>";
}
?>

Mantošana (Inheritance)

Teksts
<?php
// Vecāku klase (parent)
class Dzīvnieks {

    public function __construct(
        protected string $vārds,
        protected int    $vecums
    ) {}

    public function apraksts(): string {
        return "{$this->vārds} ({$this->vecums} gadi)";
    }

    public function skaņa(): string {
        return "...";
    }

    public function __toString(): string {
        return $this->apraksts() . " saka: " . $this->skaņa();
    }
}

// Apakšklase (child) - mantojo no Dzīvnieks
class Suns extends Dzīvnieks {

    public function __construct(string $vārds, int $vecums, private string $šķirne) {
        parent::__construct($vārds, $vecums); // Izsauc vecāku konstruktoru
    }

    // Pārrakstīt (override) vecāku metodi
    public function skaņa(): string {
        return "Hau hau!";
    }

    // Jauna metode tikai Suns klasei
    public function ienest(): string {
        return "{$this->vārds} atnes bumbu!";
    }

    public function apraksts(): string {
        return parent::apraksts() . " [{$this->šķirne}]"; // Izsauc vecāku metodi
    }
}

class Kaķis extends Dzīvnieks {
    public function skaņa(): string { return "Mjau!"; }
    public function spēlēties(): string { return "{$this->vārds} spēlējas ar dziju!"; }
}

$suns = new Suns("Rex", 3, "Labradors");
$kaķis = new Kaķis("Muris", 5);

echo $suns . "<br>";   // Rex (3 gadi) [Labradors] saka: Hau hau!
echo $kaķis . "<br>";  // Muris (5 gadi) saka: Mjau!
echo $suns->ienest() . "<br>"; // Rex atnes bumbu!

// Polimorfisms - dažādi objekti, vienāda saskarne
$dzīvnieki = [$suns, $kaķis, new Suns("Laila", 2, "Pudels")];
foreach ($dzīvnieki as $d) {
    echo $d->apraksts() . " saka: " . $d->skaņa() . "<br>";
}

// instanceof pārbaude
echo ($suns instanceof Suns) ? "Ir suns<br>" : "";
echo ($suns instanceof Dzīvnieks) ? "Arī ir dzīvnieks<br>" : "";
echo ($suns instanceof Kaķis) ? "" : "Nav kaķis<br>";
?>

Abstract klases un Interfaces

Teksts
<?php
// Abstract klase - var definēt kopīgo loģiku un abstraktās metodes
abstract class Forma {
    abstract public function laukums(): float;    // Jāiplementē apakšklasēs
    abstract public function perimetrs(): float;  // Jāiplementē apakšklasēs

    // Kopīga metode visām formām
    public function apraksts(): string {
        return sprintf(
            "%s: laukums=%.2f, perimetrs=%.2f",
            get_class($this),
            $this->laukums(),
            $this->perimetrs()
        );
    }
}

class Taisnstūris extends Forma {
    public function __construct(private float $platums, private float $augstums) {}

    public function laukums(): float { return $this->platums * $this->augstums; }
    public function perimetrs(): float { return 2 * ($this->platums + $this->augstums); }
}

class Aplis extends Forma {
    public function __construct(private float $rādiuss) {}

    public function laukums(): float { return M_PI * $this->rādiuss ** 2; }
    public function perimetrs(): float { return 2 * M_PI * $this->rādiuss; }
}

// Interface - tīrs "kontrāts" (tikai metožu paraksti, bez implementācijas)
interface Eksportējams {
    public function uzJSON(): string;
    public function uzCSV(): string;
}

interface Salīdzināms {
    public function salīdzināt(self $cits): int; // -1, 0, vai 1
}

// Klase var implementēt vairākus interfaces
class Produkts implements Eksportējams, Salīdzināms {

    public function __construct(
        public readonly string $nosaukums, // readonly - PHP 8.1+
        public readonly float  $cena
    ) {}

    public function uzJSON(): string {
        return json_encode(["nosaukums" => $this->nosaukums, "cena" => $this->cena]);
    }

    public function uzCSV(): string {
        return "{$this->nosaukums},{$this->cena}";
    }

    public function salīdzināt(self $cits): int {
        return $this->cena <=> $cits->cena;
    }
}

$forms = [new Taisnstūris(5, 3), new Aplis(4)];
foreach ($forms as $f) echo $f->apraksts() . "<br>";

$p1 = new Produkts("Ābols", 0.5);
$p2 = new Produkts("Mango", 2.1);
echo $p1->uzJSON() . "<br>";
echo $p1->salīdzināt($p2) . "<br>"; // -1 (p1 < p2 pēc cenas)
?>

Traits

Traits ļauj koplietot metodes starp klasēm bez mantošanas.

🎓 Ko mācīties tālāk?

Nākamajā sadaļā iepazīsieties ar MySQL datubāzēm PHP – kā savienoties, veikt vaicājumus un CRUD operācijas.

Teksts
<?php
trait Žurnālēšana {
    public function ierakstītŽurnālā(string $ziņa, string $līmenis = "INFO"): void {
        echo "[{$līmenis}] " . date("H:i:s") . " | " . static::class . ": $ziņa<br>";
    }
}

trait Validācija {
    public function pārbaudītNeTukšu(string $vērtība, string $lauks): void {
        if (empty(trim($vērtība))) {
            throw new InvalidArgumentException("Lauks '$lauks' nevar būt tukšs!");
        }
    }

    public function pārbaudītEpastu(string $epasts): bool {
        return (bool) filter_var($epasts, FILTER_VALIDATE_EMAIL);
    }
}

class LietotājuServiss {
    use Žurnālēšana, Validācija; // Izmantot abus traits

    public function reģistrēt(string $vārds, string $epasts): array {
        $this->pārbaudītNeTukšu($vārds, "vārds");

        if (!$this->pārbaudītEpastu($epasts)) {
            throw new InvalidArgumentException("Nepareizs e-pasts: $epasts");
        }

        $this->ierakstītŽurnālā("Reģistrēts lietotājs: $vārds");
        return ["id" => rand(1, 1000), "vārds" => $vārds, "epasts" => $epasts];
    }
}

class PasūtījumuServiss {
    use Žurnālēšana; // Arī šī klase var izmantot Žurnālēšana trait

    public function izveidotPasūtījumu(int $lietotāja_id, float $summa): void {
        $this->ierakstītŽurnālā("Pasūtījums: lietotājs $lietotāja_id, summa $summa EUR");
    }
}

$serv = new LietotājuServiss();
$l = $serv->reģistrēt("Anna", "anna@example.lv");
echo "Reģistrēts: {$l["vārds"]}, ID: {$l["id"]}<br>";

$pas = new PasūtījumuServiss();
$pas->izveidotPasūtījumu(42, 149.99);
?>