PHP – entwickler.de https://entwickler.de PHP, JavaScript, Windows Development Tue, 13 Apr 2021 08:30:05 +0000 de-DE hourly 1 https://wordpress.org/?v=5.4.2 Was ist neu in PHP 8.0? Ein Blick auf die neuen Funktionen https://kiosk.entwickler.de/php-magazin/php-magazin-3-2021/was-ist-neu-in-php-8-0-ein-blick-auf-die-neuen-funktionen/ https://kiosk.entwickler.de/php-magazin/php-magazin-3-2021/was-ist-neu-in-php-8-0-ein-blick-auf-die-neuen-funktionen/#respond Tue, 13 Apr 2021 10:00:14 +0000 https://entwickler.de/?p=579965504 Die neueste Version der beliebtesten serverseitigen Sprache des Webs ist da: PHP 8.0 hat das Licht der Welt erblickt. Das lang erwartete Major-Release ist Grund genug, sich die wichtigsten Features noch einmal genauer anzusehen.

Der Beitrag Was ist neu in PHP 8.0? Ein Blick auf die neuen Funktionen ist auf entwickler.de erschienen.

]]>
Die neueste Version der beliebtesten serverseitigen Sprache des Webs ist da: PHP 8.0 hat das Licht der Welt erblickt. Das lang erwartete Major-Release ist Grund genug, sich die wichtigsten Features noch einmal genauer anzusehen.

Der Beitrag Was ist neu in PHP 8.0? Ein Blick auf die neuen Funktionen ist auf entwickler.de erschienen.

]]>
https://kiosk.entwickler.de/php-magazin/php-magazin-3-2021/was-ist-neu-in-php-8-0-ein-blick-auf-die-neuen-funktionen/feed 0
Was kann PHP 8.0? Core-Entwickler Larry Garfield stellt seine Highlights vor https://entwickler.de/online/php/php-8-0-garfield-features-579965637.html https://entwickler.de/online/php/php-8-0-garfield-features-579965637.html#respond Tue, 13 Apr 2021 08:27:37 +0000 https://entwickler.de/?p=579965637 Die neueste Version der beliebtesten serverseitigen Sprache des Webs wurde lange erwartet und im November des letzten Jahres veröffentlicht: PHP 8.0 hat das Licht der Welt erblickt. Larry Garfield, Core-Entwickler bei PHP, stellt uns seine favorisierten Neuerungen vor

Der Beitrag Was kann PHP 8.0? Core-Entwickler Larry Garfield stellt seine Highlights vor ist auf entwickler.de erschienen.

]]>
Die neueste Version der beliebtesten serverseitigen Sprache des Webs wurde lange erwartet und im November des letzten Jahres veröffentlicht: PHP 8.0 hat das Licht der Welt erblickt. Larry Garfield, Core-Entwickler bei PHP, stellt uns seine favorisierten Neuerungen vor

Nach einem Jahr Entwicklungszeit wurde PHP 8.0 nun der Weltöffentlichkeit vorgestellt. Mit einer Fülle von neuen Funktionen, die mehr Leistung mit weniger Code versprechen, ist es die am meisten erwartete Version von PHP seit … nun, seit v7.4 im letzten Jahr. PHP ist aufregend, was soll ich anderes sagen?

PHP 8.0 ist vollgestopft mit neuen Funktionen: Von einem ausdrucksstärkeren Typisierungssystem über match()-Ausdrücke bis hin zu den potenziell enormen Verbesserungen bei persistenten Diensten durch die neue JIT-Erweiterung – PHP 8 hat für jeden etwas zu bieten. Es gibt jedoch drei Features, die ich besonders hervorheben möchte, da sie im Mittelpunkt der neuen Version stehen. Diese Features befanden sich alle bereits länger auf der Wunschliste, aber vor allem im Zusammenspiel ergeben sie etwas, das größer ist als die Summe ihrer Teile.

Constructor Property Promotion

Das erste Feature ist die Constructor Property Promotion. Constructor Promotion ist nur syntaktischer Zucker, um das Schreiben von Konstruktoren und Objekteigenschaften weniger repetitiv zu machen. Ein Beispiel ist die Klasse, die in Listing 1 zu sehen ist. Dieser Code kann nun wie in Listing 2 dargestellt zusammengefasst werden.

 
<?php

class MailMessage
{
  private string $to;
  private string $subject;
  private string $from;
  private string $body;
  private array $cc;
  private array $bcc;
  private string $attachmentPath;

  public function __construct(
    string $to;
    string $subject;
    string $from;
    string $body;
    array $cc = [];
    array $bcc = [];
    string ?$attachmentPath = null;
  ) {
    $this->to = $to;
    $this->subject = $subject;
    $this->from = $from;
    $this->body = $body;
    $this->cc = $cc;
    $this->bcc = $bcc;
    $this->attachmentPath = $attachmentPath;
  }
}
 
<?php

Class MailMessage
{
  public function __construct(
    private string $to,
    private string $subject,
    private string $from,
    private string $body,
    private array $cc = [],
    private array $bcc = [],
    private ?string $attachmentPath = null,
  ) {}
}

Wir sehen das gleiche Ergebnis bei einem Viertel des geschriebenen Codes. Und natürlich können Sie immer noch Dinge wie Non-promoted Properties und Parameter oder einen Constructor Body für zusätzliches Verhalten verwenden. Das mag nur wie eine kleine Änderung erscheinen, ist aber in Wirklichkeit ziemlich mächtig. Nicht nur, weil es unnötig ausführlichen Code reduziert (was großartig ist), sondern weil es bestimmte Ansätze einfacher macht. Insbesondere die Definition eines struct-ähnlichen Objekts (also eines, das nur öffentliche Eigenschaften enthält, die vom Konstruktor gemappt werden) ist vier Mal einfacher zu schreiben.

Heutzutage werden viele Entwickler und Entwicklerinnen standardmäßig assoziative Arrays für Quick-and-dirty-Strukturen verwenden. Das ist weniger selbstdokumentierend, verbraucht mehr Speicher, ist schwieriger zu benutzen und ist in jeder Hinsicht schlechter als die Definition einer richtigen Klasse – außer, dass viele das Erstellen einer Klasse für diesen Zweck als zu viel Arbeit empfinden. Nun, das Definieren einer Klasse ist nicht zu viel Arbeit und kann die Qualität und Effizienz einer Codebasis erheblich verbessern.

International PHP Conference

Frameworkless – the new black?

by Carsten Windler (KW-Commerce GmbH)

Getting started with PHP-FFI

by Thomas Bley (Bringmeister GmbH)

JSON-Schema von 0 auf 100

by Ingo Walther (Electronic Minds GmbH)

IT Security Camp 2021

Von der Cloud über DevSecOps bis hin zu Datenschutzproblem von WhatsApp

Christian Schneider spricht im Interview über aktuelle Security-Trends. Welche Themen rücken besonders heute stark in den Security-Fokus, warum alles rund um die Cloud immer mehr an Bedeutung gewinnt, welche Aspekte in der Cyberabwehr effektiv sind u.v.m.

IT-Security Experte, Christian Schneider

Christian ist als freiberuflicher White Hat Hacker, Trainer und Security-Coach tätig. Als Softwareentwickler mit mittlerweile 20 Jahren Erfahrung, fand er 2005 seinen Themenschwerpunkt im Bereich IT-Security.

Attribute

Das zweite wichtige Feature sind Attribute. Sie bieten die Möglichkeit, eine Klasse, Funktion, Eigenschaft oder ein Argument mit Metadaten zu versehen, die zur Laufzeit untersucht werden können – und zwar mit voller Unterstützung der Sprache. Diese Funktionalität stand bisher nur über Bibliotheken von Drittanbietern und über das benutzerdefinierte Parsen von Kommentarblöcken zur Verfügung, jetzt ist sie endlich als erstklassiger Bestandteil der Sprache verfügbar. Attribute können entweder bloße Strings sein oder auf Klassen abgebildet werden, wobei Letzteres in der Regel vorzuziehen ist (aus den gleichen Gründen, aus denen Klassen unstrukturierten Arrays vorzuziehen sind).

Obwohl Attribute an sich keine besondere Funktionalität haben, ist es einfach genug, sie im User-Space hinzuzufügen. Um zu definieren, dass die Betreffzeile einer E-Mail-Nachricht nur reinen Text enthält und auf 120 Zeichen begrenzt ist, könnten Sie zum Beispiel ein Attribut definieren (Listing 3).

 
<?php

#[Attribute(Attribute::TARGET_PROPERTY | Attribute::TARGET_PARAMETER)]
class PlainText
{
  public function __construct(private ?int $length = null) {}

  public function valid(string $str): bool
  {
    return (strlen($str) <= $this->length) && strip_tags($str) === $str;
  }
}

