Hoi, ik werk aan een project waarin ik een class heb gemaakt die api calls doet. Dit haalt producten op, maar kan ook producten/klanten etc opslaan.

Ook heb ik een Cart class gemaakt. Ik vind het handig om alle producten zo bij te houden en het totaal bedrag te bereken. De Class methodes worden uitgevoerd via ajax calls, dus de product ids komen vanuit de voorkant meegestuurd via JS. Nu is het zo dat ik nog het id, product naam en prijs meestuur naar de Cart. Maar wil eigenlijk alleen nog maar het id meesturen, om dat de gebruiker daar weinig mee kan saboteren. Ik weet wel hoe ik de data enzo kan ophalen, maar vind het slordig om direct die api call functies van die api class direct in mijn Cart class te gebruiken.

Heeft iemand ideeen, hoe ik dit netjes kan doen?
@Ad Fundum

>> In plaats daarvan kan je ook dezelfde functies schrijven waar geen geïnstantieerd object omheen zit

Wat bedoel je met een functie die data vasthoudt? Kun je een voorbeeldje geven?
Ozzie PHP op 22/12/2022 22:18:33

@Ad Fundum

>> In plaats daarvan kan je ook dezelfde functies schrijven waar geen geïnstantieerd object omheen zit

Wat bedoel je met een functie die data vasthoudt? Kun je een voorbeeldje geven?

De reden om value objects te gebruiken is bij gebrek aan ondersteuning voor eigen datatypen in PHP met bijvoorbeeld structs. De ondersteuning die je wilt is dat PHP je helpt met voorkomen van fouten. Als je een value object maakt met een X- en Y-coordinaat, dan doe je dat om zeker te weten dat er niets anders in zit, voor de 'type safety'.

Er is geen technische reden om value objects te gebruiken, ze verslechteren zelfs de performance. Nu is het performance verschil doorgaans te klein om geen value objects te gebruiken.

Het alternatief is dat je als programmeur zelf op blijft letten of de code wel klopt. Dat moet je toch op ontzettend veel manieren in PHP, dus als je dat toch al gewend bent, kan dit er ook nog wel bij. Je kunt dichter in de buurt komen met enums, waardoor de code ook al duidelijker wordt:

<?php
enum Pos: int { case X = 0; case Y = 1; }
$shape = [
  [ Pos::X->value => 0, Pos::Y->value => 0 ],
  [ Pos::X->value => 1, Pos::Y->value => 0 ],
  [ Pos::X->value => 0, Pos::Y->value => 1 ],
];

function drawShape(array $shape) {  // specifieker dan 'array' kan niet..
  foreach ($shape as $pos) {
    print 'X: ' . $pos[Pos::X->value]
      . ', Y: ' . $pos[Pos::Y->value] . PHP_EOL;
  }
}

drawShape($shape);
?>

Ik geef direct toe dat ik de implementatie van 'backed' enums onelegant vind. Maar technisch kan je alles wat OOP doet ook zonder OOP doen. Zo is er bijvoorbeeld niets dat je alleen in C++ kan doen en niet in C.
Op die manier kan je met je eigen oplettendheid meer performance uit PHP krijgen.

Maar het is ook niet ongebruikelijk om value objects te gebruiken (wederom, bij gebrek aan beter), wanneer je meer controle wilt op types in PHP en je bereid bent om performance in te leveren.

Een van de voordelen van OOP is dat je modulair kan programmeren, met scheiding van verantwoordelijkheden. De noodzaak kwam voort uit het probleem dat procedurele programma's over het algemeen minder schaalbaar zouden zijn, vooral wanneer ze worden opgedeeld in meerdere afdelingen/organisaties.
Een probleem van de OOP-gedachte is de manier waarop inheritance werd geïmplementeerd, dat zorgt op zijn beurt voor te veel overhead (als je maar een fractie van de code wilt gebruiken moet je toch het hele object meenemen) en het introduceerde weer een eigen categorie problemen zoals het 'diamond problem'.

