Vapautuminen on Yhdistettynä Yli vuosikymmenen ajan olemme luoneet uskonnollisesti gettereitä ja settereitä, jotka turpoavat entiteettejamme ja DTO: t kattiloilla, jotka lisäävät visuaalista melua mutta nollaa liiketoiminnan arvoa. PHP 8.4, Symfony 7.4 (LTS), PHP 8.4:n käyttöönotto ja Voimme kirjoittaa lyhyitä, ilmaisevia verkkotunnusmalleja, jotka kapselivat käyttäytymistä ilman sanallisuutta. Property Hooks Asymmetric Visibility Tässä artikkelissa tarkastelen, miten voin modernisoida Symfony 7.4 -sovelluksen näiden ominaisuuksien avulla. uudelleenmuodostan vanhan Doctrine-tyylisen entiteetin nykyaikaiseksi, lean PHP 8.4 -komponentiksi, joka varmistaa täydellisen yhteensopivuuden Symfony's Serializer, Validator ja Forms. ympäristöstä Ennen kuin sukellamme koodiin, varmista, että käytät oikeaa pinoa. Symfony 7.4 on pitkän aikavälin tuen versio, joka julkaistaan marraskuussa 2025. Varmista, että paikallinen ympäristö on valmis. Suorita seuraavat komennot: php -v # Output must indicate PHP 8.4.0 or higher composer version # Ensure you are on Composer 2.8+ Käytämme tavanomaisia Symfony 7.4 -komponentteja. Jos aloitat uuden projektin: composer create-project symfony/skeleton:7.4.* my_project cd my_project composer require symfony/webapp-pack:7.4.* composer require symfony/orm-pack composer require symfony/serializer-pack composer require symfony/validator-pack Jos päivität olemassa olevaa projektia, varmista, että Rajoittaminen Kaksi ja Pakkaukset 2 . composer.json php ^8.4 symfony/* ^7.4 Asymmetrinen näkyvyys: Getter / Setter Boilerplaten loppu Vuosien ajan olemme tehneet kiinteistöistä yksityisiä ja lisänneet julkisia gettereitä estääkseen ulkoisen muutoksen ja samalla sallimalla sisäisen pääsyn. The Old Way (PHP 8.3 and below): class User { private string $email; public function __construct(string $email) { $this->email = $email; } public function getEmail(): string { return $this->email; } // No setter meant it was effectively "read-only" externally, // but we still needed the getter to read it. } Asymmetrinen näkyvyys antaa meille mahdollisuuden määritellä ”asetuksen” käyttöoikeus riippumatta ”saada” käyttöoikeudesta. The PHP 8.4 Way class User { // Publicly readable, but only writeable by the class itself (private) public private(set) string $email; public function __construct(string $email) { $this->email = $email; } } Integrointi doktriinin kanssa Tämä toimii saumattomasti Doctrine ORM:n kanssa Symfoniassa 7.4. Doctrine käyttää heijastusta kosteuttamaan ominaisuuksia, ohittaen näkyvyyden vartijat, joten on täysin turvallinen kartoitetuille yksiköille. public private(set) Moderni doktrinaalinen entiteetti namespace App\Entity; use Doctrine\ORM\Mapping as ORM; use Symfony\Component\Validator\Constraints as Assert; #[ORM\Entity] class Product { #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column] public private(set) ?int $id = null; #[ORM\Column(length: 255)] #[Assert\NotBlank] public private(set) string $name; #[ORM\Column] #[Assert\PositiveOrZero] public private(set) int $stock = 0; public function __construct(string $name) { $this->name = $name; } // Business logic method to mutate state public function addToStock(int $quantity): void { if ($quantity < 1) { throw new \InvalidArgumentException('Quantity must be positive'); } $this->stock += $quantity; } } Why this matters: Nollapäällyste: Ei getId(), getName(), getStock(). Safe Encapsulation: $product->stock = 100 laukaisee tappavan virheen luokan ulkopuolelta. DX (Developer Experience): Autocompletion toimii suoraan ominaisuuksilla ($product->name), jotka tuntuvat enemmän "alkuperäisiltä" kuin menetelmäpyynnöt. Kiinteistöhousut: Älykkäät ominaisuudet Asymmetrinen näkyvyyden hallinta ja Ne korvaavat maagiset menetelmät (__get, __set) ja nimenomaiset getterit/setterit, joilla on logiikka, joka liittyy suoraan omaisuuteen. access Property Hooks Tietojen normalisointi (The set hook) Kuvittele Käyttäjäyksikkö, jossa sähköposti on aina tallennettava alakerrassa. namespace App\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] class User { #[ORM\Id] #[ORM\GeneratedValue] #[ORM\Column] public private(set) ?int $id = null; #[ORM\Column(length: 180, unique: true)] public string $email { // The 'set' hook intercepts assignment set(string $value) { if (!filter_var($value, FILTER_VALIDATE_EMAIL)) { throw new \InvalidArgumentException("Invalid email format"); } // The backing value is updated automatically via this assignment $this->email = strtolower($value); } } public function __construct(string $email) { // This triggers the set hook! $this->email = $email; } } Verification: $user = new User('ADMIN@Example.com'); echo $user->email; // Outputs: admin@example.com Virtuaaliset ominaisuudet (The Get Hook) Virtuaaliset ominaisuudet eivät tallenna tietoja, vaan laskevat ne nopeasti.Tämä sopii täydellisesti Symfony DTO:n tai Entitiesin mukavuustarvikkeisiin, joiden ei tarvitse pysyä tietokannassa. namespace App\Entity; use Doctrine\ORM\Mapping as ORM; #[ORM\Entity] class Customer { #[ORM\Column] public string $firstName; #[ORM\Column] public string $lastName; // This is a VIRTUAL property. It has no storage in memory. // Notice we do NOT add #[ORM\Column] because it's not in the DB. public string $fullName { get => $this->firstName . ' ' . $this->lastName; } } Yhteensopivuus Symfony Serializerin kanssa Symfony 7.4:n Property Hooksin yksi tehokkaimmista ominaisuuksista on se, miten Serializer-komponentti käsittelee niitä. Tuetut ominaisuudet: Serialisoitu normaalisti. Virtuaaliset ominaisuudet: Jos ne ovat julkisia, Serializer kohtelee niitä kuin todellisia ominaisuuksia. Tarkastajan esimerkki: namespace App\Controller; use App\Entity\Customer; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\Routing\Attribute\Route; class CustomerController extends AbstractController { #[Route('/customer/{id}', methods: ['GET'])] public function show(Customer $customer): JsonResponse { // Serialization automatically includes "fullName" in the JSON output return $this->json($customer); } } Tuotantoa : { "firstName": "Jane", "lastName": "Doe", "fullName": "Jane Doe" } Kehittynyt malli: arvoobjektit ja DTO:t Katsotaanpa monimutkaisempaa skenaariota, jossa on Data Transfer Object (DTO) Symfony-lomakkeen tai API: n hyötykuorman osalta. suoraan kiinteistöihin liittyvissä kysymyksissä. validation attributes namespace App\DTO; use Symfony\Component\Validator\Constraints as Assert; class RegistrationRequest { #[Assert\NotBlank] public string $firstName; #[Assert\NotBlank] public string $lastName; // A 'write-only' property behavior for passwords using a hook // We only want to set it, but reading it might return a masked value or be disallowed public string $password { set(string $value) { $this->password = password_hash($value, PASSWORD_BCRYPT); } get => '***MASKED***'; } // Combining hooks with asymmetric visibility // Publicly readable, but only settable internally or by hydration public private(set) \DateTimeImmutable $registeredAt { get => $this->registeredAt ?? new \DateTimeImmutable(); } } : Ole varovainen get hook on $registeredAt yllä. Jos omaisuus on uninitialized, pääsy siihen kautta $this->registeredAt sisällä hook aiheuttaa loputtoman uudelleenkäynnistyksen. Warning Perintöpalvelun uudelleenrakentaminen Katsotaanpa palveluluokkaa. Perinteisesti voimme injektoida riippuvuuksia ja käyttää vakiomenetelmiä. PHP 8.4:n avulla voimme tehdä palvelujärjestelyistämme puhtaampia. : Yksi Se tarvitsee oletusarvoisen ”lähettäjän” osoitteen, mutta haluamme sallia sen väliaikaisen muuttamisen tiukalla validoinnilla. Scenario EmailService namespace App\Service; use Symfony\Component\Mailer\MailerInterface; use Symfony\Component\Mime\Email; class EmailService { public function __construct( private readonly MailerInterface $mailer, // Property Hook to validate configuration immediately public string $defaultSender { set(string $value) { if (!filter_var($value, FILTER_VALIDATE_EMAIL)) { throw new \InvalidArgumentException("Invalid sender email"); } $this->defaultSender = $value; } } ) {} public function sendWelcomeEmail(string $recipient): void { $email = (new Email()) ->from($this->defaultSender) ->to($recipient) ->subject('Welcome!') ->text('Welcome to our platform.'); $this->mailer->send($email); } } ja : services.yaml services: App\Service\EmailService: arguments: $mailer: '@mailer' $defaultSender: '%env(DEFAULT_EMAIL_SENDER)%' Jos ympäristö muuttuu sisältää virheellisen sähköpostin, palvelun instantiointi epäonnistuu välittömästi selkeällä Poikkeuksella sen sijaan, että epäonnistuu hiljaa myöhemmin, kun sähköposti on lähetetty. . DEFAULT_EMAIL_SENDER This “Fail Fast” approach is enhanced by property hooks Symfony 7.4 Form Component yhteensopivuus Symfonia muodot luottavat voimakkaasti komponentti lukemaan ja kirjoittamaan tietoja objekteihisi. PropertyAccessor • The Sinfoniassa 7.4 PHP 8.4 Käyttöohjeet Good News PropertyAccessor fully supports Kun lomake lukee tietoja täyttämään kentät, se laukaisee get hook. Kun lomake lähettää tiedot takaisin objektiin, se laukaisee set hook. Entiteetin muutokset Voit usein poistaa lomaketietojen muuntajat siirtämällä logiikan Entity/DTO-liitäntään. // Old way: create a CallbackTransformer to handle string-to-array conversion // New way: class TagAwareDTO { /** @var string[] */ private array $tags = []; // The form field can be mapped to 'tagString' // The underlying data is stored in $tags array public string $tagString { get => implode(', ', $this->tags); set(string $value) { $this->tags = array_map('trim', explode(',', $value)); } } public function getTags(): array { return $this->tags; } } Sinun muotoilusi mukaan: $builder->add('tagString', TextType::class, [ 'label' => 'Tags (comma separated)', ]); Tämä yksinkertaistaa merkittävästi säilyttämällä tietojen muuntamisen logiikka sen toimialueen sisällä, johon se kuuluu. FormType Suorituskykyä koskevat näkökohdat & pitfalls Vaikka nämä ominaisuudet ovat erinomaisia, ”vanhemmat” kehittäjät tietävät, milloin niitä ei pitäisi käyttää. Kloonien kaatuminen Kun sinä Jos käytät epäsymmetristä näkyvyyttä, kloonattu objekti säilyttää samat näkyvyyssäännöt. clone Ole kuitenkin varovainen, kun Jos virtuaalinen omaisuus riippuu toisesta kohteesta (esim. ) ja kloonataan vanhempi objekti, mutta ei sisäinen , virtuaalinen ominaisuus voi silti viitata vanhaan käyttäjän viittaukseen. Tämä on PHP: n tavanomainen objektikäyttäytyminen, mutta hooksit voivat piilottaa tämän monimutkaisuuden. Virtual Properties $this->user->name $user Opettajat Proxies Doctrine käyttää Proxies (alaluokat) laiska lataus. Asymmetrinen näkyvyys: Toimii hyvin, koska oppi käyttää heijastusta yksityisten ominaisuuksien määrittämiseen. Hooks: Jos määrität hookin kartoitetulle ominaisuudelle, Doctrine laukaisee sen, kun se kosteuttaa entiteettiä, ellei se käytä heijastusta (mikä se tekee). Ole kuitenkin hyvin varovainen lisätessä sivuvaikutuksia (kuten logging tai tietokantakutsut) Doctrine-entiteetin kokoonpanoon. Kun Doctrine kosteuttaa objektia DB:stä, et halua näitä sivuvaikutuksia. : Vältä sivuvaikutuksia (kirjautuminen, API-puhelut) Entity Hooksissa. . Best Practice Keep hooks strictly for data validation and transformation Monimutkaisuus piilossa Älä laita 50 riviä liiketoiminnan logiikkaa sisälle sarjaan.Jos logiikka on monimutkainen, siirrä se yksityiseen menetelmään tai, vielä parempi, palveluun. Bad: public string $status { set { // 50 lines of code checking permissions, logging to DB, sending emails... } } Good: public string $status { set { $this->validateStatusTransition($value); $this->status = $value; } } Maahanmuuttokäsikirja: 7.3 / 8.3 - 7.4 / 8.4 Jos päivität massiivisen kooditietokannan, älä yritä kirjoittaa kaikkea uudelleen kerralla. Asymmetrinen näkyvyys. Suorita regex-haku tai käytä Rectoria (päivitetty kerran 8.4) korvaamaan yksityiset ominaisuudet + yksinkertaiset getterit julkisella yksityisellä(set).Haku: yksityinen tyyppi $prop; ... getProp() {palaa $tämä->prop; }Replace: julkinen yksityinen(set) tyyppi $prop; Virtuaaliset ominaisuudet API-resursseille. Etsi luokat, joissa on #[SerializedName(‘virtual_field’)] ja getVirtualField() -menetelmät. Muunna ne virtuaalisiksi ominaisuuksiksi. Siirrä yksinkertainen Assert-logiikka, joka muuntaa tiedot (kuten trim() tai strtolower()) ohjaimista/kuuntelijoista Property Hooksiksi. Johtopäätös ja Voimme kirjoittaa koodia, joka on kielen historian puhtain, ja siirtymme menneisyyden sanattomista, ”tyhmistä” datarakenteista älykkäisiin, itseohjautuviin objekteihin. PHP 8.4 Symfony 7.4 Tärkeimmät takeaways Käytä epäsymmetristä näkyvyyttä (public private(set)) altistaaksesi tiedot turvallisesti ilman huijauksia. Käytä Property Hooksia kevyisiin validointiin, muuntamiseen ja virtuaalisiin ominaisuuksiin. Symfony Serializer ja Forms tukevat näitä ominaisuuksia laatikosta 7.4. Pidä houkut puhtaana ja nopeasti; välttää vakavia sivuvaikutuksia. Getterien ja settereiden luomisen päivät ovat ohi.Tervetuloa nykyaikaisen PHP:n aikakauteen. Olenko tiimisi valmis siirtymään Symfony 7.4:een? autan organisaatioita nykyaikaistamaan vanhoja PHP-sovelluksia ja ottamaan käyttöön korkean suorituskyvyn arkkitehtuurit. Tutustu tarkemmin linkkiin [ ] Let’s connect https://www.linkedin.com/in/matthew-mochalkin/ https://www.linkedin.com/in/matthew-mochalkin/