Wir sehen hier die Constructor Promotion bei der Arbeit. Attribute sind ein perfektes Beispiel für Struct Classes, daher ist die Constructor Promotion eine natürliche Anpassung. Wir kennzeichnen das Attribut auch als nur für Eigenschaften und Parameter gültig, da es für eine Klasse oder Funktion keinen logischen Sinn ergeben würde. Jetzt kann die Eigenschaft „Betreffzeile“ mit einem Tag versehen werden (Listing 4).

 
<?php

Class MailMessage
{
  public function __construct(
    private string $to,
    #[PlainText(120)]
    private string $subject,
    private string $from,
    private string $body,
    private array $cc = [],
    private array $bcc = [],
    private ?string $attachmentPath = null,
  ) {}
}

Nun können wir zu jeder Zeit ein MailMessage-Objekt validieren, wie in Listing 5 geschehen.

 
<?php

$attribs = new \ReflectionObject($addr)
  ->getProperty('subject')
  ->getAttributes(PlainText::class);
if (! $attribs[0]->valid($mail->subject)) {
  throw new SomethingIsVeryWrongException();
}

In der Praxis würden man sich etwas Robusteres wünschen, aber lassen Sie es uns für den Moment so einfach wie möglich halten. All das geschieht mit nativem PHP-Code; es werden keine Bibliotheken von Drittanbietern benötigt. Das bedeutet, dass die Attributsyntax auch für Linters zur Verfügung steht, damit Ihre IDE sie farblich kodieren, typisieren oder autovervollständigen kann. Und das ist nur die Spitze des Eisbergs dessen, was an Metaprogrammierung jetzt nativ in PHP verfügbar ist.

Named Arguments

Der dritte und letzte Teil des großen PHP-8.0-Dreigestirns sind Named Arguments. Sie verkörpern genau das, was ihre Bezeichnung bereits aussagt. Anstatt eine Funktion mit Positionsargumenten aufzurufen, kann nun jede Funktion oder Methode mit benannten Parametern aufgerufen werden, in beliebiger Reihenfolge:

<?php
$found = in_array(needle: 'a', haystack: $arr);

Während Named Parameter in fast jeder Situation verwendet werden können, um die Lesbarkeit zu verbessern (insbesondere, wenn die Parameter nicht sofort aus dem Kontext ersichtlich sind), ist einer ihrer wichtigsten Anwendungsfälle der Aufruf von Konstruktoren.

 
<?php

$mail = new MailMessage(
  subject: 'Write more blog posts about PHP!',
  body: 'PHP is awesome and we should have more articles about it',
  to: 'Larry Garfield',
  from: 'Robert Douglas',
  attachmentPath: '/path/to/some/file',
);

Beachten Sie, dass die Argumente in Listing 6 nicht in der deklarierten Reihenfolge stehen – und das ist auch Ordnung. Wir lassen auch einige optionale Argumente ganz weg, da wir sie nicht benötigen.

All together now!

Constructor Property Promotion, Attribute und Named Arguments sind alle für sich genommen bereits wertvolle Ergänzungen. Ihre Kombination ist jedoch der Punkt, an dem PHP 8.0 wirklich glänzt und es die Art und Weise, wie wir PHP-Code schreiben, für die nächsten Jahre verändern wird. Lassen Sie uns als Beispiel echten Code aus meiner PSR-14-Event-Dispatcher-Implementierung, Tukio [1], betrachten. Er definiert seine eigenen Attribute (Listing 7).

 
<?php

namespace Crell\Tukio;

use \Attribute;

#[Attribute(Attribute::TARGET_FUNCTION | Attribute::TARGET_METHOD)]
class Listener implements ListenerAttribute
{
  public function __construct(
    public ?string $id = null,
    public ?string $type = null,
  ) {}
}

#[Attribute(Attribute::TARGET_FUNCTION | Attribute::TARGET_METHOD)]
class ListenerBefore implements ListenerAttribute
{
  public function __construct(
    public string $before,
    public ?string $id = null,
    public ?string $type = null,
  ) {}
}

#[Attribute(Attribute::TARGET_FUNCTION | Attribute::TARGET_METHOD)]
class ListenerPriority implements ListenerAttribute
{
  public function __construct(
    public ?int $priority,
    public ?string $id = null,
    public ?string $type = null,
  ) {}
}

Sie alle werden einfachheitshalber über Constructor Promotion definiert. Diese Attribute können dann Listener, entweder Funktionen oder Methoden, ausstatten, um zu definieren, wie sie registriert werden. In den meisten Fällen können Sie eine benutzerdefinierte ID angeben:

<?php
#[Listener('mine')]
function my_listener(MyEvent $event): void
{
// ...
}

Insbesondere bei der Verwendung von Subscriber-Klassen (eine Klasse, die eine Reihe von Listenern enthält) können Sie jedoch beliebige davon mischen und anpassen. Und viele von ihnen sind als Named Arguments einfacher zu verwenden (Listing 8).

 
<?php

class MockAttributedSubscriber
{
  #[Listener('a')]
  public function onA(CollectingEvent $event) : void { ... }

  #[ListenerPriority(priority: 5, id: 'this_listener')]
  public function onB(CollectingEvent $event) : void { ... }

  #[ListenerBefore(id: 'listener_c', before: 'a')]
  public function onC(CollectingEvent $event) : void { ... }

  #[ListenerAfter(after: 'a', id: 'extra_listener')]
  public function onD(CollectingEvent $event) : void { ... }

  #[Listener]
  public function onG(RareEvent $event) : void { ... }
}

Probieren Sie es heute aus

Natürlich gibt es in PHP 8.0 einige Änderungen [2], die Probleme für älteren Code mit sich bringen könnten. Wie bei jeder PHP-Version sollten Sie Ihren Code testen, bevor Sie Ihre Version einfach aktualisieren. Und das Testen von PHP 8.0 auf https://platform.sh könnte nicht einfacher sein. Legen Sie zunächst einen neuen Branch in Ihrem Repository an, aktualisieren Sie dann Ihre Datei .platform.app.yaml in diesem Zweig und ändern Sie den Key-Type in:

yaml
type: php:8.0

Git Commit und Deploy. Dieser Branch läuft jetzt unter PHP 8.0. Probieren Sie ihn aus, führen Sie Integrationstests durch, überprüfen Sie ihn stichprobenartig und schauen Sie, ob etwas aktualisiert werden muss. Sobald Sie alle notwendigen Änderungen vorgenommen haben, führen Sie diesen Branch wieder mit dem Master zusammen. Herzlichen Glückwunsch, Sie verwenden jetzt PHP 8.0 in der Produktion. Auch wenn Sie noch nicht bereit sind, auf PHP 8.0 zu aktualisieren, sollten Sie sich trotzdem einen Plan dafür machen.

Der Securitysupport für PHP 7.2 läuft am 30. November aus, und 7.3 geht für ein weiteres Jahr in einen reinen Sicherheitsmodus über. Wenn Sie noch mit älteren PHP-Versionen arbeiten, verpassen Sie nicht nur die Leistungsverbesserungen und neuen Funktionen, sondern verwenden möglicherweise auch noch unsichere PHP-Versionen. Machen Sie Versionsupgrades zu einem regelmäßigen Teil Ihres Wartungszyklus und es wird nicht wirklich eine Last sein, sondern ein Vergnügen, auf das Sie sich freuen können. Mit jedem Upgrade erhalten Sie all die neuen lustigen Spielzeuge, mit denen Sie spielen können.

Links & Literatur


[1] https://github.com/Crell/Tukio
[2] https://platform.sh/blog/2020/php-80-feature-focus-language-tightening/

Der Beitrag Was kann PHP 8.0? Core-Entwickler Larry Garfield stellt seine Highlights vor ist auf entwickler.de erschienen.

]]>
https://entwickler.de/online/php/php-8-0-garfield-features-579965637.html/feed 0
Wer bin ich? Was darf ich? Authentifizierung und Autorisierung in Symfony https://kiosk.entwickler.de/php-magazin/php-magazin-3-2021/wer-bin-ich-was-darf-ich/ https://kiosk.entwickler.de/php-magazin/php-magazin-3-2021/wer-bin-ich-was-darf-ich/#respond Tue, 06 Apr 2021 10:00:50 +0000 https://entwickler.de/?p=579964709 Ein geschützter Bereich für eingeloggte Nutzer lässt sich mit Symfony schnell erstellen. Das Maker Bundle hilft bei der Generierung des benötigten Codes. Dieser lässt sich problemlos an die eigenen Bedürfnisse anpassen.

Der Beitrag Wer bin ich? Was darf ich? Authentifizierung und Autorisierung in Symfony ist auf entwickler.de erschienen.

]]>
Ein geschützter Bereich für eingeloggte Nutzer lässt sich mit Symfony schnell erstellen. Das Maker Bundle hilft bei der Generierung des benötigten Codes. Dieser lässt sich problemlos an die eigenen Bedürfnisse anpassen.

