Riippuvuuksien kääntäminen käytännössä
Yhdistäkää sovittimet ytimeen riippuvuuksien kääntämisen avulla.
Riippuvuuksien kääntäminen käytännössä on ilmainen PHP Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu PHP Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. PHP Academy-kurssilla on yhteensä 4 oppituntia.
Inversio ja injektointi
Kaksi eri käsitettä sekoitetaan usein keskenään. Riippuvuusinjektio on tekniikka: yhteistoimijat välitetään sisään sen sijaan, että ne luotaisiin siellä. Riippuvuuksien kääntäminen (SOLID:n D) on periaate: korkean tason politiikka ja matalan tason yksityiskohdat riippuvat molemmat abstraktiosta, jonka korkean tason moduuli omistaa. Tässä oppitunnissa tehdään jälkimmäisestä käytäntöä — konkreettiset adapterit kytketään ytimeen, joka määrittelee rajapinnat.
Periaate täsmällisesti
DIP:n mukaan:
- Korkean tason moduulit eivät saa riippua matalan tason moduuleista. Molemmat riippuvat abstraktioista.
- Abstraktiot eivät saa riippua yksityiskohdista. Yksityiskohdat riippuvat abstraktioista.
Hienovarainen kohta on tämä: rajapinta kuuluu käyttäjälle, ei toteuttajalle. Toimialueenne määrittelee PaymentGateway-rajapinnan; Stripe-adapteri mukautuu siihen — ei päinvastoin.
Määritä abstraktio ytimessä
Sijoittakaa rajapinta sitä tarvitsevan koodin viereen ja ilmaiskaa se toimialueen termeillä. Stripe-tyypit eivät saa vuotaa mukaan.
<?php
// src/Billing/Application/Port/PaymentGateway.php
interface PaymentGateway
{
public function charge(Money $amount, CardToken $token): ChargeId;
}
final class Money {
public function __construct(public readonly int $cents, public readonly string $currency) {}
}
final class CardToken { public function __construct(public readonly string $value) {} }
final class ChargeId { public function __construct(public readonly string $value) {} }Mukauta adapteri siihen
Infrastruktuurin adapteri toteuttaa ytimen rajapinnan ja muuntaa kutsut toimittajan SDK:n muotoon. Riippuvuusnuoli osoittaa adapterista (yksityiskohdasta) abstraktioon (politiikkaan) — inversio on saavutettu.
<?php
final class StripePaymentGateway implements PaymentGateway
{
public function __construct(private \Stripe\StripeClient $stripe) {}
public function charge(Money $amount, CardToken $token): ChargeId {
$intent = $this->stripe->paymentIntents->create([
'amount' => $amount->cents,
'currency' => strtolower($amount->currency),
'payment_method' => $token->value,
'confirm' => true,
]);
return new ChargeId($intent->id);
}
}Konstruktorin injektointi on oletus
Injektoikaa riippuvuudet konstruktorin kautta ja käyttäkää tyyppinä abstraktiota. Riippuvuudet muuttuvat eksplisiittisiksi ja muuttumattomiksi, eikä niitä voi unohtaa. Välttäkää setter- ja property-injektiota pakollisille yhteistoimijoille — ne mahdollistavat puolivalmiit oliot.
<?php
final class CheckoutService
{
public function __construct(
private PaymentGateway $payments, // abstraction, not StripeClient
private OrderRepository $orders,
) {}
public function pay(OrderId $id, CardToken $token): ChargeId {
$order = $this->orders->get($id);
$charge = $this->payments->charge($order->total(), $token);
$order->markPaid($charge);
$this->orders->save($order);
return $charge;
}
}Composition root
Kaikki konkreettinen kytkentä tapahtuu täsmälleen yhdessä paikassa — composition rootissa — mahdollisimman lähellä main()-funktiota tai sisääntulopistettä. Mikään muu ei luo infrastruktuuria new-operaattorilla. Tämä on ainoa paikka, jossa tiedetään Stripen olevan käytössä.
<?php
// public/index.php — composition root
$stripe = new \Stripe\StripeClient(getenv('STRIPE_SECRET'));
$gateway = new StripePaymentGateway($stripe);
$orders = new PdoOrderRepository(new PDO(getenv('DB_DSN')));
$checkout = new CheckoutService($gateway, $orders);
// Everything below depends only on abstractions
$controller = new CheckoutController($checkout);Kytkentä DI-kontainerilla
Monimutkaisemmissa sovelluksissa kontaineri (PHP-DI, Symfony) automatisoi kytkennän. Keskeinen toimenpide on rajapintojen sitominen toteutuksiin. Automaattinen kytkentä ratkaisee konstruktorit tyypin perusteella; tarvitsee ilmoittaa vain rajapinta→luokka-kartoitus.
<?php
use function DI\autowire;
use function DI\get;
return [
PaymentGateway::class => autowire(StripePaymentGateway::class),
OrderRepository::class => autowire(PdoOrderRepository::class),
\Stripe\StripeClient::class => fn() => new \Stripe\StripeClient(getenv('STRIPE_SECRET')),
PDO::class => fn() => new PDO(getenv('DB_DSN')),
];Adapterien vaihtaminen todistaa asian
Koska ydin riippuu vain PaymentGateway-rajapinnasta, palveluntarjoajan vaihtaminen tai offline-testaus vaatii vain yhden rivin muutoksen kytkentään. Tässä on yksikkötestissä käytettävä feikki — CheckoutService pysyy muuttumattomana eikä koskaan tuo Stripea mukaan.
<?php
final class FakeGateway implements PaymentGateway {
public array $charges = [];
public function charge(Money $a, CardToken $t): ChargeId {
$this->charges[] = $a;
return new ChargeId('ch_test_' . count($this->charges));
}
}
$fake = new FakeGateway();
$id = $fake->charge(new Money(2500, 'EUR'), new CardToken('tok_visa'));
echo $id->value, ' charges=', count($fake->charges), PHP_EOL; // ch_test_1 charges=1Välttäkää service locator -ansaa
Kontainerin itsensä injektointi ja riippuvuuksien hakeminen metodien sisällä on service locator -antimalli. Se piilottaa riippuvuudet, tekee tyyppitarkistuksesta tehottoman ja kytkee koodin jälleen kontaineriin. Injektoikaa tarvitsemanne riippuvuudet eksplisiittisesti.
<?php
// ANTI-PATTERN: hidden dependencies, container leaks everywhere
final class BadCheckout {
public function __construct(private ContainerInterface $c) {}
public function pay($id, $token) {
$gateway = $this->c->get(PaymentGateway::class); // hidden!
// ...
}
}Missä kontaineri saa esiintyä
Kontaineri on oikeutettu täsmälleen yhdessä kerroksessa: composition rootissa ja sen ympärillä olevassa frameworkin liimakoodissa (esimerkiksi ohjaimen tehtaassa). Toimialue- ja sovellusluokkien on pysyttävä kontainerista riippumattomina — ne saavat tavalliset oliot konstruktoreilla, ja ne voitaisiin luoda käsin. Hyvä testi: voisitteko kytkeä koko sovelluksen yhteen PHP-tiedostoon ilman kontaineria? Jos voisitte, riippuvuutenne ovat rehellisiä.
Laiska kytkentä ilman service locatoria
Joskus riippuvuuden luominen on kallista tai sitä tarvitaan vain tietyissä tilanteissa. Älkää injektoiko kontaineria — injektoikaa sen sijaan factory closure. Riippuvuus säilyy eksplisiittisenä ja tyypitettynä, mutta sen luomista lykätään siihen asti, kunnes sitä todella tarvitaan.
<?php
final class ReportService
{
/** @param Closure():PaymentGateway $gatewayFactory */
public function __construct(private Closure $gatewayFactory) {}
public function refundIfNeeded(bool $needed): void {
if (!$needed) return;
$gateway = ($this->gatewayFactory)(); // built only when required
// $gateway->charge(...) etc.
}
}
// Composition root supplies the factory, not the container
$svc = new ReportService(fn() => new StripePaymentGateway($stripe ?? null));
echo 'lazy dependency wired', PHP_EOL;Pikatarkistus
Kenen tulisi omistaa PaymentGateway-rajapinta?
Kertaus
Kytkitte adapterit ytimeen oikealla tavalla:
- Inversio ≠ injektio: injektio on mekanismi, inversio tarkoittaa, että kuluttaja omistaa abstraktion.
- Ydin määrittelee rajapinnan; infrastruktuurin adapterit mukautuvat siihen.
- Käyttäkää abstraktioiden konstruktorin injektiota ja tehkää kaikki konkreettinen kytkentä yhdessä composition rootissa (tai kontainerin määrityksessä, joka sitoo rajapinnan→luokan).
- Adapterien vaihtaminen ja feikkien käyttäminen testeissä muuttuu yhden rivin muutokseksi.
- Välttäkää service locator -antimallia — pitäkää kontaineri vain reunalla.
Opi PHP tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 49
- Oppitunnit
- 195
Usein kysytyt kysymykset
Onko oppitunti ”Riippuvuuksien kääntäminen käytännössä” ilmainen?
Kyllä – oppitunnin ”Riippuvuuksien kääntäminen käytännössä” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko PHP Academy-kurssin, päivitä CoddyKit PROhon. PHP Academy-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Riippuvuuksien kääntäminen käytännössä”?
Yhdistäkää sovittimet ytimeen riippuvuuksien kääntämisen avulla. Harjoittelet PHP Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni PHP Academy-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin PHP Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.
Kuinka kauan ”Riippuvuuksien kääntäminen käytännössä”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä PHP Academy-oppitunnilla?
Kyllä. Jokainen PHP Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Kerrosarkkitehtuurista Clean Architectureen
- Portit ja sovittimet selitettyinä
- Käyttötapaukset ja sovelluspalvelut
- Riippuvuuksien kääntäminen käytännössä