Code overhead is alleen een probleem wanneer de hardware niet snel genoeg mee groeit of wanneer stroom te duur wordt. En om andere OOP-problemen kan je heen werken. Maar het is minder stabiel waardoor bijvoorbeeld besturingssystemen eerder in C worden geschreven dan in C++.
@Ad Fundum

Klinkt interessant! Ik ken dat enum helemaal (nog) niet.

Wat is precies de toepassing van zoiets?

Even een voorbeeld om de werking te begrijpen (laten we de OOP-aanpak even buiten beschouwing laten).

Even denken ...

Stel we hebben een object 'deur'. En die deur kan een 'status' hebben, namelijk 'open' of 'dicht'.

Als je dan zou controleren op status, dan zou je kunnen doen:

<?php

if ($deur->status() == 'open') {
// dat doet de deur dicht
}

?>
Er zijn maar 2 juiste statussen, namelijk 'open' of 'dicht'. Nu zou ik me kunnen voorstellen dat een programmeur die de code niet kent de verkeerde status (een verkeerd woord) gebruikt, bijv. geopend in plaats van open. Of gesloten in plaats van dicht.

Kun je dit met zo'n enum ondervangen? En zo ja, hoe ziet de code van die enum er dan uit?
Waar je voorheen constanten zou gebruiken:


<?php

declare(strict_types=1);

interface GenderInterface
{
    public const FEMALE = 'https://schema.org/Female';
    public const MALE = 'https://schema.org/Male';
}

?>


kun je nu enumeraties gebruiken:


<?php

declare(strict_types=1);

enum GenderType: string
{
    case Female = 'https://schema.org/Female';
    case Male = 'https://schema.org/Male';
}

?>


Hoewel het lijkt of we het topic aan het kapen zijn, hangen beide samen met value objects: een value object is namelijk immutable, dus net als constanten en enumeraties onveranderlijk.

Als je het goed doet althans. :)
Zijn enums handig om grote if statements en switches te ontwijken?
Ward van der Put op 23/12/2022 14:28:46


...

kun je nu enumeraties gebruiken:


<?php

declare(strict_types=1);

enum GenderType: string
{
    case Female = 'https://schema.org/Female';
    case Male = 'https://schema.org/Male';
}

?>



Pretty cool :-)

* Als ik het goed begrijp zet je dus het return type (in dit geval een string) direct achter de naam van de enumeratie?

Voortbordurend op jouw voorbeeld. Zoiets als dit zou dan dus ook kunnen? (gaat enkel even om de techniek)


<?php

declare(strict_types=1);

enum GenderType: string
{
    case Female = 'vrouw';
    case Male = 'vrouw';
}

class Person {

private int $gender;

public function __construst($user_id) {
  ...
}

public function getGender() : string {
  return $this->gender === 1 ? 'man' : 'vrouw';
}

}

$person = new Person($user_id);

if ($person->getGender() === GenderType::Female) {
  ...
}

?>

Dat zou dus werken?

[size=xsmall]Toevoeging op 23/12/2022 15:49:47:[/size]

Jorn Reed op 23/12/2022 14:49:00

Zijn enums handig om grote if statements en switches te ontwijken?

Op welke manier?
Ik maak vaak gebruik van een bepaalde api, en ik vang altijd al die status codes zoals 401 etc af. Maar dat worden altijd hele lange stukken code. Dacht misschien dat enums er goed voor van pas kwamen
>> Dacht misschien dat enums er goed voor van pas kwamen

Ik vermoed eigenlijk van niet, maar wellicht is de code zelf voor verbetering vatbaar?
Oh geen idee, ik vind sowieso veel if/else en een switch vrij lelijk, maar had niet echt een andere oplossing.
Je kunt die HTTP-statuscodes vaak vereenvoudigd afhandelen: alles dat begint met een 4 is een clientfout en alles met een 5 een serverfout. Als je de respons ergens logt voor eventueel verder onderzoek, maakt het voor je applicatie verder eigenlijk niet uit of de respons nou een `500 Internal Server Error`, `503 Service Unavailable` of `504 Gateway Timeout` was.

Reageren