Der Beitrag Wer bin ich? Was darf ich? Authentifizierung und Autorisierung in Symfony ist auf entwickler.de erschienen.

]]>
https://kiosk.entwickler.de/php-magazin/php-magazin-3-2021/wer-bin-ich-was-darf-ich/feed 0
Webinale & IPC 2021: Nur noch heute Early-Bird-Angebot nutzen & volles Programm von überall aus verfolgen! https://entwickler.de/online/php/webinale-ipc-early-bird-2021-579960180.html https://entwickler.de/online/php/webinale-ipc-early-bird-2021-579960180.html#respond Thu, 01 Apr 2021 11:00:11 +0000 https://entwickler.de/?p=579960180 Vom 7. bis 11. Juni findet das Konferenzduo Webinale & International PHP Conference wieder statt. Dieses Jahr können die Events von überall aus verfolgt werden. Sicher ist sicher – mit unserem Hybrid-Konzept garantieren wir auch in unsicheren Zeiten ein tolles Konferenz-Erlebnis! Noch heute, am 01.04, gelten besondere Frühbucher-Preise.

Der Beitrag Webinale & IPC 2021: Nur noch heute Early-Bird-Angebot nutzen & volles Programm von überall aus verfolgen! ist auf entwickler.de erschienen.

]]>
Vom 7. bis 11. Juni findet das Konferenzduo Webinale & International PHP Conference wieder statt. Dieses Jahr können die Events von überall aus verfolgt werden. Sicher ist sicher – mit unserem Hybrid-Konzept garantieren wir auch in unsicheren Zeiten ein tolles Konferenz-Erlebnis! Noch heute, am 01.04, gelten besondere Frühbucher-Preise.

Die Schwester-Konferenzen Webinale und International PHP Conference Berlin finden vom 7. bis 11. Juni 2021 statt. Auch in diesen unsicheren Tagen bieten die Veranstaltungen Ihnen garantiert das geballte Fachwissen: Die als Hybrid-Event geplanten Konferenzen können vollständig remote verfolgt werden. Alle Workshops, Keynotes und Talks der Events werden live übertragen. Insofern es die Lage zulässt, freuen wir uns aber natürlich auch darauf, Sie unter Einhaltung des Hygiene-Konzepts wieder vor Ort in Berlin begrüßen zu können. Das Hybrid-Format ermöglicht hier die maximale Flexibilität und Sicherheit für alle Beteiligten. Die Berliner Konferenz kann stattfinden, unabhängig davon ob wir uns vor Ort treffen.

Die Konferenzwoche umfasst fünf Tage. An zwei davon stehen zahlreiche ganztägige Power-Workshops zur Wahl, in denen Sie tief in einen Themenbereich einsteigen. An drei Tagen erwarten Sie 70+ Talks und Keynotes von 50+ renomierten Speakern der Szenen. Die Webinale mit ihren Themen aus dem Webdesign, der Suchmaschinen-Optimierung und der Frontend-Entwicklung vom klassischen UI bis zur Voice-Steuerung, ergänzt dabei die klassische PHP-Welt gut: Backend und Frontend, die ganze Welt der Web-Entwicklung an einem Ort.

Webinale & IPC: Jetzt anmelden und sparen!

Wer sich noch heute, am 1. April anmeldet, kann von besonderen Frühbucher-Angeboten profitieren – kein Aprilscherz. Die Angebote unterscheiden sich je nach Ticket-Typ; einen Überblick über die verschiedenen Optionen vom Tagesticket bis zum Pass für die gesamte Konferenzwoche und die derzeit dazugehörigen Spezialangebote gibt der Ticket-Shop. Natürlich gilt in allen Fällen: Zwei Konferenzen, ein Ticket!

Der Beitrag Webinale & IPC 2021: Nur noch heute Early-Bird-Angebot nutzen & volles Programm von überall aus verfolgen! ist auf entwickler.de erschienen.

]]>
https://entwickler.de/online/php/webinale-ipc-early-bird-2021-579960180.html/feed 0
PHPStan – Gamification für Entwickler und Teams: Spielerische Fehlersuche in PHP https://kiosk.entwickler.de/php-magazin/php-magazin-3-2021/phpstan-gamification-fuer-entwickler-und-teams/ https://kiosk.entwickler.de/php-magazin/php-magazin-3-2021/phpstan-gamification-fuer-entwickler-und-teams/#respond Tue, 30 Mar 2021 10:00:53 +0000 https://entwickler.de/?p=579963941 Gamification ist toll, das wissen wir alle. Wie wäre es, wenn wir das Prinzip auf die Verbesserung unseres Quellcodes anwenden könnten, und das am besten mit nur einer Zeile im Terminal? Herzlich willkommen bei der statischen Codeanalyse mit PHPStan.

Der Beitrag PHPStan – Gamification für Entwickler und Teams: Spielerische Fehlersuche in PHP ist auf entwickler.de erschienen.

]]>
Gamification ist toll, das wissen wir alle. Wie wäre es, wenn wir das Prinzip auf die Verbesserung unseres Quellcodes anwenden könnten, und das am besten mit nur einer Zeile im Terminal? Herzlich willkommen bei der statischen Codeanalyse mit PHPStan.

Der Beitrag PHPStan – Gamification für Entwickler und Teams: Spielerische Fehlersuche in PHP ist auf entwickler.de erschienen.

]]>
https://kiosk.entwickler.de/php-magazin/php-magazin-3-2021/phpstan-gamification-fuer-entwickler-und-teams/feed 0
Jede Menge neue zukunftsorientierte Optionen: Joomla 4.0 setzt zum Endspurt an https://kiosk.entwickler.de/php-magazin/php-magazin-3-2021/joomla-4-0-setzt-zum-endspurt-an/ https://kiosk.entwickler.de/php-magazin/php-magazin-3-2021/joomla-4-0-setzt-zum-endspurt-an/#respond Tue, 23 Mar 2021 11:00:28 +0000 https://entwickler.de/?p=579962947 Joomla! [1] ist der drittgrößte Player [2] auf dem CMS-Markt. Der Startschuss für das kurz vor der Veröffentlichung stehende Major-Release 4.0 fiel bereits 2016 und so ist die neue Version der Open-Source-Software vollgepackt mit frischen Features. Höchste Zeit, die überarbeitete Ausführung des preisgekrönten CMS genauer unter die Lupe zu nehmen.

Der Beitrag Jede Menge neue zukunftsorientierte Optionen: Joomla 4.0 setzt zum Endspurt an ist auf entwickler.de erschienen.

]]>
Joomla! [1] ist der drittgrößte Player [2] auf dem CMS-Markt. Der Startschuss für das kurz vor der Veröffentlichung stehende Major-Release 4.0 fiel bereits 2016 und so ist die neue Version der Open-Source-Software vollgepackt mit frischen Features. Höchste Zeit, die überarbeitete Ausführung des preisgekrönten CMS genauer unter die Lupe zu nehmen.

Der Beitrag Jede Menge neue zukunftsorientierte Optionen: Joomla 4.0 setzt zum Endspurt an ist auf entwickler.de erschienen.

]]>
https://kiosk.entwickler.de/php-magazin/php-magazin-3-2021/joomla-4-0-setzt-zum-endspurt-an/feed 0
Schleifen vermeiden mit LINQ: Abfragen mit LINQ übersichtlich und lesbar entwickeln https://kiosk.entwickler.de/php-magazin/php-magazin-2-2021/schleifen-vermeiden-mit-linq/ https://kiosk.entwickler.de/php-magazin/php-magazin-2-2021/schleifen-vermeiden-mit-linq/#respond Tue, 16 Mar 2021 11:00:12 +0000 https://entwickler.de/?p=579962039 Bereits seit .NET Framework 3.5 unterstützt C# das Feature LINQ. Obwohl mit Hilfe von LINQ der Code gegenüber klassischen Schleifen übersichtlicher und lesbarer wird, hat es sich zum Vermeiden von Schleifen noch nicht bei allen Entwicklern durchgesetzt. Oft wird innerhalb einer Schleife gefiltert und geschachtelt, was lange und unübersichtliche Schleifenblöcke zur Folge hat. Das soll mit LINQ ein Ende haben und jedem C#-Entwickler die Möglichkeit geben, Abfragen auf übersichtliche und lesbare Weise zu schreiben.

Der Beitrag Schleifen vermeiden mit LINQ: Abfragen mit LINQ übersichtlich und lesbar entwickeln ist auf entwickler.de erschienen.

]]>
Bereits seit .NET Framework 3.5 unterstützt C# das Feature LINQ. Obwohl mit Hilfe von LINQ der Code gegenüber klassischen Schleifen übersichtlicher und lesbarer wird, hat es sich zum Vermeiden von Schleifen noch nicht bei allen Entwicklern durchgesetzt. Oft wird innerhalb einer Schleife gefiltert und geschachtelt, was lange und unübersichtliche Schleifenblöcke zur Folge hat. Das soll mit LINQ ein Ende haben und jedem C#-Entwickler die Möglichkeit geben, Abfragen auf übersichtliche und lesbare Weise zu schreiben.

Der Beitrag Schleifen vermeiden mit LINQ: Abfragen mit LINQ übersichtlich und lesbar entwickeln ist auf entwickler.de erschienen.

]]>
https://kiosk.entwickler.de/php-magazin/php-magazin-2-2021/schleifen-vermeiden-mit-linq/feed 0
Sinnfreies Testing stoppen: Mit Mutation Testing zu sinnvolleren Unit-Tests https://kiosk.entwickler.de/php-magazin/php-magazin-2-2021/sinnfreies-testing-stoppen/ https://kiosk.entwickler.de/php-magazin/php-magazin-2-2021/sinnfreies-testing-stoppen/#respond Tue, 09 Mar 2021 11:00:45 +0000 https://entwickler.de/?p=579960671 Eine Testabdeckung von ≥ 80 Prozent wird heute häufig bei Projektbeginn festgelegt. Im weiteren Verlauf wird sie gerne als Beleg oder Metrik für die aktuelle Qualität der Software herangezogen. Leider haben die dahinterliegenden Tests oft nicht viel mehr Nutzen als diese Zahl zu erzeugen.

Der Beitrag Sinnfreies Testing stoppen: Mit Mutation Testing zu sinnvolleren Unit-Tests ist auf entwickler.de erschienen.

]]>
Eine Testabdeckung von ≥ 80 Prozent wird heute häufig bei Projektbeginn festgelegt. Im weiteren Verlauf wird sie gerne als Beleg oder Metrik für die aktuelle Qualität der Software herangezogen. Leider haben die dahinterliegenden Tests oft nicht viel mehr Nutzen als diese Zahl zu erzeugen.

Der Beitrag Sinnfreies Testing stoppen: Mit Mutation Testing zu sinnvolleren Unit-Tests ist auf entwickler.de erschienen.

]]>
https://kiosk.entwickler.de/php-magazin/php-magazin-2-2021/sinnfreies-testing-stoppen/feed 0
Architektur und Struktur: PHP End to End – Teil 2 https://kiosk.entwickler.de/php-magazin/php-magazin-2-2021/architektur-und-struktur/ https://kiosk.entwickler.de/php-magazin/php-magazin-2-2021/architektur-und-struktur/#respond Tue, 02 Mar 2021 11:00:26 +0000 https://entwickler.de/?p=579960491 PHP-Applikationen sind häufig Enterprise-Anwendungen, die i. d. R. umfangreich Nutzereingaben entgegennehmen, Daten validieren, diese verarbeiten und in einer Datenbank speichern. Doch welche Struktur erleichtert den Aufbau und führt auch über eine längere Zeit zu einer guten Wartbarkeit? Einige Denkanstöße und ein paar konkrete Lösungsvorschläge werden in diesem Artikel präsentiert.

Der Beitrag Architektur und Struktur: PHP End to End – Teil 2 ist auf entwickler.de erschienen.

]]>
PHP-Applikationen sind häufig Enterprise-Anwendungen, die i. d. R. umfangreich Nutzereingaben entgegennehmen, Daten validieren, diese verarbeiten und in einer Datenbank speichern. Doch welche Struktur erleichtert den Aufbau und führt auch über eine längere Zeit zu einer guten Wartbarkeit? Einige Denkanstöße und ein paar konkrete Lösungsvorschläge werden in diesem Artikel präsentiert.

Der Beitrag Architektur und Struktur: PHP End to End – Teil 2 ist auf entwickler.de erschienen.

]]>
https://kiosk.entwickler.de/php-magazin/php-magazin-2-2021/architektur-und-struktur/feed 0
Das PHP der Dinge: Peripheriegeräte und PHPoC – Eine IoT-Lösung für PHP-Entwickler (Teil 2) https://kiosk.entwickler.de/php-magazin/php-magazin-2-2021/das-php-der-dinge-peripheriegeraete/ https://kiosk.entwickler.de/php-magazin/php-magazin-2-2021/das-php-der-dinge-peripheriegeraete/#respond Tue, 23 Feb 2021 11:00:54 +0000 https://entwickler.de/?p=579959901 PHPoC (PHP on Chip) ist der Name einer IoT-Hardwareplattform für PHP-Entwickler aus dem Hause Sollae Systems. Wir unterziehen die Lösung einem Praxischeck und betrachten in Teil 2 der Serie die Möglichkeiten zur hardwarebeschleunigten Interaktion mit Peripheriegeräten. Da diese im Hintergrund auf einem klassischen STM32-Controller basieren, dürfen wir hohe Qualität erwarten. Zeit, dem Tier auf die Zähne zu blicken.

Der Beitrag Das PHP der Dinge: Peripheriegeräte und PHPoC – Eine IoT-Lösung für PHP-Entwickler (Teil 2) ist auf entwickler.de erschienen.

]]>
PHPoC (PHP on Chip) ist der Name einer IoT-Hardwareplattform für PHP-Entwickler aus dem Hause Sollae Systems. Wir unterziehen die Lösung einem Praxischeck und betrachten in Teil 2 der Serie die Möglichkeiten zur hardwarebeschleunigten Interaktion mit Peripheriegeräten. Da diese im Hintergrund auf einem klassischen STM32-Controller basieren, dürfen wir hohe Qualität erwarten. Zeit, dem Tier auf die Zähne zu blicken.

Der Beitrag Das PHP der Dinge: Peripheriegeräte und PHPoC – Eine IoT-Lösung für PHP-Entwickler (Teil 2) ist auf entwickler.de erschienen.

]]>
https://kiosk.entwickler.de/php-magazin/php-magazin-2-2021/das-php-der-dinge-peripheriegeraete/feed 0
MoneyPHP: Internationale Transaktionen leicht gemacht https://entwickler.de/online/php/moneyphp-579959763.html https://entwickler.de/online/php/moneyphp-579959763.html#respond Mon, 22 Feb 2021 09:06:46 +0000 https://entwickler.de/?p=579959763 Ein Softwarefehler bei der Risikoberechnung verursachte 217 Millionen Dollar an Investorenverlusten [1]. Es handelte sich um einen Fehler in grundlegenden Dezimaloperationen, die von einem Softwareentwickler programmiert wurden. Das zeigt uns, wie wichtig und verantwortungsvoll die Arbeit eines Entwicklers ist. Sind Sie sicher, dass Sie wissen, wie Sie solche Fehler in Ihren eigenen PHP-Anwendungen vermeiden können?

Der Beitrag MoneyPHP: Internationale Transaktionen leicht gemacht ist auf entwickler.de erschienen.

]]>
Ein Softwarefehler bei der Risikoberechnung verursachte 217 Millionen Dollar an Investorenverlusten [1]. Es handelte sich um einen Fehler in grundlegenden Dezimaloperationen, die von einem Softwareentwickler programmiert wurden. Das zeigt uns, wie wichtig und verantwortungsvoll die Arbeit eines Entwicklers ist. Sind Sie sicher, dass Sie wissen, wie Sie solche Fehler in Ihren eigenen PHP-Anwendungen vermeiden können?

Ich arbeite bereits seit 12 Jahren in der Softwareentwicklungsbranche und bei jedem Projekt, in das ich involviert war, ging es um die Verarbeitung von Finanztransaktionen. Ob es sich um einen Webshop, ein Nachrichtenportal, eine Affiliate-Marketing-Plattform oder ein internationales Zahlungsportal gehandelt hat – jedes Projekt hat einige monetäre Berechnungen durchgeführt. Es ist offensichtlich eine verantwortungsvolle Arbeit, und doch kommt es immer wieder vor, dass das Rad auf falsche Weise neu erfunden werden soll. Ist die richtige Verarbeitung von Finanztransaktionen so schwierig? Gibt es zuverlässige und verifizierte Lösungen, die wir wählen können? Wir werden uns weiter in dieses Thema vertiefen, indem wir einen sehr grundlegenden Schritt ausführen – die Erstellung einer Quittung für einen Kunden.

Geld in aller Welt

Bei über 200 Währungen auf der Welt gibt es viele Stolpersteine, die bei der Entwicklung einer Finanz-App beachtet werden müssen. Selbst wenn nur eine Währung verwendet werden soll, steckt der Teufel oftmals im Detail. Besonders schwierig wird es, wenn man sich an internationale Märkte heranwagen will. Fangen wir von vorne an. Wie schreibt und liest man Geldbeträge? Die meisten Währungen haben Untereinheiten, z. B. entspricht 1 Euro 100 Cent, daher ist es praktisch, Dezimalbrüche zu verwenden. Das Beispiel von 1 Euro und 23 Cent kann so etwa mit 1,23 EUR oder 1,23 € ausgedrückt werden.

Ein Cent lässt sich nicht halbieren, sodass von Zeit zu Zeit Rundungen vorgenommen werden müssen. Sollen zu 1,23 € 19 Prozent Steuern hinzugerechnet werden, ist das Ergebnis zunächst 1,4637 – nun muss entschieden werden, wie damit weiter verfahren werden soll. Auf- oder abrunden? Je nach örtlichem Gesetz könnten Sie am Ende entweder 1,46 oder 1,47 erhalten. Diese Unklarheit ist das Erste, was mit Product Ownern, Branchenexperten oder Anwälten geklärt werden muss. Diese Gespräche sollten niemals allein geführt werden – Ihre Aufgabe ist es, geschäftliche Anforderungen umzusetzen, nicht sie zu erraten!

Interessant wird es, wenn man verschiedene Währungen verarbeiten muss. Dann muss nicht nur Euro von Dollar unterschieden werden – es geht auch um die korrekte Umrechnung. Genauso wie Kilogramm und Pfund nicht direkt addieren werden können, können Euro und Dollar nicht zusammengezählt werden, ohne den Wechselkurs zwischen diesen beiden Währungen zu kennen. Die Kurse sind sicherlich jederzeit irgendwo im Internet zu finden, sie müssen jedoch von einer vertrauenswürdigen Quelle stammen, um die richtigen Berechnungen anstellen zu können.

Wie können die angesprochenen Probleme nun möglichst elegant gelöst werden, ohne dafür jedes Mal das Rad neu erfinden zu müssen? Wenn Millionen von Entwicklern auf der ganzen Welt mit ähnlichen Problemen zu kämpfen haben, kann davon ausgegangen werden, dass es einige gebrauchsfertige Lösungen gibt.

Warum Sie nicht alles selbst entwickeln sollten

Auf den ersten Blick sieht die Berechnung einer Quittung einfach aus: Man muss nur ein paar Zahlen addieren, richtig? Aber wie kann garantiert werden, dass die Berechnungen korrekt sind? Leider machen es uns die Computer nicht so einfach. Die CPUs wissen nicht, was eine Dezimalzahl ist. Wenn Sie einer Variablen eine Zahl wie 1,23 zuweisen, gibt es keine Garantie, dass eine CPU genau diesen Wert beibehält. Das liegt daran, dass CPUs und Programmiersprachen den IEEE-754-Standard verwenden, um Zahlen als Brüche zu speichern. Es sind reelle Zahlen, und der Datentyp heißt Floating Point [2] (oder kurz Float). Als der IEEE-Standard in den 1980er Jahren geschaffen wurde, verfügten Computer nur über sehr begrenzte Rechenleistung und Speicher. Die Ingenieure wollten einen möglichst großen Bereich von reellen Zahlen in nur 32 Bit unterbringen. Aus diesem Grund entschieden sie sich dafür, einen binären Typ statt eines Dezimaltyps zu verwenden. Jede Float Number wird als 2 ^ Exponent x Mantisse dargestellt. Wird dieser Wert in eine Dezimalzahl umgewandelt, ergibt sich sehr wahrscheinlich ein Präzisionsfehler.

Solche kleinen Fehler sind für wissenschaftliche Berechnungen in Ordnung, aber für die Finanzwelt völlig inakzeptabel. Leider ist die einzige Möglichkeit, mit PHP präzise Dezimalrechnungen durchzuführen, die Verwendung einer Bibliothek wie BC Math oder PHP Decimal. Sie ist nicht in die Sprache selbst integriert. Ein weiteres Problem, insbesondere für internationale Webanwendungen, ist die Unterscheidung von Währungen. Wenn eine Reihe von Zahlen verwechselt wird, ohne eine Idee von deren Währungen zu haben, werden die Berechnungen grundlegend falsch sein. Wenn die Prinzipien der objektorientierten Programmierung angewendet werden, sollte es ziemlich einfach sein, eine dedizierte Datenstruktur für Währungen und Finanzen zu erstellen.

Das Money-Pattern

In seinem Buch von 2002 schlug Martin Fowler eine Money-Struktur [3] vor, um einen Geldbetrag mit einer Währung zu kombinieren. Mit OOP können Sie diesen Wert in einem Objekt zusammenfassen und so sicherstellen, dass die Berechnungen durch die Klasse Money geschützt sind. Das Money-Pattern wurde für mehrere Sprachen wie PHP, Java und JavaScript implementiert. Es liegt nahe, dass die PHP-Implementierung MoneyPHP [4] heißt. Es handelt sich um eine ausgereifte Library, die es seit bereits seit fast zehn Jahren gibt. Listing 1 enthält ein Beispiel für die Verwendung.

use Money\Money;


// create an object of 1,23 EUR

$net = new Money(123, new Currency('EUR'));


// add 19% of tax, round up

$gross = $net->multiply('1.19', Money::ROUND_UP);


// output is 147, which means 1,47 EUR

echo $gross->getAmount();

Mit MoneyPHP können wir uns bei drei Dingen sicher sein: korrekte Dezimalberechnungen, Vermeidung von Fehlern bei der Verwendung mehrerer Währungen und Vermeidung versehentlicher Wertüberschreibungen, da Money ist ein unveränderliches Objekt ist. Jedes Mal, wenn eine Addition, Subtraktion oder eine andere Operation durchgeführt wird, erhalten wir eine neue Instanz der Money-Klasse. Dadurch werden Bugs vermieden, insbesondere wenn Ihre Money-Objekte zwischen mehreren Klassen wechseln, die die komplexe Geschäftslogik Ihrer Anwendung implementieren.

Intern speichert ein Money-Objekt den Betrag immer als String, d. h. in der kleinsten Untereinheit einer Währung. Für Euro ist das der Betrag in Cent, im obigen Beispiel entsprechen 1,23 € 123 Cent. Wenn also ein Eurobetrag vom Benutzer eingegeben wird, muss dieser nur mit 100 multipliziert oder das Dezimaltrennzeichen entfernt werden, um das Money-Objekt zu erstellen. Bei Währungen wie dem japanischen Yen oder dem ungarischen Forint ist es jedoch komplizierter. Der Yen hat aktuell keine Untereinheiten (sehr wohl aber in der Vergangenheit), daher erwartet MoneyPHP den Betrag in Yen. In Forint sind keine Münzen kleiner als 5 Ft im Umlauf, aber die 1/100-Untereinheit wird immer noch für Berechnungen verwendet. Wer Forint verwendet, muss sie für MoneyPHP immer noch mit 100 multiplizieren. Für die Verwendung von verschiedenen Währungen muss daher immer auch auf Details wie die eben erwähnten geachtet werden. Hilfestellung kann die ISO-4217-Liste der Währungen geben [5].

Die Währung richtig formatieren

Wenn wir dem Benutzer einen Geldbetrag darstellen, müssen wir die Sprache und Region berücksichtigen, die der Benutzer bevorzugt. Es reicht nicht aus, ein einfaches echo wie im ersten Listing zu verwenden. Verschiedene Regionen haben unterschiedliche Formatierungsstandards für Zahlen und Währungen. Einige Leute verwenden einen Punkt anstelle eines Kommas, um den Bruchteil zu trennen. Andere setzen die Währung vor den Betrag. Tabelle 1 zeigt einige Beispiele dafür.

Sprache und Region Beispiel eines Betrags
Deutsch (Deutschland) 12.345,67 €
Niederländisch (Niederlande) € 12.345,67
Polnisch (Polen) 12 345,67 €

Tabelle 1: Beispiele für Währungsformate in verschiedenen Sprachen und Regionen

Die meisten Money-Bibliotheken wie MoneyPHP bieten eine an den lokalen Gegebenheiten orientierte Formatierung der Geldbeträge an. Sie kombinieren Zahlen- und Währungsformatierungsregeln, die für ein Land und eine Sprache spezifisch sind (Listing 2).

use Money\Money;
use Money\Currencies\ISOCurrencies;
use Money\Currency;
use Money\Formatter\IntlMoneyFormatter;
use Money\Money;

// we need a repository of ISO standard currencies
$currencies = new ISOCurrencies();

// create an object of 1,23 EUR
$money = new Money(123, new Currency('EUR'));

// use a PHP "intl" number formatter for Germany...
$numberFormatter = new \NumberFormatter('de_DE', \NumberFormatter::CURRENCY);

// ...together with MoneyPHP formatter
$moneyFormatter = new IntlMoneyFormatter($numberFormatter, $currencies);

// output: 1,23 €
echo $moneyFormatter->format($money);

Im Beispiel in Listing 2 führt MoneyPHP ein Konzept von Währungsrepositorys ein. Bisher hatten wir nur einen Währungscode verwendet, aber jetzt muss der Formatter genau wissen, wie viele Stellen nach dem Dezimalzeichen für eine bestimmte Währung erwartet werden. Die Entwickler von MoneyPHP wollten sich nicht nur auf die Standard-ISO-Währungen beschränken. Wir werden vorerst das ISO-Repository verwenden, könnten allerdings auch ein eigenes implementieren, zum Beispiel für Kryptowährungen.

Ein weiterer Anwendungsfall eines Formatters für Money ist, Daten an ein API zu senden, das als Eingabe eine Dezimalzahl erwartet. Einige APIs könnten dem Schema.org-Standard PriceSpecification [6] folgen, der eine Dezimalzahl mit einem Punkt erwartet. Statt sich nun selbst eine Formatierung auszudenken, können Sie die Klasse DecimalMoneyFormatter verwenden, die in Listing 3 zu sehen ist.

use Money\Currency;
use Money\Formatter\DecimalMoneyFormatter;
use Money\Money;

// create an object of 1,23 EUR
$money = new Money(123, new Currency('EUR'));

// use a decimal number formatter
$decimalFormatter = new DecimalMoneyFormatter($currencies);

// output: 1.23
echo $decimalFormatter->format($money);

Integration von Backend- und Frontend-Layern

Bis jetzt haben wir eine gute Lösung gefunden, um Währungen in PHP zu speichern und sie an einen Benutzer auszugeben. Die meisten Webanwendungen verwenden jedoch mehrere Systeme. Ein Benutzer beginnt seine Reise mit dem Frontend-Layer, der dann eine Verbindung zum Backend herstellt, außerdem gibt es dann normalerweise eine Datenbank, zum Beispiel MySQL. Die Daten wandern hin und her – und auf jeder Ebene besteht die Gefahr, dass ein Teil der monetären Daten verloren geht. Aus diesem Grund müssen diese Daten mit besonderer Vorsicht verwaltet werden, angefangen bei dem Zeitpunkt, zu dem die Benutzereingaben erhalten wurden.

Nehmen wir an, es gibt einen Administrator, der einem Webshop Produkte hinzufügt und deren Preise definiert. Das einfachste Szenario wäre es, wenn ein HTML-Formular direkt per POST-Methode an das PHP-Skript gesendet wird. In diesem Fall erhalten wir den Preis in der Regel als lokalisierte Zahl, z. B. 1,23. Um ein Money-Objekt zu erstellen, muss es korrekt geparst werden.

Ein schwerwiegender Fehler, den ich an dieser Stelle mal gesehen habe, bestand darin, diesen Wert in ein Float umzuwandeln, dann mit 100 zu multiplizieren und schließlich das Ergebnis in ein Int zu konvertieren. Da der Float-Typ nicht präzise war und Int immer abgerundet wurde, ist ein Preis nicht auf 4,10 € festlegbar – er wird immer auf 4,09 € geändert. Um solche Fehler zu vermeiden, werden wir einen speziellen Money-Parser verwenden (Listing 4).

use Money\Currency;
use Money\Currencies\ISOCurrencies;
use Money\Parser\IntlLocalizedDecimalParser;

// we need a repository of ISO standard currencies
$currencies = new ISOCurrencies();

// use a PHP "intl" number formatter for Germany...
$numberFormatter = new \NumberFormatter('de_DE', \NumberFormatter::DECIMAL);

// ...together with MoneyPHP parser
$moneyParser = new IntlLocalizedDecimalParser($numberFormatter, $currencies);

// parse user input as euro
$money = $moneyParser->parse('1.234,56', new Currency('EUR'));

// output: 123456
echo $money->getAmount();

Natürlich kann der Frontend-Layer viel komplizierter sein als das; auf dieser Ebene können ja auch Client-seitige Validierungen oder sogar Berechnungen in JavaScript durchgeführt werden. Wie bereits erwähnt, gibt es bereits Implementierungen des Money-Patterns für JavaScript. Hier kann zwischen verschiedenen Bibliotheken wie currency.js, Dinero.js oder Money.js gewählt werden, das ist jedoch nicht Gegenstand dieses Artikels.

Im umgekehrten Fall müssen Sie aber möglicherweise ein Money-Objekt an JSON serialisieren und diese Daten an den Frontend-Layer senden. Die Money-Klasse implementiert das JsonSerializable-Interface, Sie müssen also nur die Funktion json_encode() verwenden, um die JSON-Datei zu empfangen, wie in Listing 5 gezeigt.

use Money\Money;

// create an object of 1,23 EUR
$net = new Money(123, new Currency('EUR'));

// output: {"amount":"123","currency":"EUR"}
echo json_encode($net);

Wenn Sie monetäre Daten zwischen Systemen austauschen, ist es immer entscheidend, zu wissen, ob beide Systeme die gleiche Einheit verwenden. Manchmal kann ein API den Betrag in Euro und ein anderes in Cent erwarten. Diese Diskrepanzen können zu Verwirrung und schwerwiegenden Fehlern führen. Es ist besser, aussagekräftigere Feldnamen wie amountDecimal oder amountInteger anstelle eines einfachen amount zu verwenden.

Geldbeträge in einer SQL-Datenbank verwalten

Für die SQL-Datenbanken ist die Lösung schwieriger, weil tatsächlich keine von ihnen das Money-Pattern implementiert. Einige Datenbanksysteme haben monetäre Datentypen, die eine global festgelegte Währung verwenden, aber das ist nicht das, was wir anstreben. Wir wollen beliebige Währungen im System speichern, ohne sie durcheinander zu bringen. Selbst wenn unsere Anwendung nur eine Währung verwendet, besteht die Chance, dass eines Tages eine neue Währung in unserem Land eingeführt wird. Wir müssen aussagekräftige Werte in der Datenbank speichern, um Probleme bei der Migration oder anderen Operationen, die eine Währungsumrechnung beinhalten, zu vermeiden.

Eine Lösung wäre, den Betrag in einer Spalte zu speichern, normalerweise vom Typ DECIMAL oder BIGINT (auf keinen Fall FLOAT oder DOUBLE!), und dann eine CHAR(3)-Spalte zu verwenden, um den ISO-Währungscode zu speichern. Das erlaubt es, einige Berechnungen direkt in der Datenbank durchzuführen, aber gleichzeitig ist es einfacher, die Währungen zu verwechseln. Eine andere Lösung besteht also darin, eine einzige VARCHAR-Spalte zu verwenden, um einen kodierten Wert wie EUR 123 zu speichern. Dann muss man den String in PHP dekodieren. So oder so müssen Sie darauf achten, entweder Euro oder Cent konsequent zu verwenden (Kasten: „Systeme ohne Fehler integrieren“).

Es ist nicht leicht zu entscheiden, wie groß der Datentyp für die Speicherung der Währung sein soll. Ein unsignierter 32-Bit INT-Typ würde Beträge über 4 Milliarden Euro ermöglichen, was mehr als genug erscheint. Allerdings haben Währungen in der Welt einen unterschiedlichen Wert, und sie können einer Hyperinflation unterliegen [7]. Im Jahr 2009 kostete in Simbabwe ein US-Dollar 1025 einer lokalen Währung. Ja, das ist die Zahl 1 mit 25 Nullen. Solche Extremfälle können schnell zu einem Integer Overflow führen. Sie sollten regelmäßig überprüfen, ob Ihre Systeme die aktuellen Geldbeträge noch verarbeiten können.

Ein Rechnungsmodell erstellen

Es spielt keine Rolle, ob Sie es eine Quittung, eine Rechnung oder einen Beleg nennen – der Punkt ist derselbe. Wir möchten ein juristisches Dokument erstellen, um den Kauf eines Kunden zu bestätigen. Die Struktur dieses Dokuments wird normalerweise durch das Gesetz festgelegt. Einige Felder, wie die Namen von Käufer und Verkäufer und eine Gesamtsumme, sind obligatorisch. Einige zusätzliche Felder können optional sein, aber sie können dennoch wertvolle Daten enthalten. Um anzufangen, greifen Sie sich einfach eine zufällig auf Ihrem Schreibtisch oder in Ihrer Brieftasche liegende Quittung und beginnen Sie mit der Untersuchung ihres Inhalts.

Dieselbe Quittung wird höchstwahrscheinlich in mehreren Formen vorliegen. Ein Kunde wird sie auf einer Webseite direkt nach einem Kauf und später in einem Abschnitt wie „“>Meine Bestellungen“ sehen. Vielleicht wird er oder sie eine E-Mail-Bestätigung mit einem PDF-Anhang erhalten. Wir haben mindestens vier Stellen, an denen ähnliche Daten präsentiert werden.

Es ist praktisch, eine Abstraktion des Dokuments zu erstellen. Lassen Sie uns eine Klasse namens Receipt entwickeln (Listing 6), die alle vom Gesetz, von Ihrer Firma und den Kunden geforderten Informationen enthält. An diesem Punkt werden wir uns nicht um SQL, JSON, HTML oder das PDF kümmern. Es geht nur um eine reine Datenstruktur mit einigen implementierten grundlegenden Verhaltensweisen, also ein abstraktes Modell.

use Money\Currency;
use Money\Money;

final class Contractor
{
  private string $name;
  private string $address;
  // constructor and getters below...
}

final class ReceiptItem
{
  private Money $unitPrice;
  private int $quantity;
  private int $tax;

  public function __construct(Money $unitPrice, int $quantity, int $tax)
  {
    // verify data correctness
    if ($quantity < 0 || $tax < 0) {
      throw new \Exception('Quantity and tax cannot be negative');
    }
    $this->unitPrice = $unitPrice;
    $this->quantity = $quantity;
    $this->tax = $tax;
  }

  // calculate total value of an item/row
  public function getTotalPrice(): Money
  {
    return $this->unitPrice
      ->multiply($this->quantity)
      ->multiply('1.' . $this->tax, Money::ROUND_UP);
  }
}

final class Receipt
{
  private Currency $currency;
  private Contractor $seller;
  private Contractor $buyer;
  private \DateTimeImmutable $issueDate;
  private \DateTimeImmutable $dueDate;
  /** @var array|ReceiptItem[] */
  private array $items = [];

  public function __construct(Currency $currency)
  {
    $this->currency = $currency;
  }

  public function addItem(Money $unitPrice, int $quantity, int $tax)
  {
    // check if the currencies match
    if (!$this->currency->equals($unitPrice->getCurrency())) {
      throw new \Exception('Currencies must match');
    }
    $this->items[] = new ReceiptItem($unitPrice, $quantity, $tax);
  }

  public function getTotalAmount(): Money
  {
    $sum = new Money(0, $this->currency);
    foreach ($this->items as $item) {
      $sum = $sum->add($item->getTotalPrice());
    }
    return $sum;
  }

  // other getters and setters below...
}

Im Beispiel in Listing 6 haben wir nun eine einfache Receipt-Klasse erstellt, die grundlegende Verkäufer- und Käuferdaten, das Ausstellungsdatum des Dokuments, das Fälligkeitsdatum der Zahlung und eine Liste von Artikeln (Zeilen) enthält. Der Beleg wird auf einer einzigen Währung basieren, daher haben wir eine zusätzliche Prüfung hinzugefügt, um sicherzustellen, dass alle Artikel dieselbe Währung haben. Es gibt eine Methode, mit der der zu zahlende Gesamtbetrag berechnet wird. Es ist sehr einfach, Tests für eine so einfache Klasse zu schreiben, die keine Verbindungen zu externen Systemen hat. Wir verwenden dafür PHPUnit [8] (Listing 7).

use Money\Currency;
use Money\Money;
use PHPUnit\Framework\TestCase;

final class ReceiptTest extends TestCase
{
  public function testTotalAmount(): void
  {
    // given
    $euro = new Currency('EUR');
    $receipt = new Receipt($euro);
    $receipt->addItem(new Money(123, $euro), 10, 19);

    // when
    $total = $receipt->getTotalAmount();

    // then
    self::assertEquals('1464', $total->getAmount());
    self::assertTrue($euro->equals($total->getCurrency()));
  }
}

Der Test ist sehr einfach. Er legt ein Receipt-Objekt mit Euro als Währung an und fügt dann einen Artikel mit einem Stückpreis von 1,23 € mal 10 Stück hinzu. Der Steuersatz für diesen Artikel beträgt 19 Prozent, also berechnet der Test den Gesamtbetrag, der 14,64 € betragen sollte.

Jetzt können wir jede noch verbleibende Logik zur Berechnung von Steuern, Zwischensummen und allen anderen Beträgen, die wir auf der Rechnung vorlegen müssen, testen und umsetzen. Im Allgemeinen wollen wir all diese Finanzlogik in unserer Receipt-Klasse einkapseln. Aus diesem Grund akzeptieren wir die berechneten Werte nicht als Benutzereingabe. Wir möchten sicherstellen, dass unsere Receipt-Objekte immer einen gültigen Zustand enthalten.

Um Ihr Receipt-Objekt mit anderen Systemen austauschbar zu machen, müssen Sie eine zusätzliche Infrastrukturschicht implementieren. Um das Objekt als JSON zu kodieren oder aus einem JSON-String zu dekodieren, erstellen wir nun unsere eigenen Serialisierer und Deserialisierer. Die Kodierungsarbeit kann jedoch auch durch die Implementierung der JsonSerializable-Schnittstelle in der Receipt-Klasse erfolgen. Die resultierenden Daten sollten zum Senden an den Frontend-Layer bereit sein (Listing 8).

final class Receipt implements JsonSerializable
{
  // prepare an array that will be encoded to JSON
  public function jsonSerialize(): array
  {
    return [
      'currency' => $this->currency->getCode(),
      'totalAmountInteger' => $this->getTotalAmount()->getAmount(),
      // more fields here...
    ];
  }
}

Eine andere Klasse, die als repository bezeichnet wird, wäre dann dafür zuständig, die Quittung in einer SQL-Datenbank zu speichern und sie wieder abzurufen. Sie können entweder auf bestehende ORM-Implementierungen wie Doctrine oder Eloquent zurückgreifen oder die Datenbanklogik selbst implementieren. Es hängt davon ab, wie sauber die Receipt-Klasse sein soll. Mit Doctrine würden Sie nur einige Anmerkungen zu dieser Klasse hinzufügen und ein separates Repository implementieren. Bei Eloquent müsste die Receipt-Klasse das Active-Record-Muster implementieren und damit eine Menge ändern. Das würde unsere Grundvoraussetzung nicht mehr erfüllen, dass die Receipt-Klasse nicht zu sehr an die Datenbank gebunden werden soll.

Zwischen Währungen umrechnen

Wenn Ihre Anwendung für internationale Märkte funktionieren soll, müssen Sie möglicherweise zwischen verschiedenen Währungen umrechnen. Selbst in der Europäischen Union hat nicht jedes Land den Euro. Einige Kunden ziehen es vielleicht vor, eine Rechnung in ihrer Landeswährung zu erhalten und oft ist es erforderlich, den umgerechneten Betrag irgendwo auf Papier zu deklarieren. Möglicherweise müssen Sie Ihrer Receipt-Klasse weitere Felder hinzufügen. Zuerst müssen Sie die aktuellen Wechselkurse von einem externen API abrufen. Es gibt eine Vielzahl von Diensten, aus denen Sie wählen können, darunter kostenlose und kostenpflichtige Angebote zum Beispiel Fixer, die Europäische Zentralbank oder Open Exchange Rates. Da die Währungsumrechnung eher ein Backend-Job sein sollte, werden wir den MoneyPHP Converter verwenden. Mit etwas Hilfe der Swap-Bibliothek werden wir die Wechselkurse von dem von Ihnen gewählten API abrufen und den Converter in Listing 9 mit Daten füttern. Weitere Tipps zum Umgang mit verschiedenen Währungen erhalten Sie im Kasten „Wie geht man mit Wechselkursen um?“.

use Money\Converter;
use Money\Currencies\ISOCurrencies;
use Money\Currency;
use Money\Exchange\SwapExchange;
use Money\Money;
use Swap\Builder;

// prepare the API client with your credentials
$swap = (new Builder())
-> add('some-api', ['access_key' =>  'your-key'])
-> build();

// build a currency exchange object
$exchange = new SwapExchange($swap);

// build a converter working on ISO currencies
$converter = new Converter(new ISOCurrencies(), $exchange);

// convert euros to dollars
$eur = new Money(123, new Currency('EUR'));
$usd = $converter-> convert($eur, new Currency('USD'));

Normalerweise ist es ausreichend, die komplette Wechselkurstabelle einmal pro Minute oder sogar einmal pro Stunde abzurufen und in Ihrer eigenen Datenbank zu speichern, damit Sie das API nicht überlasten. Besprechen Sie das Intervall für das Abrufen der Wechselkurse mit Ihren Domänenexperten. Speichern Sie immer das genaue Datum und die genaue Uhrzeit, die von dem von Ihnen verwendeten API angegeben werden. Außerdem sollten Sie bei jeder Währungsumrechnung in der Lage sein, nachzuweisen, welcher Kurs verwendet wurde und von welchem Zeitpunkt dieser stammt. Denken Sie daran, Datentypen zu verwenden, die groß genug sind, um jede beliebige Währung zu speichern, die Sie benötigen, und die präzise genug sind, die Wechselkurse zu speichern. Sie benötigen in der Regel vier Stellen nach dem Dezimalpunkt. Verwenden Sie zuverlässige Dezimaltypen und weder Float noch Double.

HTML- und PDF-Rechnungen rendern

Nach dem Kauf von Waren in Ihrem Webshop erwarten die meisten Kunden eine Bestätigung, eine Quittung oder eine Rechnung. Diese kann direkt nach dem Kauf, in einer E-Mail oder einer angehängten PDF-Datei angezeigt werden. Ähnliche Daten werden an mehreren Stellen dupliziert. Vielleicht können Sie einige HTML-Fragmente wiederverwenden, um Codeduplikation zu vermeiden. Zum Beispiel werden die Kundendaten oder die Produktliste höchstwahrscheinlich überall gleich sein.

Ihre Anwendung verwendet wahrscheinlich bereits eine Template-Engine wie Twig oder Blade, sodass wir hier nicht auf die Generierung des HTML-Codes eingehen werden. Wenn Sie einige praktische Methoden in Ihrer Receipt-Klasse vorbereitet haben, sollte es jetzt einfach sein, alle relevanten Daten an den richtigen Stellen der HTML-Vorlage einzubetten.

In diesem Stadium sollten Sie keine Berechnungen oder Entscheidungen innerhalb von HTML durchführen – das liegt in der Verantwortung der Receipt-Klasse! Wenn einige Teile des Dokuments an Bedingungen gebunden sind, implementieren Sie diese Logik in Ihrem Modell. Das Template darf nur einfache Fragen an das Modell stellen, z. B.: „Soll ich diesen Abschnitt anzeigen oder nicht?“

Sobald Sie ein HTML-Dokument vorbereitet haben, sollte es einfach sein, daraus eine PDF-Quittung zu erstellen. Es gibt viele Lösungen, um HTML direkt in ein PDF zu konvertieren. Quittungen haben normalerweise einfache Layouts, so dass zum Beispiel die dompdf-Bibliothek [9] ausreicht. Sie verfügt über eine eigene Rendering-Engine, die den größten Teil der Syntax von HTML5 und CSS 2.1 versteht (Listing 10).

$dompdf = new Dompdf\Dompdf();

// load the HTML document and set paper size
$dompdf->loadHtml($html);
$dompdf->setPaper('A4', 'portrait');

// render the document and get the PDF contents
$dompdf->render();
$pdf = $dompdf->output();

Das erstellte PDF testen

Auch wenn wir für unsere Receipt-Klasse Unit-Tests implementiert haben, sollten wir noch sicherstellen, dass unsere HTML-Vorlagen korrekt sind. Wenn Sie mit mehreren Geldbeträgen und mehreren Begriffen wie „Summe“, „Zwischensumme“ und so weiter arbeiten, könnten sich Fehler einschleichen, die vor dem Finanzamt schwer zu erklären sind. Das Testen von Dokumenten ist viel schwieriger als das Schreiben von Unit-Tests für Klassen. Eine Abschlussquittung kombiniert Geschäftsdaten mit HTML-Markup und vielleicht sogar einigen CSS-Tricks. Wenn Sie über eine saubere Struktur für das HTML-Template nachdenken, haben Sie deshalb den Vorteil, dass das Testen einfacher ist.

Der beste Weg, ein HTML-Template mit PHP zu testen, ist die Verwendung der gebündelten DOM-Erweiterung. DOM steht für Document Object Model und ist ein Standardmechanismus zur Darstellung einer HTML-Dokumentstruktur im Speicher. Nach dem Rendern einer Vorlage erstellen Sie also ein DOMDocument-Objekt und verwenden dann XPath-Abfragen, um alle Elemente nachzuschlagen, die wichtige Daten enthalten. Listing 11 zeigt das Vorgehen.

use PHPUnit\Framework\TestCase;

final class TemplateTest extends TestCase
{
  public function testTemplateRendersProperly(): void
  {
    // given
    $html = '<html><body><address class="seller">Foobar GmbH</address></body></html>';
    $document = new \DOMDocument();
    $document->loadHTML($html);
    $xpath = new \DOMXPath($document);

    // when
    $element = $xpath->query('//address[@class="seller"]')->item(0);

    // then
    self::assertEquals('Foobar GmbH', $element->textContent);
  }
}

Um sicherzustellen, dass das Layout Ihrer endgültigen Quittung korrekt ist, kann ein weiterer Test entweder einen Screenshot des fertigen PDFs erfassen und ihn mit dem erwarteten Bild vergleichen oder Text aus einem rechteckigen Bereich extrahieren, um zu sehen, ob ein erwarteter Datenblock richtig positioniert wurde. Auf diese Weise können Sie sicherstellen, dass sich die Kundendaten irgendwo in der rechten oberen Ecke befinden, die Produktliste irgendwo in der Mitte und so weiter.

Es ist nicht einfach, Text aus einer PDF-Datei zu extrahieren, da die physische Reihenfolge der Elemente in einer PDF-Datei oft von der im HTML abweicht. Eine PDF-Datei hat keinen Textfluss; sie arbeitet mit festen Inhaltsblöcken. Sie können dafür mit dem Werkzeug pdftotext aus dem Paket poppler-utils [10] oder mit Sébastien Malots PdfParser [11] experimentieren. Der Kasten „Sollte man Drittanbietertools vertrauen?” gibt einige Infos zur Verwendung solcher Tools.

Nun könnte noch die Frage aufkommen, warum man die fertigen PDF-Dateien testen sollten, wenn man eine beliebte Bibliothek verwendet, um sie aus HTML zu generieren. Die Frage ist: Wie sehr vertrauen Sie den Lösungen, die von anderen Leuten vorbereitet wurden? Haben Sie überprüft, wie gut die Bibliothek getestet wird? Sind Sie sicher, dass ein Upgrade der PDF-Bibliothek Ihr Layout nicht beeinträchtigt? Das ist mir nach einem kleineren Upgrade eines anderen PDF-Tools passiert.
Denken Sie daran, dass diese Programme von Leuten gemacht werden, die Fehler machen wie alle anderen auch. Ihre Kunden werden allerdings Ihnen die Schuld an den Fehlern anderer geben. Sie sind für die Werkzeuge, die Sie in Ihren Projekten verwenden, verantwortlich.

Fazit

Die Entwicklung von E-Commerce- und Finanzanwendungen ist eine verantwortungsvolle Aufgabe. Sie wollen sich oder Ihre Kunden nicht dem Risiko aussetzen, Geld und Ansehen zu verlieren. Sie können die Zuverlässigkeit Ihres Codes erheblich verbessern, indem Sie einige Grundregeln bei der Geldverarbeitung anwenden. Es gibt viele einsatzbereite Lösungen, die Ihnen die Arbeit erleichtern, sodass es nicht sinnvoll ist, das Rad neu zu erfinden.

Links & Literatur

[1] https://www.theregister.com/2011/09/22/software_bug_fine/

[2] https://floating-point-gui.de

[3] Fowler, Martin: „Patterns of Enterprise Application Architecture“, Addison-Wesley, 2002

[4] https://moneyphp.org

[5] https://www.iso.org/iso-4217-currency-codes.html

[6] https://schema.org/PriceSpecification

[7] https://de.wikipedia.org/wiki/Hyperinflation

[8] https://phpunit.de

[9] https://github.com/dompdf/dompdf

[10] https://poppler.freedesktop.org

[11] https://www.pdfparser.org

Der Beitrag MoneyPHP: Internationale Transaktionen leicht gemacht ist auf entwickler.de erschienen.

]]>
https://entwickler.de/online/php/moneyphp-579959763.html/feed 0
Einführung einer Build Pipeline: Erfolgreich Softwareprojekte modernisieren – Teil 2 https://kiosk.entwickler.de/php-magazin/php-magazin-2-2021/einfuehrung-einer-build-pipeline/ https://kiosk.entwickler.de/php-magazin/php-magazin-2-2021/einfuehrung-einer-build-pipeline/#respond Tue, 16 Feb 2021 11:00:50 +0000 https://entwickler.de/?p=579958979 Der vorangegangene Artikel der Serie befasste sich mit dem Faktor Mensch. Neben der dort angesprochenen Modernisierung von innen heraus müssen sich die Entwicklerinnen zwangsläufig mit der Software in der Form befassen, in der sie gerade vorliegt. Fehler müssen behoben, Funktionalitäten umgesetzt und die Software ihren Benutzerinnen zur Verfügung gestellt werden.

Der Beitrag Einführung einer Build Pipeline: Erfolgreich Softwareprojekte modernisieren – Teil 2 ist auf entwickler.de erschienen.

]]>
Der vorangegangene Artikel der Serie befasste sich mit dem Faktor Mensch. Neben der dort angesprochenen Modernisierung von innen heraus müssen sich die Entwicklerinnen zwangsläufig mit der Software in der Form befassen, in der sie gerade vorliegt. Fehler müssen behoben, Funktionalitäten umgesetzt und die Software ihren Benutzerinnen zur Verfügung gestellt werden.

Der Beitrag Einführung einer Build Pipeline: Erfolgreich Softwareprojekte modernisieren – Teil 2 ist auf entwickler.de erschienen.

]]>
https://kiosk.entwickler.de/php-magazin/php-magazin-2-2021/einfuehrung-einer-build-pipeline/feed 0