From 1db65f78a7f0aed4f26324d05348846226d9ec06 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Mon, 2 Sep 2024 01:21:39 +0200 Subject: [PATCH 1/5] new translation wip --- latte/de/filters.texy | 482 ++++++++++++++++++++-------------------- latte/de/tags.texy | 498 +++++++++++++++++++++--------------------- 2 files changed, 490 insertions(+), 490 deletions(-) diff --git a/latte/de/filters.texy b/latte/de/filters.texy index 701c434b25..a205f37276 100644 --- a/latte/de/filters.texy +++ b/latte/de/filters.texy @@ -1,101 +1,101 @@ -Latte Filtern -************* +Latte Filter +************ .[perex] -Filter sind Funktionen, die die Daten in der gewünschten Form verändern oder formatieren. Dies ist eine Zusammenfassung der eingebauten Filter, die verfügbar sind. +In Templates können wir Funktionen verwenden, die bei der Anpassung oder Umformatierung von Daten in die endgültige Form helfen. Wir nennen sie *Filter*. .[table-latte-filters] -|## String / Array Transformation -| `batch` | [Auflistung linearer Daten in einer Tabelle |#batch] -| `breakLines` | [fügt HTML-Zeilenumbrüche vor allen Zeilenumbrüchen ein |#breakLines] -| `bytes` | [formatiert Größe in Bytes |#bytes] -| `clamp` | [klemmt Wert auf den Bereich |#clamp] -| `dataStream` | [Konvertierung des Daten-URI-Protokolls |#datastream] -| `date` | [formatiert das Datum und die Uhrzeit |#date] -| `explode` | [trennt eine Zeichenkette durch das angegebene Trennzeichen auf |#explode] -| `first` | [gibt das erste Element eines Arrays oder ein Zeichen einer Zeichenkette zurück |#first] -| `group` | [gruppiert Daten nach verschiedenen Kriterien |#group] -| `implode` | [fügt ein Array zu einer Zeichenkette zusammen |#implode] -| `indent` | [rückt den Text von links mit einer Anzahl von Tabulatorenein |#indent] -| `join` | [verbindet ein Array mit einer Zeichenkette|#implode] -| `last` | [gibt das letzte Element eines Arrays oder ein Zeichen einer Zeichenkette zurück |#last] -| `length` | [gibt die Länge einer Zeichenkette oder eines Arrays zurück |#length] -| `localDate` | [formatiert das Datum und die Uhrzeit entsprechend dem Gebietsschema |#localDate] -| `number` | [formatiert Zahlen |#number] -| `padLeft` | [vervollständigt die Zeichenkette auf die angegebene Länge von links |#padLeft] -| `padRight` | [vervollständigt die Zeichenkette auf die angegebene Länge von rechts |#padRight] -| `random` | [gibt zufällige Elemente eines Arrays oder Zeichen einer Zeichenkette zurück |#random] -| `repeat` | [Wiederholt die Zeichenkette |#repeat] -| `replace` | [ersetzt alle Vorkommen der gesuchten Zeichenkette durch die Ersetzung |#replace] -| `replaceRE` | [ersetzt alle Vorkommen entsprechend dem regulären Ausdruck |#replaceRE] -| `reverse` | [kehrt eine UTF-8 Zeichenkette oder ein Array um |#reverse] -| `slice` | [extrahiert einen Ausschnitt aus einem Array oder einer Zeichenkette |#slice] -| `sort` | [sortiert ein Array |#sort] -| `spaceless` | [entfernt Leerzeichen |#spaceless], ähnlich dem [spaceless |tags] tag -| `split` | [trennt eine Zeichenkette durch das angegebene Trennzeichen auf |#explode] -| `strip` | [Entfernt Leerzeichen |#spaceless] -| `stripHtml` | [entfernt HTML-Tags und konvertiert HTML-Entities in Text |#stripHtml] -| `substr` | [gibt einen Teil der Zeichenkette zurück |#substr] -| `trim` | [entfernt Leerzeichen aus der Zeichenkette |#trim] -| `translate` | [Übersetzung in andere Sprachen |#translate] -| `truncate` | [verkürzt die Länge unter Beibehaltung ganzer Wörter |#truncate] -| `webalize` | [passt die UTF-8-Zeichenfolge an die in der URL verwendete Forman |#webalize] +|## Transformation +| `batch` | [Auflistung linearer Daten in einer Tabelle |#batch] +| `breakLines` | [Fügt HTML-Zeilenumbrüche am Ende der Zeilen hinzu |#breakLines] +| `bytes` | [formatiert die Größe in Bytes |#bytes] +| `clamp` | [begrenzt einen Wert auf einen bestimmten Bereich |#clamp] +| `dataStream` | [Konvertierung für das Data URI-Protokoll |#datastream] +| `date` | [formatiert Datum und Uhrzeit |#date] +| `explode` | [teilt eine Zeichenkette in ein Array anhand eines Trennzeichens |#explode] +| `first` | [gibt das erste Element eines Arrays oder Zeichen einer Zeichenkette zurück |#first] +| `group` | [gruppiert Daten nach verschiedenen Kriterien |#group] +| `implode` | [verbindet ein Array zu einer Zeichenkette |#implode] +| `indent` | [rückt Text von links um eine bestimmte Anzahl von Tabulatoren ein |#indent] +| `join` | [verbindet ein Array zu einer Zeichenkette |#implode] +| `last` | [gibt das letzte Element eines Arrays oder Zeichen einer Zeichenkette zurück |#last] +| `length` | [gibt die Länge einer Zeichenkette in Zeichen oder eines Arrays zurück |#length] +| `localDate` | [formatiert Datum und Uhrzeit entsprechend den Ländereinstellungen |#localDate] +| `number` | [formatiert eine Zahl |#number] +| `padLeft` | [füllt eine Zeichenkette links auf eine bestimmte Länge auf |#padLeft] +| `padRight` | [füllt eine Zeichenkette rechts auf eine bestimmte Länge auf |#padRight] +| `random` | [gibt ein zufälliges Element eines Arrays oder Zeichen einer Zeichenkette zurück |#random] +| `repeat` | [Wiederholung einer Zeichenkette |#repeat] +| `replace` | [ersetzt Vorkommen einer gesuchten Zeichenkette |#replace] +| `replaceRE` | [ersetzt Vorkommen anhand eines regulären Ausdrucks |#replaceRE] +| `reverse` | [kehrt eine UTF-8 Zeichenkette oder ein Array um |#reverse] +| `slice` | [extrahiert einen Teil eines Arrays oder einer Zeichenkette |#slice] +| `sort` | [sortiert ein Array |#sort] +| `spaceless` | [entfernt Leerzeichen |#spaceless], ähnlich wie das [spaceless |tags] Tag +| `split` | [teilt eine Zeichenkette in ein Array anhand eines Trennzeichens |#explode] +| `strip` | [entfernt Leerzeichen |#spaceless] +| `stripHtml` | [entfernt HTML-Tags und konvertiert HTML-Entities in Zeichen |#stripHtml] +| `substr` | [gibt einen Teil einer Zeichenkette zurück |#substr] +| `trim` | [entfernt führende und abschließende Leerzeichen oder andere Zeichen |#trim] +| `translate` | [Übersetzung in andere Sprachen |#translate] +| `truncate` | [kürzt die Länge unter Beibehaltung von Wörtern |#truncate] +| `webalize` | [passt eine UTF-8 Zeichenkette in eine in URLs verwendete Form an |#webalize] .[table-latte-filters] -|## Buchstabenumbruch -| `capitalize` | [Kleinschreibung, der erste Buchstabe eines jeden Wortes wird großgeschrieben |#capitalize] -| `firstUpper` | [macht den ersten Buchstaben zu einem Großbuchstaben |#firstUpper] -| `lower` | [macht eine Zeichenfolge klein |#lower] -| `upper` | [macht eine Zeichenkette zu einem Großbuchstaben |#upper] +|## Groß-/Kleinschreibung +| `capitalize` | [Kleinbuchstaben, erste Buchstaben der Wörter groß |#capitalize] +| `firstUpper` | [konvertiert den ersten Buchstaben in einen Großbuchstaben |#firstUpper] +| `lower` | [konvertiert in Kleinbuchstaben |#lower] +| `upper` | [konvertiert in Großbuchstaben |#upper] .[table-latte-filters] -|## Rundung von Zahlen -| `ceil` | [rundet eine Zahl auf eine bestimmte Genauigkeit auf|#ceil] -| `floor` | [rundet eine Zahl auf eine bestimmte Genauigkeit ab |#floor] -| `round` | [rundet eine Zahl auf eine bestimmte Genauigkeit|#round] +|## Rundung +| `ceil` | [rundet eine Zahl auf eine bestimmte Genauigkeit auf |#ceil] +| `floor` | [rundet eine Zahl auf eine bestimmte Genauigkeit ab |#floor] +| `round` | [rundet eine Zahl auf eine bestimmte Genauigkeit |#round] .[table-latte-filters] |## Escaping -| `escapeUrl` | [gibt einen Parameter in der URL als Escapezeichen aus|#escapeUrl] -| `noescape` | [druckt eine Variable ohne Escaping |#noescape] -| `query` | [erzeugt eine Abfragezeichenfolge in der URL |#query] +| `escapeUrl` | [escapet einen Parameter in einer URL |#escapeUrl] +| `noescape` | [gibt eine Variable ohne Escaping aus |#noescape] +| `query` | [generiert einen Query-String in einer URL |#query] -Es gibt auch Escape-Filter für HTML (`escapeHtml` und `escapeHtmlComment`), XML (`escapeXml`), JavaScript (`escapeJs`), CSS (`escapeCss`) und iCalendar (`escapeICal`), die Latte dank [kontextsensitivem Escaping |safety-first#Context-aware escaping] selbst verwendet und die Sie nicht schreiben müssen. +Es gibt außerdem Escaping-Filter für HTML (`escapeHtml` und `escapeHtmlComment`), XML (`escapeXml`), JavaScript (`escapeJs`), CSS (`escapeCss`) und iCalendar (`escapeICal`), die Latte selbst dank [kontextsensitivem Escaping |safety-first#Context-aware escaping] verwendet und die Sie nicht explizit schreiben müssen. .[table-latte-filters] |## Sicherheit -| `checkUrl` | [säubert Zeichenketten für die Verwendung im href-Attribut |#checkUrl] -| `nocheck` | [verhindert automatische URL-Sanitisierung |#nocheck] +| `checkUrl` | [behandelt eine URL-Adresse gegen gefährliche Eingaben |#checkUrl] +| `nocheck` | [verhindert die automatische Behandlung einer URL-Adresse |#nocheck] -Latte der `src` und `href` Attribute [prüft automatisch |safety-first#link checking], so dass Sie den `checkUrl` Filter fast nicht verwenden müssen. +Latte [überprüft automatisch |safety-first#link checking] die Attribute `src` und `href`, sodass Sie den `checkUrl`-Filter fast nie verwenden müssen. .[note] -Alle eingebauten Filter arbeiten mit UTF-8 kodierten Zeichenketten. +Alle Standard-Filter sind für Zeichenketten in UTF-8-Kodierung ausgelegt. Verwendung .[#toc-usage] ======================== -Latte erlaubt den Aufruf von Filtern unter Verwendung der Pipe-Schreibweise (vorangestelltes Leerzeichen ist erlaubt): +Filter werden durch einen senkrechten Strich notiert (vor dem ein Leerzeichen stehen kann): ```latte

{$heading|upper}

``` -Filter können verkettet werden, in diesem Fall gelten sie in der Reihenfolge von links nach rechts: +Filter (in älteren Versionen Helper genannt) können verkettet werden und werden dann in der Reihenfolge von links nach rechts angewendet: ```latte

{$heading|lower|capitalize}

``` -Die Parameter werden durch Doppelpunkt oder Komma getrennt hinter den Filternamen gesetzt: +Parameter werden nach dem Filternamen durch Doppelpunkte oder Kommas getrennt angegeben: ```latte

{$heading|truncate:20,''}

``` -Filter können auf Ausdrücke angewendet werden: +Filter können auch auf Ausdrücke angewendet werden: ```latte {var $name = ($title|upper) . ($subtitle|lower)} @@ -108,7 +108,7 @@ $latte = new Latte\Engine; $latte->addFilter('shortify', fn(string $s, int $len = 10) => mb_substr($s, 0, $len)); ``` -Wir verwenden sie in einer Vorlage wie dieser: +Im Template wird es dann so aufgerufen: ```latte

{$text|shortify}

@@ -122,7 +122,7 @@ Filter .[#toc-filters] batch(int $length, mixed $item): array .[filter] ------------------------------------------------ -Filter, der die Auflistung von linearen Daten in Form einer Tabelle vereinfacht. Er gibt ein Array von Arrays mit der angegebenen Anzahl von Elementen zurück. Wenn Sie einen zweiten Parameter angeben, wird dieser verwendet, um fehlende Elemente in der letzten Zeile aufzufüllen. +Ein Filter, der die Ausgabe linearer Daten in Form einer Tabelle vereinfacht. Er gibt ein Array von Arrays mit der angegebenen Anzahl von Elementen zurück. Wenn Sie einen zweiten Parameter angeben, wird er verwendet, um fehlende Elemente in der letzten Zeile zu ergänzen. ```latte {var $items = ['a', 'b', 'c', 'd', 'e']} @@ -137,7 +137,7 @@ Filter, der die Auflistung von linearen Daten in Form einer Tabelle vereinfacht. ``` -Druckt: +Gibt aus: ```latte @@ -154,22 +154,22 @@ Druckt:
``` -Siehe auch [group |#group] und [iterateWhile-Tag |tags#iterateWhile]. +Siehe auch [#group] und das [iterateWhile |tags#iterateWhile] Tag. breakLines .[filter] -------------------- -Fügt HTML-Zeilenumbrüche vor allen Zeilenumbrüchen ein. +Fügt vor jedem Zeilenumbruchzeichen ein HTML-Tag `
` ein ```latte {var $s = "Text & with \n newline"} -{$s|breakLines} {* gibt "Text & with
\n newline" *} +{$s|breakLines} {* gibt "Text & with
\n newline" aus *} ``` bytes(int $precision=2) .[filter] --------------------------------- -Formatiert die Größe in Bytes in eine für Menschen lesbare Form. Wenn das [Gebietsschema |develop#locale] festgelegt ist, werden die entsprechenden Dezimal- und Tausendertrennzeichen verwendet. +Formatiert die Größe in Bytes in eine menschenlesbare Form. Wenn [Ländereinstellungen |develop#locale] gesetzt sind, werden die entsprechenden Dezimal- und Tausendertrennzeichen verwendet. ```latte {$size|bytes} 0 B, 1.25 GB, … @@ -179,51 +179,51 @@ Formatiert die Größe in Bytes in eine für Menschen lesbare Form. Wenn das [Ge ceil(int $precision=0) .[filter] -------------------------------- -Rundet eine Zahl bis zu einer bestimmten Genauigkeit. +Rundet eine Zahl auf eine bestimmte Genauigkeit auf. ```latte -{=3.4|ceil} {* gibt 4 *} -{=135.22|ceil:1} {* gibt 135.3 *} -{=135.22|ceil:3} {* gibt 135.22 *} +{=3.4|ceil} {* gibt 4 aus *} +{=135.22|ceil:1} {* gibt 135.3 aus *} +{=135.22|ceil:3} {* gibt 135.22 aus *} ``` -Siehe auch [Stockwerk |#floor], [Runden |#round]. +Siehe auch [#floor], [#round]. capitalize .[filter] -------------------- -Gibt eine Version des Wertes in Großbuchstaben zurück. Die Wörter beginnen mit Großbuchstaben, alle übrigen Zeichen sind Kleinbuchstaben. Erfordert die PHP-Erweiterung `mbstring`. +Wörter beginnen mit Großbuchstaben, alle verbleibenden Zeichen sind klein. Erfordert die PHP-Erweiterung `mbstring`. ```latte -{='i like LATTE'|capitalize} {* gibt 'I Like Latte' *} +{='i like LATTE'|capitalize} {* gibt 'I Like Latte' aus *} ``` -Siehe auch [firstUpper |#firstUpper], [lower |#lower], [upper |#upper]. +Siehe auch [#firstUpper], [#lower], [#upper]. checkUrl .[filter] ------------------ -Erzwingt URL-Sanitization. Sie prüft, ob die Variable eine Web-URL enthält (d. h. HTTP/HTTPS-Protokoll) und verhindert das Schreiben von Links, die ein Sicherheitsrisiko darstellen könnten. +Erzwingt die Behandlung einer URL-Adresse. Überprüft, ob die Variable eine Web-URL enthält (d.h. HTTP/HTTPS-Protokoll) und verhindert die Ausgabe von Links, die ein Sicherheitsrisiko darstellen können. ```latte {var $link = 'javascript:window.close()'} -checked -unchecked +geprüft +ungeprüft ``` -Druckt: +Gibt aus: ```latte -checked -unchecked +geprüft +ungeprüft ``` -Siehe auch [nocheck |#nocheck]. +Siehe auch [#nocheck]. clamp(int|float $min, int|float $max) .[filter] ----------------------------------------------- -Gibt einen Wert zurück, der auf den einschließenden Bereich von min und max geklemmt ist. +Begrenzt einen Wert auf den angegebenen inklusiven Bereich von min und max. ```latte {$level|clamp: 0, 255} @@ -234,15 +234,15 @@ Existiert auch als [Funktion |functions#clamp]. dataStream(string $mimetype=detect) .[filter] --------------------------------------------- -Konvertiert den Inhalt in ein Daten-URI-Schema. Es kann verwendet werden, um Bilder in HTML oder CSS einzufügen, ohne dass externe Dateien verlinkt werden müssen. +Konvertiert den Inhalt in das Data URI-Schema. Damit können Bilder ohne die Notwendigkeit externer Dateien in HTML oder CSS eingebettet werden. -Nehmen wir an, ein Bild befindet sich in einer Variablen `$img = Image::fromFile('obrazek.gif')`, dann +Angenommen, wir haben ein Bild in der Variable `$img = Image::fromFile('bild.gif')`, dann ```latte ``` -Druckt zum Beispiel: +Gibt beispielsweise aus: ```latte {$name} ``` -Siehe auch [Abfrage |#query]. +Siehe auch [#query]. explode(string $separator='') .[filter] --------------------------------------- -Teilt eine Zeichenkette durch den angegebenen Begrenzer und gibt ein Array von Zeichenketten zurück. Alias für `split`. +Teilt eine Zeichenkette anhand eines Trennzeichens in ein Array. Alias für `split`. ```latte -{='one,two,three'|explode:','} {* liefert ['one', 'two', 'three'] *} +{='one,two,three'|explode:','} {* gibt ['one', 'two', 'three'] zurück *} ``` Wenn das Trennzeichen eine leere Zeichenkette ist (Standardwert), wird die Eingabe in einzelne Zeichen aufgeteilt: ```latte -{='123'|explode} {* liefert ['1', '2', '3'] *} +{='123'|explode} {* gibt ['1', '2', '3'] zurück *} ``` Sie können auch den Alias `split` verwenden: ```latte -{='1,2,3'|split:','} {* liefert ['1', '2', '3'] *} +{='1,2,3'|split:','} {* gibt ['1', '2', '3'] zurück *} ``` -Siehe auch [implode |#implode]. +Siehe auch [#implode]. first .[filter] --------------- -Gibt das erste Element eines Arrays oder ein Zeichen einer Zeichenkette zurück: +Gibt das erste Element eines Arrays oder das erste Zeichen einer Zeichenkette zurück: ```latte -{=[1, 2, 3, 4]|first} {* gibt 1 *} -{='abcd'|first} {* gibt 'a' *} +{=[1, 2, 3, 4]|first} {* gibt 1 aus *} +{='abcd'|first} {* gibt 'a' aus *} ``` -Siehe auch [last |#last], [random |#random]. +Siehe auch [#last], [#random]. floor(int $precision=0) .[filter] @@ -316,30 +316,30 @@ floor(int $precision=0) .[filter] Rundet eine Zahl auf eine bestimmte Genauigkeit ab. ```latte -{=3.5|floor} {* gibt 3 *} -{=135.79|floor:1} {* gibt 135.7 *} -{=135.79|floor:3} {* gibt 135.79 *} +{=3.5|floor} {* gibt 3 aus *} +{=135.79|floor:1} {* gibt 135.7 aus *} +{=135.79|floor:3} {* gibt 135.79 aus *} ``` -Siehe auch [ceil |#ceil], [round |#round]. +Siehe auch [#ceil], [#round]. firstUpper .[filter] -------------------- -Konvertiert den ersten Buchstaben eines Wertes in Großbuchstaben. Erfordert die PHP-Erweiterung `mbstring`. +Konvertiert den ersten Buchstaben in einen Großbuchstaben. Erfordert die PHP-Erweiterung `mbstring`. ```latte -{='the latte'|firstUpper} {* gibt 'The latte' *} +{='the latte'|firstUpper} {* gibt 'The latte' aus *} ``` -Siehe auch [capitalize |#capitalize], [lower |#lower], [upper |#upper]. +Siehe auch [#capitalize], [#lower], [#upper]. group(string|int|\Closure $by): array .[filter]{data-version:3.0.16} -------------------------------------------------------------------- -Der Filter gruppiert die Daten nach verschiedenen Kriterien. +Filter, der Daten nach verschiedenen Kriterien gruppiert. -In diesem Beispiel werden die Zeilen in der Tabelle nach der Spalte `categoryId` gruppiert. Die Ausgabe ist ein Array von Arrays, wobei der Schlüssel der Wert in der Spalte `categoryId` ist. Lesen Sie die [ausführliche Anleitung |cookbook/grouping]. +In diesem Beispiel werden die Tabellenzeilen nach der Spalte `categoryId` gruppiert. Die Ausgabe ist ein Array von Arrays, wobei der Schlüssel der Wert in der Spalte `categoryId` ist. [Lesen Sie die detaillierte Anleitung |cookbook/grouping]. ```latte {foreach ($items|group: categoryId) as $categoryId => $categoryItems} @@ -351,28 +351,28 @@ In diesem Beispiel werden die Zeilen in der Tabelle nach der Spalte `categoryId` {/foreach} ``` -Siehe auch [Batch |#batch], die [Gruppenfunktion |functions#group] und das [iterateWhile-Tag |tags#iterateWhile]. +Siehe auch [#batch], die Funktion [group |functions#group] und das Tag [iterateWhile |tags#iterateWhile]. implode(string $glue='') .[filter] ---------------------------------- -Gibt eine Zeichenkette zurück, die die Verkettung der Zeichenketten im Array ist. Alias für `join`. +Gibt eine Zeichenkette zurück, die eine Verkettung der Elemente einer Sequenz ist. Alias für `join`. ```latte -{=[1, 2, 3]|implode} {* gibt '123' *} -{=[1, 2, 3]|implode:'|'} {* gibt '1|2|3' *} +{=[1, 2, 3]|implode} {* gibt '123' aus *} +{=[1, 2, 3]|implode:'|'} {* gibt '1|2|3' aus *} ``` -Sie können auch einen Alias `join` verwenden: +Sie können auch den Alias `join` verwenden: ```latte -{=[1, 2, 3]|join} {* gibt '123' *} +{=[1, 2, 3]|join} {* gibt '123' aus *} ``` indent(int $level=1, string $char="\t") .[filter] ------------------------------------------------- -Rückt einen Text von links um eine bestimmte Anzahl von Tabulatoren oder anderen Zeichen ein, die wir im zweiten optionalen Argument angeben. Leerzeilen werden nicht eingerückt. +Rückt Text von links um eine bestimmte Anzahl von Tabulatoren oder anderen Zeichen ein, die im zweiten Argument angegeben werden können. Leere Zeilen werden nicht eingerückt. ```latte
@@ -382,7 +382,7 @@ Rückt einen Text von links um eine bestimmte Anzahl von Tabulatoren oder andere
``` -Druckt: +Gibt aus: ```latte
@@ -393,24 +393,24 @@ Druckt: last .[filter] -------------- -Gibt das letzte Element eines Arrays oder ein Zeichen einer Zeichenkette zurück: +Gibt das letzte Element eines Arrays oder das letzte Zeichen einer Zeichenkette zurück: ```latte -{=[1, 2, 3, 4]|last} {* gibt 4 *} -{='abcd'|last} {* gibt 'd' *} +{=[1, 2, 3, 4]|last} {* gibt 4 aus *} +{='abcd'|last} {* gibt 'd' aus *} ``` -Siehe auch [first |#first], [random |#random]. +Siehe auch [#first], [#random]. length .[filter] ---------------- Gibt die Länge einer Zeichenkette oder eines Arrays zurück. -- bei Strings wird die Länge in UTF-8 Zeichen zurückgegeben -- für Arrays wird die Anzahl der Elemente zurückgegeben -- bei Objekten, die die Schnittstelle Countable implementieren, wird der Rückgabewert der Funktion count() verwendet -- für Objekte, die die Schnittstelle IteratorAggregate implementieren, wird der Rückgabewert von iterator_count() verwendet. +- für Zeichenketten gibt es die Länge in UTF-8-Zeichen zurück +- für Arrays gibt es die Anzahl der Elemente zurück +- für Objekte, die das Countable-Interface implementieren, verwendet es den Rückgabewert der count()-Methode +- für Objekte, die das IteratorAggregate-Interface implementieren, verwendet es den Rückgabewert der iterator_count()-Funktion ```latte @@ -422,28 +422,28 @@ Gibt die Länge einer Zeichenkette oder eines Arrays zurück. localDate(?string $format=null, ?string $date=null, ?string $time=null) .[filter] --------------------------------------------------------------------------------- -Formatiert Datum und Uhrzeit entsprechend dem [Gebietsschema |develop#locale], um eine konsistente und lokalisierte Anzeige von Zeitdaten in verschiedenen Sprachen und Regionen zu gewährleisten. Der Filter akzeptiert das Datum als UNIX-Zeitstempel, String oder `DateTimeInterface` Objekt. +Formatiert Datum und Uhrzeit gemäß den [Ländereinstellungen |develop#locale], was eine konsistente und lokalisierte Darstellung von Zeitangaben in verschiedenen Sprachen und Regionen gewährleistet. Der Filter akzeptiert ein Datum als UNIX-Timestamp, Zeichenkette oder Objekt vom Typ `DateTimeInterface`. ```latte -{$date|localDate} {* 15. dubna 2024 *} +{$date|localDate} {* 15. April 2024 *} {$date|format: yM} {* 4/2024 *} {$date|localDate: date: medium} {* 15. 4. 2024 *} ``` -Wenn Sie den Filter ohne Parameter verwenden, gibt er das Datum in der Langformatebene aus, wie weiter unten erläutert. +Wenn Sie den Filter ohne Parameter verwenden, wird das Datum auf der Ebene `long` ausgegeben, siehe unten. **a) Verwendung des Formats** -Der Parameter `format` beschreibt, welche Zeitkomponenten angezeigt werden sollen. Er verwendet Buchstabencodes, wobei die Anzahl der Wiederholungen die Breite der Ausgabe beeinflusst: +Der Parameter `format` beschreibt, welche Zeitkomponenten angezeigt werden sollen. Es verwendet Buchstabencodes dafür, deren Wiederholungsanzahl die Breite der Ausgabe beeinflusst: | Jahr | `y` / `yy` / `yyyy` | `2024` / `24` / `2024` | Monat | `M` / `MM` / `MMM` / `MMMM` | `8` / `08` / `Aug` / `August` -| Tag | `d` / `dd` / `E` / `EEEE` | `1` / `01` / `So` / `Sonntag` -| Stunde | `j` / `H` / `h` | bevorzugt / 24 Stunden / 12 Stunden -| Minute | `m` / `mm` | `5` / `05` (2-stellig, wenn mit Sekunden kombiniert) -| Sekunde | `s` / `ss` | `8` / `08` (2 Ziffern, wenn mit Minuten kombiniert) +| Tag | `d` / `dd` / `E` / `EEEE` | `1` / `01` / `So` / `Sonntag` +| Stunde | `j` / `H` / `h` | bevorzugt / 24-Stunden / 12-Stunden +| Minute | `m` / `mm` | `5` / `05` (2 Ziffern in Kombination mit Sekunden) +| Sekunde | `s` / `ss` | `8` / `08` (2 Ziffern in Kombination mit Minuten) -Die Reihenfolge der Codes im Format spielt keine Rolle, da die Reihenfolge der Komponenten entsprechend den Konventionen des jeweiligen Gebietsschemas angezeigt wird. Daher ist das Format ortsunabhängig. Zum Beispiel gibt das Format `yyyyMMMMd` im Gebietsschema `en_US` `April 15, 2024` aus, während es im Gebietsschema `cs_CZ` `15. dubna 2024` ausgibt: +Die Reihenfolge der Codes im Format spielt keine Rolle, da die Reihenfolge der Komponenten gemäß den Konventionen der Ländereinstellungen ausgegeben wird. Das Format ist also unabhängig davon. Zum Beispiel wird das Format `yyyyMMMMd` in der Umgebung `en_US` als `April 15, 2024` ausgegeben, während es in der Umgebung `de_DE` als `15. April 2024` ausgegeben wird: | locale: | de-DE | en_US |--- @@ -456,9 +456,9 @@ Die Reihenfolge der Codes im Format spielt keine Rolle, da die Reihenfolge der K | `format: 'hm'` | 5:54 PM | 5:54 PM -**b) Verwendung voreingestellter Stile** +**b) Verwendung vordefinierter Stile** -Die Parameter `date` und `time` bestimmen den Detaillierungsgrad der Datums- und Zeitanzeige. Sie können aus mehreren Stufen wählen: `full`, `long`, `medium`, `short`. Sie können nur das Datum, nur die Uhrzeit oder beides anzeigen lassen: +Die Parameter `date` und `time` bestimmen, wie detailliert Datum und Uhrzeit ausgegeben werden sollen. Sie können aus mehreren Ebenen wählen: `full`, `long`, `medium`, `short`. Es ist möglich, nur das Datum, nur die Uhrzeit oder beides ausgeben zu lassen: | locale: | de-DE | en_US |--- @@ -473,52 +473,52 @@ Die Parameter `date` und `time` bestimmen den Detaillierungsgrad der Datums- und | `date: medium, time: short` | 23.01.1978, 08:30 | Jan 23, 1978, 8:30 AM | `date: long, time: short` | 23. Januar 1978 um 08:30 | January 23, 1978 at 8:30 AM -Für das Datum können Sie auch das Präfix `relative-` verwenden (z. B. `relative-short`), das für Daten, die kurz vor der Gegenwart liegen, `yesterday`, `today` oder `tomorrow` anzeigt; andernfalls erfolgt die Anzeige auf die übliche Weise. +Für das Datum können Sie außerdem das Präfix `relative-` verwenden (z.B. `relative-short`), das für Daten nahe der Gegenwart `gestern`, `heute` oder `morgen` anzeigt, andernfalls wird es auf die Standardweise ausgegeben. ```latte -{$date|localDate: date: relative-short} {* yesterday *} +{$date|localDate: date: relative-short} {* gestern *} ``` -Siehe auch [Datum |#date]. +Siehe auch [#date]. lower .[filter] --------------- -Konvertiert einen Wert in Kleinbuchstaben. Erfordert die PHP-Erweiterung `mbstring`. +Konvertiert eine Zeichenkette in Kleinbuchstaben. Erfordert die PHP-Erweiterung `mbstring`. ```latte -{='LATTE'|lower} {* gibt 'latte' *} +{='LATTE'|lower} {* gibt 'latte' aus *} ``` -Siehe auch [capitalize |#capitalize], [firstUpper |#firstUpper], [upper |#upper]. +Siehe auch [#capitalize], [#firstUpper], [#upper]. nocheck .[filter] ----------------- -Verhindert die automatische URL-Sanitization. Latte [prüft automatisch |safety-first#Link checking], ob die Variable eine Web-URL enthält (d.h. HTTP/HTTPS-Protokoll) und verhindert das Schreiben von Links, die ein Sicherheitsrisiko darstellen könnten. +Verhindert die automatische Behandlung einer URL-Adresse. Latte [überprüft automatisch |safety-first#Link checking], ob die Variable eine Web-URL enthält (d.h. HTTP/HTTPS-Protokoll) und verhindert die Ausgabe von Links, die ein Sicherheitsrisiko darstellen können. -Wenn der Link ein anderes Schema verwendet, z. B. `javascript:` oder `data:`, und Sie sich des Inhalts sicher sind, können Sie die Prüfung über `|nocheck` deaktivieren. +Wenn der Link ein anderes Schema verwendet, z.B. `javascript:` oder `data:`, und Sie sich seines Inhalts sicher sind, können Sie die Überprüfung mit `|nocheck` deaktivieren. ```latte {var $link = 'javascript:window.close()'} -checked -unchecked +geprüft +ungeprüft ``` -Drucke: +Gibt aus: ```latte -checked -unchecked +geprüft +ungeprüft ``` -Siehe auch [checkUrl |#checkUrl]. +Siehe auch [#checkUrl]. noescape .[filter] ------------------ -Deaktiviert das automatische Escaping. +Deaktiviert automatisches Escaping. ```latte {var $trustedHtmlString = 'hello'} @@ -526,7 +526,7 @@ Escaped: {$trustedHtmlString} Unescaped: {$trustedHtmlString|noescape} ``` -Druckt: +Gibt aus: ```latte Escaped: <b>hello</b> @@ -534,33 +534,33 @@ Unescaped: hello ``` .[warning] -Die missbräuchliche Verwendung des `noescape` Filters kann zu einer XSS-Schwachstelle führen! Verwenden Sie ihn nur, wenn Sie **absolut sicher** sind, was Sie tun und dass die Zeichenfolge, die Sie drucken, aus einer vertrauenswürdigen Quelle stammt. +Falsche Verwendung des `noescape`-Filters kann zu XSS-Schwachstellen führen! Verwenden Sie ihn niemals, wenn Sie nicht **absolut sicher** sind, was Sie tun, und dass die ausgegebene Zeichenkette aus einer vertrauenswürdigen Quelle stammt. number(int $decimals=0, string $decPoint='.', string $thousandsSep=',') .[filter] --------------------------------------------------------------------------------- -Formatiert eine Zahl mit einer bestimmten Anzahl von Dezimalstellen. Wenn das [Gebietsschema |develop#locale] festgelegt ist, werden die entsprechenden Dezimal- und Tausendertrennzeichen verwendet. +Formatiert eine Zahl auf eine bestimmte Anzahl von Dezimalstellen. Wenn [Ländereinstellungen |develop#locale] gesetzt sind, werden die entsprechenden Dezimal- und Tausendertrennzeichen verwendet. ```latte -{1234.20 |number} 1,234 -{1234.20 |number:1} 1,234.2 -{1234.20 |number:2} 1,234.20 -{1234.20 |number:2, ',', ' '} 1 234,20 +{1234.20|number} 1,234 +{1234.20|number:1} 1,234.2 +{1234.20|number:2} 1,234.20 +{1234.20|number:2, ',', ' '} 1 234,20 ``` number(string $format) .[filter] -------------------------------- -Mit dem Parameter `format` können Sie das Aussehen von Zahlen genau nach Ihren Bedürfnissen festlegen. Er erfordert ein festgelegtes [Gebietsschema |develop#locale]. Das Format besteht aus mehreren Sonderzeichen, deren vollständige Beschreibung in der Dokumentation "DecimalFormat":https://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns zu finden ist: +Der Parameter `format` ermöglicht es Ihnen, das Aussehen von Zahlen genau nach Ihren Bedürfnissen zu definieren. Dafür müssen [Ländereinstellungen |develop#locale] gesetzt sein. Das Format besteht aus mehreren speziellen Zeichen, deren vollständige Beschreibung Sie in der Dokumentation "DecimalFormat":https://unicode.org/reports/tr35/tr35-numbers.html#Number_Format_Patterns finden: -- obligatorische Ziffer, wird immer angezeigt, auch wenn sie Null ist -- `#` optionale Ziffer, wird nur angezeigt, wenn die Zahl eine Ziffer an dieser Stelle hat -- `@` signifikante Ziffer, hilft bei der Anzeige der Zahl mit einer bestimmten Anzahl signifikanter Ziffern -- `.` markiert die Stelle, an der das Dezimaltrennzeichen stehen soll (Komma oder Punkt, je nach Gebietsschema) -- `,` wird verwendet, um Gruppen von Ziffern zu trennen, normalerweise Tausender +- `0` obligatorische Ziffer, wird immer angezeigt, auch wenn es eine Null ist +- `#` optionale Ziffer, wird nur angezeigt, wenn an dieser Stelle tatsächlich eine Zahl steht +- `@` signifikante Ziffer, hilft, eine Zahl mit einer bestimmten Anzahl gültiger Ziffern anzuzeigen +- `.` kennzeichnet, wo das Dezimalkomma (oder -punkt, je nach Land) sein soll +- `,` dient zur Trennung von Zifferngruppen, meist Tausender - `%` multipliziert die Zahl mit 100 und fügt das Prozentzeichen hinzu -Schauen wir uns einige Beispiele an. Im ersten Beispiel sind zwei Dezimalstellen obligatorisch, im zweiten sind sie optional. Das dritte Beispiel zeigt Auffüllungen mit Nullen auf beiden Seiten, und das vierte Beispiel zeigt nur die vorhandenen Ziffern an: +Schauen wir uns einige Beispiele an. Im ersten Beispiel sind zwei Dezimalstellen obligatorisch, im zweiten optional. Das dritte Beispiel zeigt das Auffüllen mit Nullen links und rechts, das vierte zeigt nur existierende Ziffern: ```latte {1234.5|number: '#,##0.00'} {* 1,234.50 *} @@ -569,7 +569,7 @@ Schauen wir uns einige Beispiele an. Im ersten Beispiel sind zwei Dezimalstellen {1.2 |number: '##.##'} {* 1.2 *} ``` -Signifikante Ziffern legen fest, wie viele Ziffern, unabhängig vom Dezimalpunkt, angezeigt werden sollen, wobei die Zahl gegebenenfalls gerundet wird: +Signifikante Ziffern bestimmen, wie viele Ziffern unabhängig vom Dezimalpunkt angezeigt werden sollen, wobei gerundet wird: ```latte {1234|number: '@@'} {* 1200 *} @@ -579,13 +579,13 @@ Signifikante Ziffern legen fest, wie viele Ziffern, unabhängig vom Dezimalpunkt {0.00123|number: '@@'} {* 0.0012 *} ``` -Eine einfache Möglichkeit, eine Zahl als Prozentsatz anzuzeigen. Die Zahl wird mit 100 multipliziert und das Zeichen `%` wird hinzugefügt: +Ein einfacher Weg, eine Zahl als Prozentsatz anzuzeigen. Die Zahl wird mit 100 multipliziert und das `%`-Zeichen wird hinzugefügt: ```latte {0.1234|number: '#.##%'} {* 12.34% *} ``` -Wir können ein unterschiedliches Format für positive und negative Zahlen definieren, die durch ein `;` Zeichen getrennt sind. Auf diese Weise können z. B. positive Zahlen mit einem `+` -Zeichen angezeigt werden: +Wir können unterschiedliche Formate für positive und negative Zahlen definieren, getrennt durch ein `;`-Zeichen. Auf diese Weise können wir zum Beispiel festlegen, dass positive Zahlen mit einem `+`-Zeichen angezeigt werden sollen: ```latte {42|number: '#.##;(#.##)'} {* 42 *} @@ -594,140 +594,140 @@ Wir können ein unterschiedliches Format für positive und negative Zahlen defin {-42|number: '+#.##;-#.##'} {* -42 *} ``` -Denken Sie daran, dass das tatsächliche Aussehen von Zahlen je nach den Einstellungen des Gebietsschemas variieren kann. In einigen Ländern wird zum Beispiel ein Komma anstelle eines Punktes als Dezimaltrennzeichen verwendet. Dieser Filter berücksichtigt dies automatisch, so dass Sie sich darüber keine Gedanken machen müssen. +Beachten Sie, dass das tatsächliche Aussehen der Zahlen je nach den Ländereinstellungen variieren kann. In einigen Ländern wird beispielsweise ein Komma statt eines Punkts als Dezimaltrennzeichen verwendet. Dieser Filter berücksichtigt dies automatisch, und Sie müssen sich um nichts kümmern. padLeft(int $length, string $pad=' ') .[filter] ----------------------------------------------- -Füllt eine Zeichenkette bis zu einer bestimmten Länge mit einer anderen Zeichenkette von links auf. +Füllt eine Zeichenkette auf eine bestimmte Länge mit einer anderen Zeichenkette von links auf. ```latte -{='hello'|padLeft: 10, '123'} {* gibt '12312hello' *} +{='hello'|padLeft: 10, '123'} {* gibt '12312hello' aus *} ``` padRight(int $length, string $pad=' ') .[filter] ------------------------------------------------ -Füllt eine Zeichenfolge auf eine bestimmte Länge mit einer anderen Zeichenfolge von rechts. +Füllt eine Zeichenkette auf eine bestimmte Länge mit einer anderen Zeichenkette von rechts auf. ```latte -{='hello'|padRight: 10, '123'} {* gibt 'hello12312' *} +{='hello'|padRight: 10, '123'} {* gibt 'hello12312' aus *} ``` -query .[filter] ----------------- -Erzeugt dynamisch eine Abfragezeichenfolge in der URL: +query .[filter] +--------------- +Generiert dynamisch einen Query-String in einer URL: ```latte -click -search +klicken +suchen ``` -Druckt: +Gibt aus: ```latte -click -search +klicken +suchen ``` -Tasten mit einem Wert von `null` werden ausgelassen. +Schlüssel mit dem Wert `null` werden weggelassen. -Siehe auch [escapeUrl |#escapeUrl]. +Siehe auch [#escapeUrl]. random .[filter] ---------------- -Gibt ein zufälliges Element eines Arrays oder ein Zeichen einer Zeichenkette zurück: +Gibt ein zufälliges Element eines Arrays oder ein zufälliges Zeichen einer Zeichenkette zurück: ```latte -{=[1, 2, 3, 4]|random} {* example output: 3 *} -{='abcd'|random} {* example output: 'b' *} +{=[1, 2, 3, 4]|random} {* gibt z.B.: 3 aus *} +{='abcd'|random} {* gibt z.B.: 'b' aus *} ``` -Siehe auch [first |#first], [last |#last]. +Siehe auch [#first], [#last]. repeat(int $count) .[filter] ---------------------------- -Wiederholt die Zeichenkette x-mal. +Wiederholt eine Zeichenkette x-mal. ```latte -{='hello'|repeat: 3} {* gibt 'hellohellohello' *} +{='hello'|repeat: 3} {* gibt 'hellohellohello' aus *} ``` replace(string|array $search, string $replace='') .[filter] ----------------------------------------------------------- -Ersetzt alle Vorkommen der Suchzeichenfolge durch die Ersatzzeichenfolge. +Ersetzt alle Vorkommen der Suchzeichenkette durch die Ersatzzeichenkette. ```latte -{='hello world'|replace: 'world', 'friend'} {* gibt 'hello friend' *} +{='hello world'|replace: 'world', 'friend'} {* gibt 'hello friend' aus *} ``` -Es können mehrere Ersetzungen auf einmal vorgenommen werden: +Es können auch mehrere Ersetzungen auf einmal durchgeführt werden: ```latte -{='hello world'|replace: [h => l, l => h]} {* gibt 'lehho worhd' *} +{='hello world'|replace: [h => l, l => h]} {* gibt 'lehho worhd' aus *} ``` replaceRE(string $pattern, string $replace='') .[filter] -------------------------------------------------------- -Ersetzt alle Vorkommen entsprechend dem regulären Ausdruck. +Führt eine Suche und Ersetzung mit regulären Ausdrücken durch. ```latte -{='hello world'|replaceRE: '/l.*/', 'l'} {* gibt 'hel' *} +{='hello world'|replaceRE: '/l.*/', 'l'} {* gibt 'hel' aus *} ``` reverse .[filter] ----------------- -Kehrt eine gegebene Zeichenkette oder ein gegebenes Array um. +Kehrt die gegebene Zeichenkette oder das Array um. ```latte {var $s = 'Nette'} -{$s|reverse} {* gibt 'etteN' *} +{$s|reverse} {* gibt 'etteN' aus *} {var $a = ['N', 'e', 't', 't', 'e']} -{$a|reverse} {* liefert ['e', 't', 't', 'e', 'N'] *} +{$a|reverse} {* gibt ['e', 't', 't', 'e', 'N'] zurück *} ``` round(int $precision=0) .[filter] --------------------------------- -Rundet eine Zahl auf eine bestimmte Genauigkeit. +Rundet eine Zahl auf die angegebene Genauigkeit. ```latte -{=3.4|round} {* gibt 3 *} -{=3.5|round} {* gibt 4 *} -{=135.79|round:1} {* gibt 135.8 *} -{=135.79|round:3} {* gibt 135.79 *} +{=3.4|round} {* gibt 3 aus *} +{=3.5|round} {* gibt 4 aus *} +{=135.79|round:1} {* gibt 135.8 aus *} +{=135.79|round:3} {* gibt 135.79 aus *} ``` -Siehe auch [ceil |#ceil], [floor |#floor]. +Siehe auch [#ceil], [#floor]. slice(int $start, ?int $length=null, bool $preserveKeys=false) .[filter] ------------------------------------------------------------------------ -Extrahiert einen Ausschnitt aus einem Array oder einer Zeichenkette. +Extrahiert einen Teil eines Arrays oder einer Zeichenkette. ```latte -{='hello'|slice: 1, 2} {* gibt 'el' *} -{=['a', 'b', 'c']|slice: 1, 2} {* gibt ['b', 'c'] *} +{='hello'|slice: 1, 2} {* gibt 'el' aus *} +{=['a', 'b', 'c']|slice: 1, 2} {* gibt ['b', 'c'] aus *} ``` -Der Slice-Filter funktioniert wie die PHP-Funktion `array_slice` für Arrays und `mb_substr` für Strings mit einem Fallback auf `iconv_substr` im UTF-8-Modus. +Der Filter funktioniert wie die PHP-Funktion `array_slice` für Arrays oder `mb_substr` für Zeichenketten mit Fallback auf die Funktion `iconv_substr` im UTF-8-Modus. -Wenn start nicht negativ ist, beginnt die Sequenz an diesem Anfang in der Variablen. Wenn start negativ ist, beginnt die Sequenz so weit vom Ende der Variablen entfernt. +Wenn start positiv ist, beginnt die Sequenz um diese Anzahl vom Anfang des Arrays/der Zeichenkette verschoben. Wenn es negativ ist, beginnt die Sequenz um diese Anzahl vom Ende verschoben. -Wenn length angegeben wird und positiv ist, wird die Sequenz bis zu dieser Anzahl von Elementen enthalten. Wenn die Variable kürzer als die Länge ist, werden nur die verfügbaren Elemente der Variablen angezeigt. Wenn length angegeben wird und negativ ist, endet die Sequenz so viele Elemente vor dem Ende der Variablen. Wird sie weggelassen, enthält die Sequenz alle Elemente vom Offset bis zum Ende der Variablen. +Wenn der Parameter length angegeben und positiv ist, enthält die Sequenz so viele Elemente. Wenn ein negativer length-Parameter an diese Funktion übergeben wird, enthält die Sequenz alle Elemente des ursprünglichen Arrays, beginnend an der Position start und endend an der Position, die um length Elemente vom Ende des Arrays entfernt ist. Wenn Sie diesen Parameter weglassen, enthält die Sequenz alle Elemente des ursprünglichen Arrays, beginnend an der Position start. -Filter ordnet die Schlüssel des Integer-Arrays standardmäßig neu an und setzt sie zurück. Dieses Verhalten kann geändert werden, indem preserveKeys auf true gesetzt wird. String-Schlüssel werden immer beibehalten, unabhängig von diesem Parameter. +Standardmäßig ändert der Filter die Reihenfolge und setzt die ganzzahligen Schlüssel des Arrays zurück. Dieses Verhalten kann geändert werden, indem preserveKeys auf true gesetzt wird. String-Schlüssel werden immer beibehalten, unabhängig von diesem Parameter. sort(?Closure $comparison, string|int|\Closure|null $by=null, string|int|\Closure|bool $byKey=false) .[filter] -------------------------------------------------------------------------------------------------------------- -Der Filter sortiert Elemente eines Arrays oder Iterators unter Beibehaltung ihrer assoziativen Schlüssel. Wenn ein [Gebietsschema |develop#locale] festgelegt ist, folgt die Sortierung dessen Regeln, es sei denn, eine benutzerdefinierte Vergleichsfunktion ist angegeben. +Der Filter sortiert die Elemente eines Arrays oder Iterators und behält ihre assoziativen Schlüssel bei. Bei gesetzten [Ländereinstellungen |develop#locale] folgt die Sortierung deren Regeln, wenn keine eigene Vergleichsfunktion angegeben ist. ```latte {foreach ($names|sort) as $name} @@ -735,7 +735,7 @@ Der Filter sortiert Elemente eines Arrays oder Iterators unter Beibehaltung ihre {/foreach} ``` -Array in umgekehrter Reihenfolge sortiert. +Sortiertes Array in umgekehrter Reihenfolge: ```latte {foreach ($names|sort|reverse) as $name} @@ -743,13 +743,13 @@ Array in umgekehrter Reihenfolge sortiert. {/foreach} ``` -Sie können eine benutzerdefinierte Vergleichsfunktion für die Sortierung angeben (das Beispiel zeigt, wie Sie die Sortierung von der größten zur kleinsten umkehren können): +Sie können eine eigene Vergleichsfunktion für die Sortierung angeben (das Beispiel zeigt, wie die Sortierung von größter zu kleinster umgekehrt wird): ```latte {var $reverted = ($names|sort: fn($a, $b) => $b <=> $a)} ``` -Mit dem Filter `|sort` können Sie auch Elemente nach Schlüssel sortieren: +Der Filter `|sort` ermöglicht auch die Sortierung von Elementen nach Schlüsseln: ```latte {foreach ($names|sort: byKey: true) as $name} @@ -757,7 +757,7 @@ Mit dem Filter `|sort` können Sie auch Elemente nach Schlüssel sortieren: {/foreach} ``` -Wenn Sie eine Tabelle nach einer bestimmten Spalte sortieren müssen, können Sie den Parameter `by` verwenden. Der Wert `'name'` im Beispiel gibt an, dass die Sortierung nach `$row->name` oder `$row['name']`erfolgt, je nachdem, ob `$row` ein Array oder ein Objekt ist: +Wenn Sie eine Tabelle nach einer bestimmten Spalte sortieren müssen, können Sie den Parameter `by` verwenden. Der Wert `'name'` im Beispiel gibt an, dass nach `$item->name` oder `$item['name']` sortiert wird, je nachdem, ob `$item` ein Array oder ein Objekt ist: ```latte {foreach ($items|sort: by: 'name') as $item} @@ -765,7 +765,7 @@ Wenn Sie eine Tabelle nach einer bestimmten Spalte sortieren müssen, können Si {/foreach} ``` -Sie können auch eine Callback-Funktion definieren, die den Wert bestimmt, nach dem sortiert wird: +Sie können auch eine Callback-Funktion definieren, die den Wert bestimmt, nach dem sortiert werden soll: ```latte {foreach ($items|sort: by: fn($items) => $items->category->name) as $item} @@ -773,12 +773,12 @@ Sie können auch eine Callback-Funktion definieren, die den Wert bestimmt, nach {/foreach} ``` -Der Parameter `byKey` kann auf dieselbe Weise verwendet werden. +Der Parameter `byKey` kann auf die gleiche Weise verwendet werden. -spaceless .[filter] --------------------- -Entfernt unnötige Leerzeichen aus der Ausgabe. Sie können auch den Alias `strip` verwenden. +spaceless .[filter] +------------------- +Entfernt überflüssige Leerzeichen aus der Ausgabe. Sie können auch den Alias `strip` verwenden. ```latte {block |spaceless} @@ -788,7 +788,7 @@ Entfernt unnötige Leerzeichen aus der Ausgabe. Sie können auch den Alias `stri {/block} ``` -Druckt: +Gibt aus: ```latte
  • Hello
@@ -797,18 +797,18 @@ Druckt: stripHtml .[filter] ------------------- -Konvertiert HTML in einfachen Text. Das heißt, es werden HTML-Tags entfernt und HTML-Elemente in Text umgewandelt. +Konvertiert HTML in reinen Text. Das heißt, es entfernt HTML-Tags und konvertiert HTML-Entities in Text. ```latte -{='

one < two

'|stripHtml} {* gibt 'one < two' *} +{='

one < two

'|stripHtml} {* gibt 'one < two' aus *} ``` -Der resultierende reine Text kann natürlich Zeichen enthalten, die HTML-Tags darstellen, zum Beispiel wird `'<p>'|stripHtml` in `

`. Geben Sie den resultierenden Text niemals mit `|noescape` aus, da dies zu einer Sicherheitslücke führen kann. +Der resultierende reine Text kann natürlich Zeichen enthalten, die HTML-Tags darstellen, zum Beispiel wird `'<p>'|stripHtml` zu `

` konvertiert. Geben Sie den so erzeugten Text auf keinen Fall mit `|noescape` aus, da dies zu einer Sicherheitslücke führen kann. substr(int $offset, ?int $length=null) .[filter] ------------------------------------------------ -Extrahiert einen Ausschnitt aus einer Zeichenkette. Dieser Filter wurde durch einen [Slice-Filter |#slice] ersetzt. +Extrahiert einen Teil einer Zeichenkette. Dieser Filter wurde durch den Filter [#slice] ersetzt. ```latte {$string|substr: 1, 2} @@ -817,57 +817,57 @@ Extrahiert einen Ausschnitt aus einer Zeichenkette. Dieser Filter wurde durch ei translate(string $message, ...$args) .[filter] ---------------------------------------------- -Er übersetzt Ausdrücke in andere Sprachen. Um den Filter verfügbar zu machen, müssen Sie den [Übersetzer ein richten|develop#TranslatorExtension]. Sie können auch die [Tags für die Übersetzung |tags#Translation] verwenden. +Übersetzt Ausdrücke in andere Sprachen. Damit der Filter verfügbar ist, muss ein [Übersetzer eingerichtet |develop#TranslatorExtension] sein. Sie können auch [Tags für Übersetzungen |tags#Translation] verwenden. ```latte -{='Baskter'|translate} +{='Cart'|translate} {$item|translate} ``` trim(string $charlist=" \t\n\r\0\x0B\u{A0}") .[filter] ------------------------------------------------------ -Entfernen Sie führende und nachgestellte Zeichen, standardmäßig Leerzeichen. +Entfernt Leerzeichen (oder andere Zeichen) vom Anfang und Ende einer Zeichenkette. ```latte -{=' I like Latte. '|trim} {* gibt 'I like Latte.' *} -{=' I like Latte.'|trim: '.'} {* gibt ' I like Latte' *} +{=' I like Latte. '|trim} {* gibt 'I like Latte.' aus *} +{=' I like Latte.'|trim: '.'} {* gibt ' I like Latte' aus *} ``` truncate(int $length, string $append='…') .[filter] --------------------------------------------------- -Kürzt eine Zeichenkette auf die maximal angegebene Länge, versucht aber, ganze Wörter zu erhalten. Wenn die Zeichenkette abgeschnitten ist, wird am Ende ein Auslassungszeichen hinzugefügt (dies kann durch den zweiten Parameter geändert werden). +Kürzt eine Zeichenkette auf die angegebene maximale Länge, wobei versucht wird, ganze Wörter zu erhalten. Wenn die Zeichenkette gekürzt wird, wird am Ende ein Auslassungszeichen hinzugefügt (kann mit dem zweiten Parameter geändert werden). ```latte {var $title = 'Hello, how are you?'} -{$title|truncate:5} {* Hell… *} -{$title|truncate:17} {* Hello, how are… *} -{$title|truncate:30} {* Hello, how are you? *} +{$title|truncate:5} {* Hell… *} +{$title|truncate:17} {* Hello, how are… *} +{$title|truncate:30} {* Hello, how are you? *} ``` upper .[filter] --------------- -Konvertiert einen Wert in Großbuchstaben. Erfordert die PHP-Erweiterung `mbstring`. +Konvertiert eine Zeichenkette in Großbuchstaben. Erfordert die PHP-Erweiterung `mbstring`. ```latte -{='latte'|upper} {* gibt 'LATTE' *} +{='latte'|upper} {* gibt 'LATTE' aus *} ``` -Siehe auch [capitalize |#capitalize], [firstUpper |#firstUpper], [lower |#lower]. +Siehe auch [#capitalize], [#firstUpper], [#lower]. webalize .[filter] ------------------ -Konvertiert nach ASCII. +Konvertiert eine UTF-8-Zeichenkette in die in URLs verwendete Form. -Konvertiert Leerzeichen in Bindestriche. Entfernt Zeichen, die keine alphanumerischen Zeichen, Unterstriche oder Bindestriche sind. Konvertiert in Kleinbuchstaben. Entfernt auch führende und nachfolgende Leerzeichen. +Es wird in ASCII konvertiert. Konvertiert Leerzeichen in Bindestriche. Entfernt Zeichen, die nicht alphanumerisch, Unterstriche oder Bindestriche sind. Konvertiert in Kleinbuchstaben. Entfernt auch führende und abschließende Leerzeichen. ```latte -{var $s = 'Our 10. product'} -{$s|webalize} {* gibt 'our-10-product' *} +{var $s = 'Unser 10. Produkt'} +{$s|webalize} {* gibt 'unser-10-produkt' aus *} ``` .[caution] -Erfordert das Paket [nette/utils |utils:]. +Erfordert die Bibliothek [nette/utils |utils:]. diff --git a/latte/de/tags.texy b/latte/de/tags.texy index c0ef1f3af7..23ecde451c 100644 --- a/latte/de/tags.texy +++ b/latte/de/tags.texy @@ -2,167 +2,167 @@ Latte Tags ********** .[perex] -Zusammenfassung und Beschreibung aller in Latte integrierten Tags. +Eine Übersicht und Beschreibung aller Latte-Template-System-Tags, die standardmäßig zur Verfügung stehen. .[table-latte-tags language-latte] -|## Drucken -| `{$var}`, `{...}` oder `{=...}` | [druckt eine Variable oder einen Ausdruck mit Escapezeichen |#printing] -| `{$var\|filter}` | [druckt mit Filtern |#filters] -| `{l}` oder `{r}` | druckt `{` or `}` Zeichen +|## Ausgabe +| `{$var}`, `{...}` oder `{=...}` | [gibt eine escaped Variable oder einen Ausdruck aus|#Ausgabe] +| `{$var\|filter}` | [gibt mit Verwendung von Filtern aus|#Filter] +| `{l}` oder `{r}` | gibt das Zeichen `{` oder `}` aus .[table-latte-tags language-latte] |## Bedingungen -| `{if}`... `{elseif}`... `{else}`... `{/if}` | [Bedingung if |#if-elseif-else] -| `{ifset}`... `{elseifset}`... `{/ifset}` | [Bedingung ifset |#ifset-elseifset] -| `{ifchanged}`... `{/ifchanged}` | [Test, ob eine Änderung stattgefunden hat |#ifchanged] -| `{switch}` `{case}` `{default}` `{/switch}` | [Bedingung switch |#switch-case-default] -| `n:else` | [alternative Inhalte für Bedingungen |#n:else] +| `{if}` … `{elseif}` … `{else}` … `{/if}` | [if-Bedingung|#if-elseif-else] +| `{ifset}` … `{elseifset}` … `{/ifset}` | [ifset-Bedingung|#ifset-elseifset] +| `{ifchanged}` … `{/ifchanged}` | [Test, ob eine Änderung aufgetreten ist|#ifchanged] +| `{switch}` `{case}` `{default}` `{/switch}` | [switch-Bedingung|#switch-case-default] +| `n:else` | [alternativer Inhalt für Bedingungen|#n:else] .[table-latte-tags language-latte] |## Schleifen -| `{foreach}`... `{/foreach}` | [foreach |#foreach] -| `{for}`... `{/for}` | [for |#for] -| `{while}`... `{/while}` | [while |#while] -| `{continueIf $cond}` | [weiter zur nächsten Iteration |#continueif-skipif-breakif] -| `{skipIf $cond}` | [überspringt die aktuelle Schleifeniteration |#continueif-skipif-breakif] -| `{breakIf $cond}` | [bricht Schleife ab |#continueif-skipif-breakif] -| `{exitIf $cond}` | [vorzeitiges Beenden |#exitif] -| `{first}`... `{/first}` | [ist dies die erste Iteration? |#first-last-sep] -| `{last}`... `{/last}` | [ist es die letzte Iteration? |#first-last-sep] -| `{sep}`... `{/sep}` | [wird die nächste Iteration folgen? |#first-last-sep] -| `{iterateWhile}`... `{/iterateWhile}` | [strukturiert foreach |#iterateWhile] -| `$iterator` | [Spezielle Variable innerhalb der foreach-Schleife |#$iterator] +| `{foreach}` … `{/foreach}` | [#foreach] +| `{for}` … `{/for}` | [#for] +| `{while}` … `{/while}` | [#while] +| `{continueIf $cond}` | [mit der nächsten Iteration fortfahren|#continueif-skipif-breakif] +| `{skipIf $cond}` | [Iteration überspringen|#continueif-skipif-breakif] +| `{breakIf $cond}` | [Schleife abbrechen|#continueif-skipif-breakif] +| `{exitIf $cond}` | [vorzeitige Beendigung|#exitif] +| `{first}` … `{/first}` | [ist es der erste Durchlauf?|#first-last-sep] +| `{last}` … `{/last}` | [ist es der letzte Durchlauf?|#first-last-sep] +| `{sep}` … `{/sep}` | [wird noch ein Durchlauf folgen?|#first-last-sep] +| `{iterateWhile}` … `{/iterateWhile}` | [strukturiertes foreach|#iterateWhile] +| `$iterator` | [spezielle Variable innerhalb von foreach|#$iterator] .[table-latte-tags language-latte] -|## Einbindung anderer Vorlagen -| `{include 'file.latte'}` | [schließt eine Vorlage aus einer anderen Datei ein |#include] -| `{sandbox 'file.latte'}` | [Einfügen einer Vorlage im Sandbox-Modus |#sandbox] +|## Einbindung weiterer Templates +| `{include 'file.latte'}` | [lädt ein Template aus einer anderen Datei|#include] +| `{sandbox 'file.latte'}` | [lädt ein Template im Sandbox-Modus|#sandbox] .[table-latte-tags language-latte] -|## Blöcke, Layouts, Vererbung von Vorlagen -| `{block}` | [anonymer Block |#block] -| `{block blockname}` | [Blockdefinition |template-inheritance#blocks] -| `{define blockname}` | [Blockdefinition für zukünftige Verwendung |template-inheritance#definitions] -| `{include blockname}` | [druckt Block |template-inheritance#printing-blocks] -| `{include blockname from 'file.latte'}` | [druckt einen Block aus einer Datei |template-inheritance#printing-blocks] -| `{import 'file.latte'}` | [lädt Blöcke aus einer anderen Vorlage |template-inheritance#horizontal-reuse] -| `{layout 'file.latte'}` / `{extends}` | [gibt eine Layout-Datei an |template-inheritance#layout-inheritance] -| `{embed}`... `{/embed}` | [lädt die Vorlage oder den Block und ermöglicht das Überschreiben der Blöcke |template-inheritance#unit-inheritance] -| `{ifset blockname}`... `{/ifset}` | [Bedingung, wenn Block definiert ist |template-inheritance#checking-block-existence] +|## Blöcke, Layouts, Template-Vererbung +| `{block}` | [anonymer Block|#block] +| `{block blockname}` | [definiert einen Block|template-inheritance#blocks] +| `{define blockname}` | [definiert einen Block zur späteren Verwendung|template-inheritance#definitions] +| `{include blockname}` | [Darstellung eines Blocks|template-inheritance#printing-blocks] +| `{include blockname from 'file.latte'}` | [stellt einen Block aus einer Datei dar|template-inheritance#printing-blocks] +| `{import 'file.latte'}` | [lädt Blöcke aus einem Template|template-inheritance#horizontal-reuse] +| `{layout 'file.latte'}` / `{extends}` | [bestimmt die Layout-Datei|template-inheritance#layout-inheritance] +| `{embed}` … `{/embed}` | [lädt ein Template oder einen Block und ermöglicht das Überschreiben von Blöcken|template-inheritance#unit-inheritance] +| `{ifset blockname}` … `{/ifset}` | [Bedingung, ob ein Block existiert|template-inheritance#checking-block-existence] .[table-latte-tags language-latte] |## Ausnahmebehandlung -| `{try}`... `{else}`... `{/try}` | [Abfangen von Ausnahmen |#try] -| `{rollback}` | [verwirft try-Block |#rollback] +| `{try}` … `{else}` … `{/try}` | [Abfangen von Ausnahmen|#try] +| `{rollback}` | [Verwerfen eines try-Blocks|#rollback] .[table-latte-tags language-latte] |## Variablen -| `{var $foo = value}` | [Erstellung von Variablen |#var-default] -| `{default $foo = value}` | [Standardwert, wenn Variable nicht deklariert ist |#var-default] -| `{parameters}` | [deklariert Variablen, gibt einen Standardwert ein |#parameters] -| `{capture}`... `{/capture}` | [erfasst einen Abschnitt in einer Variablen |#capture] +| `{var $foo = value}` | [erstellt eine Variable|#var-default] +| `{default $foo = value}` | [erstellt eine Variable, wenn sie nicht existiert|#var-default] +| `{parameters}` | [deklariert Variablen, Typen und Standardwerte|#parameters] +| `{capture}` … `{/capture}` | [erfasst einen Block in eine Variable|#capture] .[table-latte-tags language-latte] |## Typen -| `{varType}` | [deklariert den Typ einer Variablen |type-system#varType] -| `{varPrint}` | [schlägt Variablentypen vor |type-system#varPrint] -| `{templateType}` | [deklariert Variablentypen mittels Klasse |type-system#templateType] -| `{templatePrint}` | [erzeugt Klasse mit Eigenschaften |type-system#templatePrint] +| `{varType}` | [deklariert den Typ einer Variable|type-system#varType] +| `{varPrint}` | [schlägt Typen für Variablen vor|type-system#varPrint] +| `{templateType}` | [deklariert Variablentypen basierend auf einer Klasse|type-system#templateType] +| `{templatePrint}` | [schlägt eine Klasse mit Variablentypen vor|type-system#templatePrint] .[table-latte-tags language-latte] -|## Übersetzung -| `{_string}` | [druckt übersetzt |#Translation] -| `{translate}`... `{/translate}` | [übersetzt den Inhalt |#Translation] +|## Übersetzungen +| `{_...}` | [gibt eine Übersetzung aus|#übersetzungen] +| `{translate}` … `{/translate}` | [übersetzt den Inhalt|#übersetzungen] .[table-latte-tags language-latte] -|## Andere -| `{contentType}` | [schaltet den Escaping-Modus um und sendet HTTP-Header |#contenttype] -| `{debugbreak}` | [setzt einen Haltepunkt im Code |#debugbreak] -| `{do}` | [wertet einen Ausdruck aus, ohne ihn zu drucken |#do] -| `{dump}` | [gibt Variablen in die Tracy Bar aus |#dump] -| `{php}` | [führt beliebigen PHP-Code aus |#php] -| `{spaceless}`... `{/spaceless}` | [entfernt unnötige Leerzeichen |#spaceless] -| `{syntax}` | [schaltet die Syntax während der Laufzeit um |#syntax] -| `{trace}` | [zeigt Stack-Trace |#trace] +|## Sonstiges +| `{contentType}` | [schaltet das Escaping um und sendet einen HTTP-Header|#contenttype] +| `{debugbreak}` | [platziert einen Breakpoint im Code|#debugbreak] +| `{do}` | [führt Code aus, gibt aber nichts aus|#do] +| `{dump}` | [dumpt Variablen in die Tracy Bar|#dump] +| `{php}` | [führt beliebigen PHP-Code aus|#php] +| `{spaceless}` … `{/spaceless}` | [entfernt überflüssige Leerzeichen|#spaceless] +| `{syntax}` | [Änderung der Syntax zur Laufzeit|#syntax] +| `{trace}` | [zeigt den Stack-Trace an|#trace] .[table-latte-tags language-latte] -|## HTML-Tag-Helfer -| `n:class` | [intelligentes Klassenattribut |#n:class] -| `n:attr` | [intelligente HTML-Attribute |#n:attr] -| `n:tag` | [Dynamischer Name des HTML-Elements |#n:tag] -| `n:ifcontent` | [Leeren HTML-Tag auslassen |#n:ifcontent] +|## Helfer für HTML-Codierer +| `n:class` | [dynamische Schreibweise des HTML-Attributs class|#n:class] +| `n:attr` | [dynamische Schreibweise beliebiger HTML-Attribute|#n:attr] +| `n:tag` | [dynamische Schreibweise des HTML-Element-Namens|#n:tag] +| `n:ifcontent` | [lässt einen leeren HTML-Tag aus|#n:ifcontent] .[table-latte-tags language-latte] -|## Nur in Nette Framework verfügbar -| `n:href` | [Link in `` HTML-Elementen |application:creating-links#In the Presenter Template] -| `{link}` | [gibt einen Link aus |application:creating-links#In the Presenter Template] -| `{plink}` | [druckt einen Link zu einem Presenter |application:creating-links#In the Presenter Template] -| `{control}` | [druckt eine Komponente |application:components#Rendering] -| `{snippet}`... `{/snippet}` | [ein Template-Snippet, das per AJAX gesendet werden kann |application:ajax#snippets-in-latte] -| `{snippetArea}` | [Schnipsel Umschlag |application:ajax#snippet-areas] -| `{cache}`... `{/cache}` | [zwischenspeichert einen Vorlagenabschnitt |caching:#caching-in-latte] +|## Nur im Nette Framework verfügbar +| `n:href` | [Link, der in HTML-Elementen `` verwendet wird|application:creating-links#In the Presenter Template] +| `{link}` | [gibt einen Link aus|application:creating-links#In the Presenter Template] +| `{plink}` | [gibt einen Link zu einem Presenter aus|application:creating-links#In the Presenter Template] +| `{control}` | [rendert eine Komponente|application:components#Rendering] +| `{snippet}` … `{/snippet}` | [ein Snippet, das per AJAX gesendet werden kann|application:ajax#snippets-in-latte] +| `{snippetArea}` | [Wrapper für Snippets|application:ajax#snippet-areas] +| `{cache}` … `{/cache}` | [cached einen Teil des Templates|caching:#caching-in-latte] .[table-latte-tags language-latte] |## Nur mit Nette Forms verfügbar -| `{form}`... `{/form}` | [druckt ein Formularelement |forms:rendering#form] -| `{label}`... `{/label}` | [druckt eine Formulareingabebezeichnung |forms:rendering#label-input] -| `{input}` | [druckt ein Formulareingabeelement |forms:rendering#label-input] -| `{inputError}` | [gibt eine Fehlermeldung für ein Formulareingabeelement aus |forms:rendering#inputError] -| `n:name` | [aktiviert ein HTML-Eingabeelement |forms:rendering#n:name] -| `{formContainer}`... `{/formContainer}` | [Darstellung des Formular-Containers |forms:rendering#special-cases] +| `{form}` … `{/form}` | [rendert Formular-Tags|forms:rendering#form] +| `{label}` … `{/label}` | [rendert ein Label für ein Formularelement|forms:rendering#label-input] +| `{input}` | [rendert ein Formularelement|forms:rendering#label-input] +| `{inputError}` | [gibt eine Fehlermeldung für ein Formularelement aus|forms:rendering#inputError] +| `n:name` | [aktiviert ein Formularelement|forms:rendering#n:name] +| `{formContainer}` … `{/formContainer}` | [Zeichnen eines Formular-Containers|forms:rendering#special-cases] -Drucken .[#toc-printing] +Ausgabe .[#toc-printing] ======================== `{$var}` `{...}` `{=...}` ------------------------- -Latte verwendet das Tag `{=...}`, um einen beliebigen Ausdruck in der Ausgabe auszugeben. Wenn der Ausdruck mit einer Variablen oder einem Funktionsaufruf beginnt, ist es nicht nötig, ein Gleichheitszeichen zu schreiben. Das bedeutet in der Praxis, dass es fast nie geschrieben werden muss: +In Latte wird das Tag `{=...}` verwendet, um einen beliebigen Ausdruck auszugeben. Latte legt Wert auf Ihren Komfort, daher ist es nicht nötig, das Gleichheitszeichen zu schreiben, wenn der Ausdruck mit einer Variable oder einem Funktionsaufruf beginnt. Das bedeutet in der Praxis, dass es fast nie notwendig ist, es zu schreiben: ```latte Name: {$name} {$surname}
-Age: {date('Y') - $birth}
+Alter: {date('Y') - $birth}
``` -Sie können alles, was Sie aus PHP kennen, als Ausdruck schreiben. Sie müssen nur keine neue Sprache lernen. Zum Beispiel: +Als Ausdruck können Sie alles schreiben, was Sie aus PHP kennen. Sie müssen einfach keine neue Sprache lernen. Zum Beispiel: ```latte {='0' . ($num ?? $num * 3) . ', ' . PHP_VERSION} ``` -Bitte suchen Sie nicht nach einer Bedeutung in dem vorherigen Beispiel, aber wenn Sie eine finden, schreiben Sie uns :-) +Bitte suchen Sie in dem vorherigen Beispiel keinen Sinn, aber wenn Sie einen finden sollten, schreiben Sie uns :-) -Ausweichende Ausgabe .[#toc-escaping-output] --------------------------------------------- +Ausgabe escapen .[#toc-escaping-output] +--------------------------------------- -Was ist die wichtigste Aufgabe eines Template-Systems? Sicherheitslücken zu vermeiden. Und genau das tut Latte, wenn Sie etwas in die Ausgabe drucken. Es entschlüsselt automatisch alles: +Was ist die wichtigste Aufgabe eines Template-Systems? Sicherheitslücken zu verhindern. Und genau das macht Latte immer, wenn Sie etwas ausgeben. Es escaped es automatisch: ```latte -

{='one < two'}

{* prints: '

one < two

' *} +

{='one < two'}

{* gibt aus: '

one < two

' *} ``` -Um genau zu sein, verwendet Latte kontextabhängiges Escaping, eine so wichtige und einzigartige Funktion dass wir ihr [ein eigenes Kapitel |safety-first#context-aware-escaping] gewidmet haben. +Um genau zu sein, verwendet Latte kontextsensitives Escaping, was so wichtig und einzigartig ist, dass wir ihm [ein eigenes Kapitel|safety-first#context-aware-escaping] gewidmet haben. -Und wenn Sie HTML-codierte Inhalte aus einer vertrauenswürdigen Quelle drucken? Dann können Sie das Escaping einfach abschalten: +Und was ist, wenn Sie HTML-codierten Inhalt aus einer vertrauenswürdigen Quelle ausgeben? Dann kann das Escaping einfach deaktiviert werden: ```latte {$trustedHtmlString|noescape} ``` .[warning] -Der Missbrauch des `noescape`-Filters kann zu einer XSS-Schwachstelle führen! Verwenden Sie ihn nur, wenn Sie **absolut sicher** sind, was Sie tun und dass die Zeichenfolge, die Sie ausgeben, aus einer vertrauenswürdigen Quelle stammt. +Eine falsche Verwendung des `noescape`-Filters kann zu einer XSS-Schwachstelle führen! Verwenden Sie ihn niemals, wenn Sie sich nicht **absolut sicher** sind, was Sie tun, und dass die ausgegebene Zeichenkette aus einer vertrauenswürdigen Quelle stammt. -Drucken in JavaScript .[#toc-printing-in-javascript] +Ausgabe in JavaScript .[#toc-printing-in-javascript] ---------------------------------------------------- -Dank der kontextsensitiven Escape-Funktion ist es wunderbar einfach, Variablen innerhalb von JavaScript zu drucken, und Latte wird sie korrekt escapen. +Dank des kontextsensitiven Escapings ist es wunderbar einfach, Variablen innerhalb von JavaScript auszugeben, und Latte kümmert sich um das korrekte Escaping. -Die Variable muss keine Zeichenkette sein, es wird jeder Datentyp unterstützt, der dann als JSON kodiert wird: +Die Variable muss nicht unbedingt ein String sein, es wird jeder Datentyp unterstützt, der dann als JSON kodiert wird: ```latte {var $foo = ['hello', true, 1]} @@ -179,7 +179,7 @@ Erzeugt: ``` -Dies ist auch der Grund, warum **Variablen nicht in Anführungszeichen** gesetzt werden sollten: Latte fügt sie um Strings herum ein. Und wenn Sie eine String-Variable in einen anderen String einfügen wollen, verketten Sie sie einfach: +Das ist auch der Grund, warum **keine Anführungszeichen** um die Variable geschrieben werden: Latte fügt sie bei Strings selbst hinzu. Und wenn Sie eine String-Variable in einen anderen String einfügen möchten, verbinden Sie sie einfach: ```latte ``` @@ -195,13 +195,13 @@ Dies ist auch der Grund, warum **Variablen nicht in Anführungszeichen** gesetzt Filter .[#toc-filters] ---------------------- -Der gedruckte Ausdruck kann [durch Filter |syntax#filters] verändert werden. In diesem Beispiel wird die Zeichenkette beispielsweise in Großbuchstaben umgewandelt und auf maximal 30 Zeichen gekürzt: +Der ausgegebene Ausdruck kann durch einen [Filter|syntax#filters] modifiziert werden. So können wir zum Beispiel eine Zeichenkette in Großbuchstaben umwandeln und auf maximal 30 Zeichen kürzen: ```latte {$string|upper|truncate:30} ``` -Sie können auch Filter auf Teile eines Ausdrucks anwenden, wie folgt: +Filter können auch auf Teile eines Ausdrucks auf folgende Weise angewendet werden: ```latte {$left . ($middle|upper) . $right} @@ -215,60 +215,60 @@ Bedingungen .[#toc-conditions] `{if}` `{elseif}` `{else}` -------------------------- -Bedingungen verhalten sich genauso wie die entsprechenden PHP-Ausdrücke. Sie können die gleichen Ausdrücke verwenden, die Sie aus PHP kennen, Sie müssen keine neue Sprache lernen. +Bedingungen verhalten sich genauso wie ihre Pendants in PHP. Sie können in ihnen die gleichen Ausdrücke verwenden, die Sie aus PHP kennen, Sie müssen keine neue Sprache lernen. ```latte {if $product->inStock > Stock::Minimum} - In stock + Auf Lager {elseif $product->isOnWay()} - On the way + Unterwegs {else} - Not available + Nicht verfügbar {/if} ``` -Wie jedes Paar-Tag kann ein Paar von `{if} ... {/ if}` zum Beispiel als [n:attribute |syntax#n:attributes] geschrieben werden: +Wie jedes Paar-Tag kann auch das Paar `{if} ... {/if}` in Form eines [n:Attributs|syntax#n:attributes] geschrieben werden, zum Beispiel: ```latte -

In stock {$count} items

+

{$count} Artikel auf Lager

``` -Wussten Sie, dass Sie das Präfix `tag-` zu n:Attributen hinzufügen können? Dann wirkt sich die Bedingung nur auf die HTML-Tags aus und der Inhalt zwischen ihnen wird immer gedruckt: +Wussten Sie, dass Sie n:Attribute mit dem Präfix `tag-` versehen können? Dann bezieht sich die Bedingung nur auf die Ausgabe der HTML-Tags, und der Inhalt dazwischen wird immer ausgegeben: ```latte
Hello -{* prints 'Hello' when $clickable is falsey *} -{* prints 'Hello' when $clickable is truthy *} +{* gibt 'Hello' aus, wenn $clickable falsch ist *} +{* gibt 'Hello' aus, wenn $clickable wahr ist *} ``` -Schön. +Göttlich. `n:else` .{data-version:3.0.11} ------------------------------- -Wenn Sie die Bedingung `{if} ... {/if}` in Form eines [n:-Attributs |syntax#n:attributes] schreiben, haben Sie die Möglichkeit, mit `n:else` eine alternative Verzweigung anzugeben: +Wenn Sie die Bedingung `{if} ... {/if}` in Form eines [n:Attributs|syntax#n:attributes] schreiben, haben Sie die Möglichkeit, eine alternative Verzweigung mit `n:else` anzugeben: ```latte -In stock {$count} items +{$count} Artikel auf Lager -not available +nicht verfügbar ``` -Das Attribut `n:else` kann auch in Verbindung mit [`n:ifset` |#ifset-elseifset], [`n:foreach` |#foreach], [`n:try` |#try], [`n:ifcontent` |#n:ifcontent], und [`n:ifchanged` |#ifchanged]. +Das Attribut `n:else` kann auch in Kombination mit [`n:ifset` |#ifset-elseifset], [`n:foreach` |#foreach], [`n:try` |#try], [`n:ifcontent` |#n:ifcontent] und [`n:ifchanged` |#ifchanged] verwendet werden. `{/if $cond}` ------------- -Sie werden vielleicht überrascht sein, dass der Ausdruck in der Bedingung `{if}` auch im End-Tag angegeben werden kann. Dies ist in Situationen nützlich, in denen wir den Wert der Bedingung noch nicht kennen, wenn das Tag geöffnet wird. Nennen wir es eine aufgeschobene Entscheidung. +Es mag Sie überraschen, dass der Ausdruck in der Bedingung `{if}` auch im schließenden Tag angegeben werden kann. Dies ist nützlich in Situationen, in denen wir beim Öffnen der Bedingung ihren Wert noch nicht kennen. Nennen wir es eine verzögerte Entscheidung. -Wir beginnen z. B. mit der Auflistung einer Tabelle mit Datensätzen aus der Datenbank und stellen erst nach Fertigstellung des Berichts fest, dass kein Datensatz in der Datenbank vorhanden war. Also setzen wir die Bedingung in das End-Tag `{/if}`, und wenn es keinen Datensatz gibt, wird nichts davon gedruckt: +Zum Beispiel beginnen wir mit der Ausgabe einer Tabelle mit Datensätzen aus der Datenbank und erst nach Abschluss der Ausgabe stellen wir fest, dass kein Datensatz in der Datenbank vorhanden war. Also setzen wir eine Bedingung in das schließende `{/if}`-Tag, und wenn kein Datensatz vorhanden ist, wird nichts davon ausgegeben: ```latte {if} -

Printing rows from the database

+

Ausgabe von Zeilen aus der Datenbank

{foreach $resultSet as $row} @@ -278,9 +278,9 @@ Wir beginnen z. B. mit der Auflistung einer Tabelle mit Datensätzen aus der Dat {/if isset($row)} ``` -Praktisch, nicht wahr? +Clever, nicht wahr? -Sie können auch `{else}` in der aufgeschobenen Bedingung verwenden, aber nicht `{elseif}`. +In einer verzögerten Bedingung kann auch `{else}` verwendet werden, aber nicht `{elseif}`. `{ifset}` `{elseifset}` @@ -289,7 +289,7 @@ Sie können auch `{else}` in der aufgeschobenen Bedingung verwenden, aber nicht .[note] Siehe auch [`{ifset block}` |template-inheritance#checking-block-existence] -Verwenden Sie die `{ifset $var}` Bedingung, um festzustellen, ob eine Variable (oder mehrere Variablen) existiert und einen Nicht-Null-Wert hat. Es ist eigentlich das Gleiche wie `if (isset($var))` in PHP. Wie jedes Paar-Tag kann es in der Form von [n:attribute |syntax#n:attributes] geschrieben werden, also zeigen wir es in einem Beispiel: +Mit der Bedingung `{ifset $var}` können wir überprüfen, ob eine Variable (oder mehrere Variablen) existiert und einen nicht-null-Wert hat. Es ist im Grunde dasselbe wie `if (isset($var))` in PHP. Wie jedes Paar-Tag kann es auch in Form eines [n:Attributs|syntax#n:attributes] geschrieben werden, also zeigen wir es als Beispiel: ```latte @@ -299,9 +299,9 @@ Verwenden Sie die `{ifset $var}` Bedingung, um festzustellen, ob eine Variable ( `{ifchanged}` ------------- -`{ifchanged}` prüft, ob sich der Wert einer Variablen seit der letzten Iteration in der Schleife (foreach, for oder while) geändert hat. +`{ifchanged}` überprüft, ob sich der Wert einer Variable seit der letzten Iteration in einer Schleife (foreach, for oder while) geändert hat. -Wenn wir eine oder mehrere Variablen im Tag angeben, wird geprüft, ob sich eine von ihnen geändert hat, und der Inhalt wird entsprechend ausgegeben. Im folgenden Beispiel wird beispielsweise bei der Auflistung von Namen jedes Mal der erste Buchstabe eines Namens als Überschrift ausgegeben, wenn er sich ändert: +Wenn wir eine oder mehrere Variablen im Tag angeben, wird überprüft, ob sich eine von ihnen geändert hat, und dementsprechend wird der Inhalt ausgegeben. Das folgende Beispiel gibt den ersten Buchstaben des Namens als Überschrift aus, jedes Mal wenn er sich bei der Ausgabe der Namen ändert: ```latte {foreach ($names|sort) as $name} @@ -311,7 +311,7 @@ Wenn wir eine oder mehrere Variablen im Tag angeben, wird geprüft, ob sich eine {/foreach} ``` -Wenn jedoch kein Argument angegeben wird, wird der gerenderte Inhalt selbst mit seinem vorherigen Zustand verglichen. Das bedeutet, dass wir im vorherigen Beispiel das Argument im Tag getrost weglassen können. Und natürlich können wir auch [n:attribute |syntax#n:attributes] verwenden: +Wenn wir jedoch kein Argument angeben, wird der gerenderte Inhalt im Vergleich zu seinem vorherigen Zustand überprüft. Das bedeutet, dass wir im vorherigen Beispiel das Argument im Tag weglassen können. Und natürlich können wir auch ein [n:Attribut|syntax#n:attributes] verwenden: ```latte {foreach ($names|sort) as $name} @@ -321,35 +321,35 @@ Wenn jedoch kein Argument angegeben wird, wird der gerenderte Inhalt selbst mit {/foreach} ``` -Sie können auch eine `{else}` Klausel innerhalb der `{ifchanged}` einfügen. +Innerhalb von `{ifchanged}` kann auch eine `{else}`-Klausel verwendet werden. `{switch}` `{case}` `{default}` ------------------------------- -Vergleicht den Wert mit mehreren Optionen. Dies ist ähnlich wie die `switch` Struktur, die Sie aus PHP kennen. Latte verbessert sie jedoch: +Vergleicht einen Wert mit mehreren Möglichkeiten. Es ist ähnlich wie die bedingte Anweisung `switch`, die Sie aus PHP kennen. Latte verbessert sie jedoch: -- verwendet einen strengen Vergleich (`===`) -- braucht kein `break` +- es verwendet einen strikten Vergleich (`===`) +- es benötigt kein `break` -Es ist also das exakte Äquivalent der `match` Struktur, die PHP 8.0 mitbringt. +Es ist also das genaue Äquivalent zur `match`-Struktur, die mit PHP 8.0 eingeführt wurde. ```latte {switch $transport} {case train} - By train + Mit dem Zug {case plane} - By plane + Mit dem Flugzeug {default} - Differently + Anderweitig {/switch} ``` -Die Klausel `{case}` kann mehrere durch Kommas getrennte Werte enthalten: +Die `{case}`-Klausel kann mehrere durch Kommas getrennte Werte enthalten: ```latte {switch $status} -{case $status::New}new item -{case $status::Sold, $status::Unknown}not available +{case $status::New}neuer Artikel +{case $status::Sold, $status::Unknown}nicht verfügbar {/switch} ``` @@ -357,13 +357,13 @@ Die Klausel `{case}` kann mehrere durch Kommas getrennte Werte enthalten: Schleifen .[#toc-loops] ======================= -In Latte stehen Ihnen alle Schleifen, die Sie aus PHP kennen, zur Verfügung: foreach, for und while. +In Latte finden Sie alle Schleifen, die Sie aus PHP kennen: foreach, for und while. `{foreach}` ----------- -Sie schreiben den Zyklus genau so wie in PHP: +Wir schreiben die Schleife genauso wie in PHP: ```latte {foreach $langs as $code => $lang} @@ -371,11 +371,11 @@ Sie schreiben den Zyklus genau so wie in PHP: {/foreach} ``` -Darüber hinaus hat er einige praktische Verbesserungen, über die wir jetzt sprechen werden. +Zusätzlich hat sie einige nützliche Funktionen, über die wir jetzt sprechen werden. -So stellt Latte zum Beispiel sicher, dass erstellte Variablen nicht versehentlich gleichnamige globale Variablen überschreiben. Das hilft Ihnen, wenn Sie davon ausgehen, dass `$lang` die aktuelle Sprache der Seite ist, und Sie nicht merken, dass `foreach $langs as $lang` diese Variable überschrieben hat. +Latte überprüft zum Beispiel, ob erstellte Variablen versehentlich globale Variablen mit demselben Namen überschreiben. Das rettet Situationen, in denen Sie davon ausgehen, dass `$lang` die aktuelle Sprache der Seite ist, und nicht bemerken, dass `foreach $langs as $lang` diese Variable überschrieben hat. -Die foreach-Schleife kann auch sehr elegant und sparsam mit [n:attribute |syntax#n:attributes] geschrieben werden: +Die foreach-Schleife kann auch sehr elegant und kompakt als [n:Attribut|syntax#n:attributes] geschrieben werden: ```latte
    @@ -383,7 +383,7 @@ Die foreach-Schleife kann auch sehr elegant und sparsam mit [n:attribute |syntax
``` -Wussten Sie, dass Sie n:attributes das Präfix `inner-` voranstellen können? Dann wird in der Schleife nur noch der innere Teil des Elements wiederholt: +Wussten Sie, dass Sie n:Attribute mit dem Präfix `inner-` versehen können? Dann wird nur der Inhalt des Elements in der Schleife wiederholt: ```latte
@@ -392,7 +392,7 @@ Wussten Sie, dass Sie n:attributes das Präfix `inner-` voranstellen können? Da
``` -Es wird also etwas gedruckt wie: +Dies wird also etwas wie folgendes ausgeben: ```latte
@@ -407,14 +407,14 @@ Es wird also etwas gedruckt wie: `{else}` .{toc: foreach-else} ----------------------------- -Die Schleife `foreach` kann eine optionale Klausel `{else}` enthalten, deren Text angezeigt wird, wenn das angegebene Feld leer ist: +Innerhalb einer `foreach`-Schleife kann eine `{else}`-Klausel angegeben werden, deren Inhalt angezeigt wird, wenn die Schleife leer ist: ```latte
    {foreach $people as $person}
  • {$person->name}
  • {else} -
  • Sorry, no users in this list
  • +
  • Leider sind in dieser Liste keine Benutzer
  • {/foreach}
``` @@ -423,17 +423,17 @@ Die Schleife `foreach` kann eine optionale Klausel `{else}` enthalten, deren Tex `$iterator` ----------- -Innerhalb der Schleife `foreach` wird die Variable `$iterator` initialisiert. Sie enthält wichtige Informationen über die aktuelle Schleife. +Innerhalb einer `foreach`-Schleife erstellt Latte eine Variable `$iterator`, mit der wir nützliche Informationen über die laufende Schleife abrufen können: -- `$iterator->first` - ist dies die erste Iteration? -- `$iterator->last` - ist dies die letzte Iteration? -- `$iterator->counter` - Iterationszähler, beginnt bei 1 -- `$iterator->counter0` - Iterationszähler, beginnt bei 0 -- `$iterator->odd` - Ist diese Iteration ungerade? -- `$iterator->even` - ist diese Iteration gerade? -- `$iterator->parent` - der Iterator, der den aktuellen Iterator umgibt -- `$iterator->nextValue` - das nächste Element in der Schleife -- `$iterator->nextKey` - der Schlüssel des nächsten Elements in der Schleife +- `$iterator->first` - ist dies der erste Durchlauf? +- `$iterator->last` - ist dies der letzte Durchlauf? +- `$iterator->counter` - der wievielte Durchlauf ist es, gezählt ab eins? +- `$iterator->counter0` - der wievielte Durchlauf ist es, gezählt ab null? +- `$iterator->odd` - ist dies ein ungerader Durchlauf? +- `$iterator->even` - ist dies ein gerader Durchlauf? +- `$iterator->parent` - der Iterator, der den aktuellen umgibt +- `$iterator->nextValue` - der nächste Eintrag in der Schleife +- `$iterator->nextKey` - der Schlüssel des nächsten Eintrags in der Schleife ```latte @@ -449,20 +449,20 @@ Innerhalb der Schleife `foreach` wird die Variable `$iterator` initialisiert. Si {/foreach} ``` -Die Latte ist schlau und `$iterator->last` funktioniert nicht nur für Arrays, sondern auch, wenn die Schleife über einen allgemeinen Iterator läuft, bei dem die Anzahl der Elemente nicht im Voraus bekannt ist. +Latte ist schlau und `$iterator->last` funktioniert nicht nur bei Arrays, sondern auch wenn die Schleife über einen allgemeinen Iterator läuft, bei dem die Anzahl der Elemente nicht im Voraus bekannt ist. `{first}` `{last}` `{sep}` -------------------------- -Diese Tags können innerhalb der Schleife `{foreach}` verwendet werden. Der Inhalt von `{first}` wird beim ersten Durchlauf gerendert. -Der Inhalt von `{last}` wird gerendert ... können Sie es erraten? Ja, für den letzten Durchlauf. Dies sind eigentlich Abkürzungen für `{if $iterator->first}` und `{if $iterator->last}`. +Diese Tags können innerhalb einer `{foreach}`-Schleife verwendet werden. Der Inhalt von `{first}` wird gerendert, wenn es sich um den ersten Durchlauf handelt. +Der Inhalt von `{last}` wird gerendert ... können Sie es erraten? Ja, wenn es sich um den letzten Durchlauf handelt. Es handelt sich eigentlich um Abkürzungen für `{if $iterator->first}` und `{if $iterator->last}`. -Die Tags können auch als [n:attributes |syntax#n:attributes] geschrieben werden: +Die Tags können auch elegant als [n:Attribute|syntax#n:attributes] verwendet werden: ```latte {foreach $rows as $row} - {first}

List of names

{/first} + {first}

Liste der Namen

{/first}

{$row->name}

@@ -470,21 +470,21 @@ Die Tags können auch als [n:attributes |syntax#n:attributes] geschrieben werden {/foreach} ``` -Der Inhalt von `{sep}` wird wiedergegeben, wenn es sich nicht um die letzte Iteration handelt, und eignet sich daher für die Ausgabe von Begrenzungszeichen, wie z. B. Kommas zwischen aufgelisteten Elementen: +Der Inhalt des `{sep}`-Tags wird gerendert, wenn der Durchlauf nicht der letzte ist. Es eignet sich also zum Rendern von Trennzeichen, zum Beispiel Kommas zwischen ausgegebenen Elementen: ```latte {foreach $items as $item} {$item} {sep}, {/sep} {/foreach} ``` -Das ist doch ziemlich praktisch, oder? +Das ist ziemlich praktisch, nicht wahr? `{iterateWhile}` ---------------- -Vereinfacht die Gruppierung von linearen Daten während der Iteration in einer foreach-Schleife durch Iteration in einer verschachtelten Schleife, bis eine Bedingung erfüllt ist. [Lesen Sie die ausführliche Anleitung |cookbook/grouping]. +Vereinfacht die Gruppierung linearer Daten während der Iteration in einer foreach-Schleife, indem die Iteration in einer verschachtelten Schleife durchgeführt wird, solange eine Bedingung erfüllt ist. [Lesen Sie die detaillierte Anleitung|cookbook/grouping]. -Sie kann auch `{first}` und `{last}` im obigen Beispiel elegant ersetzen: +Es kann auch elegant `{first}` und `{last}` im obigen Beispiel ersetzen: ```latte {foreach $rows as $row} @@ -501,21 +501,21 @@ Sie kann auch `{first}` und `{last}` im obigen Beispiel elegant ersetzen: {/foreach} ``` -Siehe auch [Batch- |filters#batch] und [Gruppenfilter |filters#group]. +Siehe auch die Filter [batch|filters#batch] und [group|filters#group]. `{for}` ------- -Wir schreiben den Zyklus genau so wie in PHP: +Wir schreiben die Schleife genauso wie in PHP: ```latte {for $i = 0; $i < 10; $i++} - Item #{$i} + Element {$i} {/for} ``` -Das Tag kann auch als [n:attribute |syntax#n:attributes] geschrieben werden: +Das Tag kann auch als [n:Attribut|syntax#n:attributes] verwendet werden: ```latte

{$i}

@@ -525,7 +525,7 @@ Das Tag kann auch als [n:attribute |syntax#n:attributes] geschrieben werden: `{while}` --------- -Auch hier schreiben wir den Zyklus genau so, wie in PHP: +Wir schreiben die Schleife wieder genauso wie in PHP: ```latte {while $row = $result->fetch()} @@ -533,7 +533,7 @@ Auch hier schreiben wir den Zyklus genau so, wie in PHP: {/while} ``` -Oder als [n:Attribut |syntax#n:attributes]: +Oder als [n:Attribut|syntax#n:attributes]: ```latte @@ -541,7 +541,7 @@ Oder als [n:Attribut |syntax#n:attributes]: ``` -Eine Variante mit einer Bedingung im End-Tag entspricht der do-while-Schleife in PHP: +Eine Variante mit der Bedingung im schließenden Tag ist ebenfalls möglich, die der do-while-Schleife in PHP entspricht: ```latte {while} @@ -553,7 +553,7 @@ Eine Variante mit einer Bedingung im End-Tag entspricht der do-while-Schleife in `{continueIf}` `{skipIf}` `{breakIf}` ------------------------------------- -Es gibt spezielle Tags, die Sie zur Steuerung jeder Schleife verwenden können - `{continueIf ?}` und `{breakIf ?}`, die zur nächsten Iteration springen bzw. die Schleife beenden, wenn die Bedingungen erfüllt sind: +Zur Steuerung jeder Schleife können die Tags `{continueIf ?}` und `{breakIf ?}` verwendet werden, die zum nächsten Element übergehen bzw. die Schleife beenden, wenn eine Bedingung erfüllt ist: ```latte {foreach $rows as $row} @@ -564,7 +564,7 @@ Es gibt spezielle Tags, die Sie zur Steuerung jeder Schleife verwenden können - ``` -Das Tag `{skipIf}` ist dem Tag `{continueIf}` sehr ähnlich, erhöht aber den Zähler nicht. So gibt es keine Löcher in der Nummerierung, wenn Sie `$iterator->counter` ausdrucken und einige Elemente überspringen. Auch die {else}-Klausel wird wiedergegeben, wenn Sie alle Elemente überspringen. +Das `{skipIf}`-Tag ist sehr ähnlich wie `{continueIf}`, erhöht aber nicht den Zähler `$iterator->counter`, so dass, wenn wir ihn ausgeben und gleichzeitig einige Elemente überspringen, keine Lücken in der Nummerierung entstehen. Außerdem wird die `{else}`-Klausel gerendert, wenn wir alle Elemente überspringen. ```latte
    @@ -572,7 +572,7 @@ Das Tag `{skipIf}` ist dem Tag `{continueIf}` sehr ähnlich, erhöht aber den Z {skipIf $person->age < 18}
  • {$iterator->counter}. {$person->name}
  • {else} -
  • Sorry, no adult users in this list
  • +
  • Leider gibt es keine Erwachsenen in dieser Liste
  • {/foreach}
``` @@ -581,20 +581,20 @@ Das Tag `{skipIf}` ist dem Tag `{continueIf}` sehr ähnlich, erhöht aber den Z `{exitIf}` .{data-version:3.0.5} -------------------------------- -Beendet das Rendering einer Vorlage oder eines Blocks, wenn eine Bedingung erfüllt ist (d. h. "early exit"). +Beendet das Rendern des Templates oder Blocks, wenn eine Bedingung erfüllt ist (sogenannter "early exit"). ```latte {exitIf !$messages} -

Messages

+

Nachrichten

{$message}
``` -Schablonen einbeziehen .[#toc-including-templates] -================================================== +Einbindung von Templates .[#toc-including-templates] +==================================================== `{include 'file.latte'}` .{toc: include} @@ -603,46 +603,46 @@ Schablonen einbeziehen .[#toc-including-templates] .[note] Siehe auch [`{include block}` |template-inheritance#printing-blocks] -Der `{include}` Tag lädt und rendert die angegebene Vorlage. In unserer Lieblingssprache PHP sieht das so aus: +Das `{include}`-Tag lädt und rendert das angegebene Template. Wenn wir in der Sprache unserer Lieblingssprache PHP sprechen würden, wäre es so etwas wie: ```php ``` -Eingebundene Templates haben keinen Zugriff auf die Variablen des aktiven Kontexts, aber sie haben Zugriff auf die globalen Variablen. +Eingebundene Templates haben keinen Zugriff auf die Variablen des aktiven Kontexts, sie haben nur Zugriff auf globale Variablen. -Sie können der eingefügten Vorlage auf folgende Weise Variablen übergeben: +Variablen können auf diese Weise an das eingebundene Template übergeben werden: ```latte {include 'template.latte', foo: 'bar', id: 123} ``` -Der Name der Vorlage kann ein beliebiger PHP-Ausdruck sein: +Der Name des Templates kann ein beliebiger PHP-Ausdruck sein: ```latte {include $someVar} {include $ajax ? 'ajax.latte' : 'not-ajax.latte'} ``` -Der eingefügte Inhalt kann durch [Filter |syntax#filters] verändert werden. Im folgenden Beispiel werden alle HTML-Elemente entfernt und die Groß- und Kleinschreibung angepasst: +Der eingebundene Inhalt kann mit [Filtern|syntax#Filters] modifiziert werden. Das folgende Beispiel entfernt das gesamte HTML und passt die Groß-/Kleinschreibung an: ```latte {include 'heading.latte' |stripHtml|capitalize} ``` -Die [Vorlagenvererbung |template inheritance] ist standardmäßig **nicht** daran beteiligt. Sie können zwar Block-Tags zu eingebundenen Vorlagen hinzufügen, diese ersetzen jedoch nicht die passenden Blöcke in der Vorlage, in die sie eingebunden sind. Betrachten Sie Includes als unabhängige und abgeschirmte Teile von Seiten oder Modulen. Dieses Verhalten kann mit dem Modifikator `with blocks` geändert werden: +Standardmäßig spielt die [Template-Vererbung|template-inheritance] in diesem Fall keine Rolle. Auch wenn wir in dem eingebundenen Template Blöcke verwenden können, werden die entsprechenden Blöcke in dem Template, in das eingebunden wird, nicht ersetzt. Denken Sie an eingebundene Templates als separate, abgeschirmte Teile von Seiten oder Modulen. Dieses Verhalten kann mit dem Modifikator `with blocks` geändert werden: ```latte {include 'template.latte' with blocks} ``` -Die Beziehung zwischen dem im Tag angegebenen Dateinamen und der Datei auf der Festplatte ist eine Sache des [Loaders |extending-latte#Loaders]. +Die Beziehung zwischen dem im Tag angegebenen Dateinamen und der Datei auf der Festplatte ist eine Angelegenheit des [Loaders|extending-latte#Loaders]. `{sandbox}` ----------- -Wenn Sie eine von einem Endbenutzer erstellte Vorlage einbinden, sollten Sie eine Sandbox verwenden (weitere Informationen finden Sie in der [Sandbox-Dokumentation |sandbox]): +Bei der Einbindung eines vom Endbenutzer erstellten Templates sollten Sie den Sandbox-Modus in Betracht ziehen (weitere Informationen finden Sie in der [Sandbox-Dokumentation |sandbox]): ```latte {sandbox 'untrusted.latte', level: 3, data: $menu} @@ -655,7 +655,7 @@ Wenn Sie eine von einem Endbenutzer erstellte Vorlage einbinden, sollten Sie ein .[note] Siehe auch [`{block name}` |template-inheritance#blocks] -Blöcke ohne Namen dienen dazu, [Filter |syntax#filters] auf einen Teil der Vorlage anzuwenden. Sie können zum Beispiel einen [Streifenfilter |filters#strip] anwenden, um überflüssige Leerzeichen zu entfernen: +Namenlose Blöcke dienen als Möglichkeit, [Filter|syntax#Filters] auf einen Teil des Templates anzuwenden. Zum Beispiel kann auf diese Weise der [strip|filters#strip]-Filter angewendet werden, der überflüssige Leerzeichen entfernt: ```latte {block|strip} @@ -666,16 +666,16 @@ Blöcke ohne Namen dienen dazu, [Filter |syntax#filters] auf einen Teil der Vorl ``` -Behandlung von Ausnahmen .[#toc-exception-handling] -=================================================== +Ausnahmebehandlung .[#toc-exception-handling] +============================================= `{try}` ------- -Diese Tags machen es extrem einfach, robuste Vorlagen zu erstellen. +Dank dieses Tags ist es extrem einfach, robuste Templates zu erstellen. -Wenn beim Rendern des `{try}` -Blocks eine Ausnahme auftritt, wird der gesamte Block verworfen und das Rendern danach fortgesetzt: +Wenn während des Renderns eines `{try}`-Blocks eine Ausnahme auftritt, wird der gesamte Block verworfen und das Rendering wird danach fortgesetzt: ```latte {try} @@ -687,7 +687,7 @@ Wenn beim Rendern des `{try}` -Blocks eine Ausnahme auftritt, wird der gesamte B {/try} ``` -Der Inhalt der optionalen Klausel `{else}` wird nur gerendert, wenn eine Ausnahme auftritt: +Der Inhalt in der optionalen `{else}`-Klausel wird nur gerendert, wenn eine Ausnahme auftritt: ```latte {try} @@ -697,11 +697,11 @@ Der Inhalt der optionalen Klausel `{else}` wird nur gerendert, wenn eine Ausnahm {/foreach} {else} -

Sorry, the tweets could not be loaded.

+

Es tut uns leid, die Tweets konnten nicht geladen werden.

{/try} ``` -Der Tag kann auch als [n:attribute |syntax#n:attributes] geschrieben werden: +Das Tag kann auch als [n:Attribut|syntax#n:attributes] verwendet werden: ```latte
    @@ -709,13 +709,13 @@ Der Tag kann auch als [n:attribute |syntax#n:attributes] geschrieben werden:
``` -Es ist auch möglich, [einen eigenen Exception-Handler |develop#exception handler] für z.B. die Protokollierung zu definieren: +Es ist auch möglich, einen eigenen [Handler für Ausnahmen|develop#exception handler] zu definieren, zum Beispiel für Logging-Zwecke. `{rollback}` ------------ -Der Block `{try}` kann auch manuell mit `{rollback}` angehalten und übersprungen werden. So müssen Sie nicht alle Eingabedaten im Voraus prüfen und können erst während des Renderings entscheiden, ob es sinnvoll ist, das Objekt zu rendern. +Ein `{try}`-Block kann auch manuell mit `{rollback}` gestoppt und übersprungen werden. Dadurch müssen Sie nicht alle Eingabedaten im Voraus überprüfen und können während des Renderings entscheiden, dass Sie das Objekt überhaupt nicht rendern möchten: ```latte {try} @@ -738,13 +738,13 @@ Variablen .[#toc-variables] `{var}` `{default}` ------------------- -Wir werden neue Variablen in der Vorlage mit dem Tag `{var}` erstellen: +Neue Variablen werden im Template mit dem Tag `{var}` erstellt: ```latte {var $name = 'John Smith'} {var $age = 27} -{* Mehrfache Deklaration *} +{* Mehrfachdeklaration *} {var $name = 'John Smith', $age = 27} ``` @@ -754,7 +754,7 @@ Das Tag `{default}` funktioniert ähnlich, mit dem Unterschied, dass es Variable {default $lang = 'cs'} ``` -Sie können auch [Typen von Variablen |type-system] angeben. Im Moment sind sie informativ und Latte prüft sie nicht. +Sie können auch [Variablentypen|type-system] angeben. Diese sind derzeit informativ und werden von Latte nicht überprüft. ```latte {var string $name = $article->getTitle()} @@ -765,7 +765,7 @@ Sie können auch [Typen von Variablen |type-system] angeben. Im Moment sind sie `{parameters}` -------------- -So wie eine Funktion ihre Parameter deklariert, kann eine Vorlage ihre Variablen am Anfang deklarieren: +So wie eine Funktion ihre Parameter deklariert, kann auch ein Template am Anfang seine Variablen deklarieren: ```latte {parameters @@ -775,15 +775,15 @@ So wie eine Funktion ihre Parameter deklariert, kann eine Vorlage ihre Variablen } ``` -Die Variablen `$a` und `$b` ohne Standardwert haben automatisch den Standardwert `null`. Die deklarierten Typen sind immer noch informativ, und Latte überprüft sie nicht. +Variablen `$a` und `$b` ohne angegebenen Standardwert haben automatisch den Standardwert `null`. Die deklarierten Typen sind derzeit informativ und werden von Latte nicht überprüft. -Andere als die deklarierten Variablen werden nicht an die Vorlage übergeben. Dies ist ein Unterschied zum Tag `{default}`. +Andere als die deklarierten Variablen werden nicht in das Template übertragen. Dies unterscheidet es vom Tag `{default}`. `{capture}` ----------- -Mit dem Tag `{capture}` können Sie die Ausgabe in einer Variablen erfassen: +Erfasst die Ausgabe in eine Variable: ```latte {capture $var} @@ -792,10 +792,10 @@ Mit dem Tag `{capture}` können Sie die Ausgabe in einer Variablen erfassen: {/capture} -

Captured: {$var}

+

Erfasst: {$var}

``` -Der Tag kann auch als [n:attribute |syntax#n:attributes] geschrieben werden, wie jeder paarweise Tag: +Das Tag kann, wie jedes Paar-Tag, auch als [n:Attribut|syntax#n:Attribute] geschrieben werden: ```latte
    @@ -803,17 +803,17 @@ Der Tag kann auch als [n:attribute |syntax#n:attributes] geschrieben werden, wie
``` -Die HTML-Ausgabe wird in der Variablen `$var` als `Latte\Runtime\Html` -Objekt gespeichert, um [unerwünschtes Escaping |develop#disabling-auto-escaping-of-variable] beim Drucken [zu vermeiden |develop#disabling-auto-escaping-of-variable]. +Die HTML-Ausgabe wird in der Variable `$var` als `Latte\Runtime\Html`-Objekt gespeichert, um [unerwünschtes Escaping |develop#disabling-auto-escaping-of-variable] beim Ausgeben zu verhindern. -Andere .[#toc-others] -===================== +Sonstiges .[#toc-others] +======================== `{contentType}` --------------- -Verwenden Sie das Tag, um anzugeben, welche Art von Inhalt die Vorlage darstellt. Die Optionen sind: +Mit diesem Tag geben Sie an, welchen Inhaltstyp das Template darstellt. Die Optionen sind: - `html` (Standardtyp) - `xml` @@ -822,16 +822,16 @@ Verwenden Sie das Tag, um anzugeben, welche Art von Inhalt die Vorlage darstellt - `calendar` (iCal) - `text` -Die Verwendung dieses Befehls ist wichtig, weil er die [kontextabhängige Escape-Funktion |safety-first#context-aware-escaping] einstellt und nur dann kann Latte korrekt escapen. Zum Beispiel schaltet `{contentType xml}` in den XML-Modus, `{contentType text}` schaltet das Escapen komplett ab. +Seine Verwendung ist wichtig, da es das [kontextsensitive Escaping |safety-first#context-aware-escaping] festlegt und nur so richtig escapen kann. Zum Beispiel schaltet `{contentType xml}` in den XML-Modus um, `{contentType text}` schaltet das Escaping komplett aus. -Handelt es sich bei dem Parameter um einen MIME-Typ mit vollem Funktionsumfang, wie z. B. `application/xml`, so wird auch ein HTTP-Header `Content-Type` an den Browser gesendet: +Wenn der Parameter ein vollständiger MIME-Typ ist, wie zum Beispiel `application/xml`, wird zusätzlich der HTTP-Header `Content-Type` an den Browser gesendet: ```latte {contentType application/xml} - RSS feed + RSS-Feed ... @@ -843,19 +843,19 @@ Handelt es sich bei dem Parameter um einen MIME-Typ mit vollem Funktionsumfang, `{debugbreak}` -------------- -Gibt die Stelle an, an der die Codeausführung unterbrochen wird. Sie wird zu Debugging-Zwecken verwendet, damit der Programmierer die Laufzeitumgebung überprüfen und sicherstellen kann, dass der Code wie erwartet ausgeführt wird. Er unterstützt [Xdebug |https://xdebug.org]. Zusätzlich können Sie eine Bedingung angeben, unter der der Code unterbrochen werden soll. +Markiert eine Stelle, an der die Programmausführung angehalten und der Debugger gestartet wird, damit der Programmierer die Laufzeitumgebung inspizieren und überprüfen kann, ob das Programm wie erwartet funktioniert. Es unterstützt [Xdebug |https://xdebug.org/]. Eine Bedingung kann hinzugefügt werden, die bestimmt, wann das Programm angehalten werden soll. ```latte -{debugbreak} {* bricht das Programm *} +{debugbreak} {* hält das Programm an *} -{debugbreak $counter == 1} {* bricht das Programm ab, wenn die Bedingung erfüllt ist *} +{debugbreak $counter == 1} {* hält das Programm an, wenn die Bedingung erfüllt ist *} ``` `{do}` ------ -Führt den PHP-Code aus und gibt nichts aus. Wie bei allen anderen Tags ist der PHP-Code ein einzelner Ausdruck, siehe [PHP-Einschränkungen |syntax#PHP Limitations in Latte]. +Führt PHP-Code aus und gibt nichts aus. Wie bei allen anderen Tags mit PHP-Code handelt es sich um einen einzelnen Ausdruck, siehe [PHP-Einschränkungen |syntax#PHP Limitations in Latte]. ```latte {do $num++} @@ -868,80 +868,80 @@ Führt den PHP-Code aus und gibt nichts aus. Wie bei allen anderen Tags ist der Gibt eine Variable oder den aktuellen Kontext aus. ```latte -{dump $name} {* gibt die Variable $name aus *} +{dump $name} {* Gibt die Variable $name aus *} -{dump} {* gibt alle definierten Variablen aus *} +{dump} {* Gibt alle aktuell definierten Variablen aus *} ``` .[caution] -Erfordert das Paket [Tracy |tracy:]. +Erfordert die [Tracy|tracy:]-Bibliothek. `{php}` ------- -Ermöglicht die Ausführung von beliebigem PHP-Code. Das Tag muss mit der Erweiterung [RawPhpExtension |develop#RawPhpExtension] aktiviert werden. +Ermöglicht die Ausführung beliebigen PHP-Codes. Das Tag muss durch die [RawPhpExtension |develop#RawPhpExtension] aktiviert werden. `{spaceless}` ------------- -Entfernt unnötige Leerzeichen. Ähnlich wie der [raumlose |filters#spaceless] Filter. +Entfernt überflüssige Leerzeichen aus der Ausgabe. Funktioniert ähnlich wie der Filter [spaceless|filters#spaceless]. ```latte {spaceless}
    -
  • Hello
  • +
  • Hallo
{/spaceless} ``` -Ausgaben: +Erzeugt ```latte -
  • Hello
+
  • Hallo
``` -Der Tag kann auch als [n:attribute |syntax#n:attributes] geschrieben werden: +Das Tag kann auch als [n:Attribut|syntax#n:attributes] geschrieben werden. `{syntax}` ---------- -Latten-Tags müssen nicht nur in geschweifte Klammern eingeschlossen werden. Sie können ein anderes Trennzeichen wählen, auch zur Laufzeit. Dies geschieht durch `{syntax…}`, wobei der Parameter sein kann: +Latte-Tags müssen nicht nur durch einfache geschweifte Klammern begrenzt sein. Wir können auch einen anderen Begrenzer wählen, sogar zur Laufzeit. Dafür wird `{syntax …}` verwendet, wobei als Parameter angegeben werden kann: - double: `{{...}}` -- off: deaktiviert die Latte-Tags vollständig +- off: schaltet die Verarbeitung von Latte-Tags komplett aus -Mit der Notation n:attribute können wir Latte nur für einen JavaScript-Block deaktivieren: +Mit Hilfe von n:Attributen kann Latte zum Beispiel nur für einen JavaScript-Block ausgeschaltet werden: ```latte ``` -Latte kann sehr bequem innerhalb von JavaScript verwendet werden, man sollte nur Konstrukte wie in diesem Beispiel vermeiden, bei denen der Buchstabe unmittelbar auf `{` folgt, siehe [Latte innerhalb von JavaScript oder CSS |recipes#Latte inside JavaScript or CSS]. +Latte kann sehr bequem auch innerhalb von JavaScript verwendet werden, man muss nur Konstruktionen wie in diesem Beispiel vermeiden, bei denen direkt nach `{` ein Buchstabe folgt, siehe [Latte innerhalb von JavaScript oder CSS|recipes#Latte inside JavaScript or CSS]. -Wenn Sie Latte mit dem `{syntax off}` (d.h. Tag, nicht das n:-Attribut) ausschalten, werden alle Tags bis zu `{/syntax}` strikt ignoriert. +Wenn Sie Latte mit `{syntax off}` ausschalten (d.h. mit einem Tag, nicht mit einem n:Attribut), wird es konsequent alle Tags bis `{/syntax}` ignorieren. {trace} ------- -Wirft eine `Latte\RuntimeException` Exception, deren Stack-Trace im Sinne der Templates ist. Anstatt Funktionen und Methoden aufzurufen, werden also Blöcke aufgerufen und Vorlagen eingefügt. Wenn Sie ein Tool zur übersichtlichen Darstellung von geworfenen Ausnahmen wie [Tracy |tracy:] verwenden, sehen Sie deutlich den Aufrufstapel, einschließlich aller übergebenen Argumente. +Wirft eine `Latte\RuntimeException`, deren Stack-Trace im Geiste der Templates ist. Anstelle von Funktions- und Methodenaufrufen enthält er also Blockaufrufe und Template-Einbindungen. Wenn Sie ein Tool zur übersichtlichen Anzeige von geworfenen Ausnahmen verwenden, wie zum Beispiel [Tracy|tracy:], wird Ihnen der Call Stack einschließlich aller übergebenen Argumente übersichtlich angezeigt. -HTML-Tag-Hilfsmittel .[#toc-html-tag-helpers] -============================================= +Helfer für HTML-Codierer .[#toc-html-tag-helpers] +================================================= n:class ------- -Dank `n:class` ist es sehr einfach, das HTML-Attribut `class` genau so zu generieren, wie Sie es brauchen. +Dank `n:class` können Sie sehr einfach das HTML-Attribut `class` genau nach Ihren Vorstellungen generieren. -Beispiel: Ich möchte, dass das aktive Element die Klasse `active` hat: +Beispiel: Ich brauche, dass das aktive Element die Klasse `active` hat: ```latte {foreach $items as $item} @@ -949,7 +949,7 @@ Beispiel: Ich möchte, dass das aktive Element die Klasse `active` hat: {/foreach} ``` -Außerdem muss das erste Element die Klassen `first` und `main` haben: +Und weiter, dass das erste Element die Klassen `first` und `main` hat: ```latte {foreach $items as $item} @@ -957,7 +957,7 @@ Außerdem muss das erste Element die Klassen `first` und `main` haben: {/foreach} ``` -Und alle Elemente sollten die Klasse `list-item` haben: +Und alle Elemente sollen die Klasse `list-item` haben: ```latte {foreach $items as $item} @@ -965,13 +965,13 @@ Und alle Elemente sollten die Klasse `list-item` haben: {/foreach} ``` -Verblüffend einfach, nicht wahr? +Unglaublich einfach, nicht wahr? n:attr ------ -Das Attribut `n:attr` kann beliebige HTML-Attribute mit der gleichen Eleganz wie [n:class |#n:class] erzeugen. +Das Attribut `n:attr` kann mit der gleichen Eleganz wie [n:class|#n:class] beliebige HTML-Attribute generieren. ```latte {foreach $data as $item} @@ -979,7 +979,7 @@ Das Attribut `n:attr` kann beliebige HTML-Attribute mit der gleichen Eleganz wie {/foreach} ``` -Abhängig von den zurückgegebenen Werten zeigt es z. B: +Abhängig von den zurückgegebenen Werten wird zum Beispiel Folgendes ausgegeben: ```latte @@ -993,25 +993,25 @@ Abhängig von den zurückgegebenen Werten zeigt es z. B: n:tag ----- -Das Attribut `n:tag` kann den Namen eines HTML-Elements dynamisch ändern. +Das Attribut `n:tag` kann den Namen des HTML-Elements dynamisch ändern. ```latte

{$title}

``` -Wenn `$heading === null`, wird das `

` Tag ohne Änderung gedruckt. Andernfalls wird der Elementname in den Wert der Variablen geändert, so dass für `$heading === 'h3'` geschrieben wird: +Wenn `$heading === null` ist, wird der Tag `

` unverändert ausgegeben. Andernfalls wird der Name des Elements auf den Wert der Variable geändert, so dass für `$heading === 'h3'` Folgendes ausgegeben wird: ```latte

...

``` -Da es sich bei Latte um ein sicheres Templating-System handelt, wird überprüft, ob der neue Tag-Name gültig ist und keine unerwünschten oder bösartigen Werte enthält. +Da Latte ein sicheres Template-System ist, überprüft es, ob der neue Tag-Name gültig ist und keine unerwünschten oder schädlichen Werte enthält. n:ifcontent ----------- -Verhindert, dass ein leeres HTML-Element gedruckt wird, d.h. ein Element, das nichts als Leerraum enthält. +Verhindert, dass ein leeres HTML-Element ausgegeben wird, d.h. ein Element, das nichts außer Leerzeichen enthält. ```latte
@@ -1019,7 +1019,7 @@ Verhindert, dass ein leeres HTML-Element gedruckt wird, d.h. ein Element, das ni
``` -Abhängig von den Werten der Variablen `$error` wird dies gedruckt: +Gibt abhängig vom Wert der Variable `$error` aus: ```latte {* $error = '' *} @@ -1033,10 +1033,10 @@ Abhängig von den Werten der Variablen `$error` wird dies gedruckt: ``` -Übersetzung .[#toc-translation] -=============================== +Übersetzungen .[#toc-translation] +================================= -Damit die Übersetzungs-Tags funktionieren, müssen Sie den [Übersetzer ein richten|develop#TranslatorExtension]. Sie können auch den [`translate` |filters#translate] Filter für die Übersetzung verwenden. +Damit die Übersetzungs-Tags funktionieren, muss der [Übersetzer aktiviert werden|develop#TranslatorExtension]. Für Übersetzungen können Sie auch den Filter [`translate`|filters#translate] verwenden. `{_...}` @@ -1045,30 +1045,30 @@ Damit die Übersetzungs-Tags funktionieren, müssen Sie den [Übersetzer ein ric Übersetzt Werte in andere Sprachen. ```latte -{_'Basket'} +{_'Warenkorb'} {_$item} ``` -Es können auch andere Parameter an den Übersetzer übergeben werden: +Dem Übersetzer können auch weitere Parameter übergeben werden: ```latte -{_'Basket', domain: order} +{_'Warenkorb', domain: order} ``` `{translate}` ------------- -Překládá části šablony: +Übersetzt Teile des Templates: ```latte -

{translate}Order{/translate}

+

{translate}Bestellung{/translate}

{translate domain: order}Lorem ipsum ...{/translate} ``` -Der Tag kann auch als [n:attribute |syntax#n:attributes] geschrieben werden, um das Innere des Elements zu übersetzen: +Das Tag kann auch als [n:Attribut|syntax#n:attributes] geschrieben werden, um den Inhalt des Elements zu übersetzen: ```latte -

Order

+

Bestellung

``` From cfaa617f6424b05062c4201ec2b7ba923d7ac8ae Mon Sep 17 00:00:00 2001 From: David Grudl Date: Sun, 24 Nov 2024 15:36:05 +0100 Subject: [PATCH 2/5] smartobject: info about PHP 8.4 --- utils/bg/smartobject.texy | 180 +++++++++++++++++++------------------ utils/cs/smartobject.texy | 142 +++++++++++++++-------------- utils/de/smartobject.texy | 182 +++++++++++++++++++------------------ utils/el/smartobject.texy | 174 ++++++++++++++++++------------------ utils/en/smartobject.texy | 158 ++++++++++++++++---------------- utils/es/smartobject.texy | 182 +++++++++++++++++++------------------ utils/fr/smartobject.texy | 182 +++++++++++++++++++------------------ utils/hu/smartobject.texy | 176 ++++++++++++++++++------------------ utils/it/smartobject.texy | 170 ++++++++++++++++++----------------- utils/pl/smartobject.texy | 174 ++++++++++++++++++------------------ utils/pt/smartobject.texy | 180 +++++++++++++++++++------------------ utils/ro/smartobject.texy | 174 ++++++++++++++++++------------------ utils/ru/smartobject.texy | 183 +++++++++++++++++++------------------- utils/sl/smartobject.texy | 176 ++++++++++++++++++------------------ utils/tr/smartobject.texy | 180 +++++++++++++++++++------------------ utils/uk/smartobject.texy | 180 +++++++++++++++++++------------------ 16 files changed, 1428 insertions(+), 1365 deletions(-) diff --git a/utils/bg/smartobject.texy b/utils/bg/smartobject.texy index 9e32435002..76466e6529 100644 --- a/utils/bg/smartobject.texy +++ b/utils/bg/smartobject.texy @@ -2,28 +2,73 @@ SmartObject *********** .[perex] -SmartObject поправяше поведението на обектите по много начини, но днешният PHP вече включва повечето от тези подобрения. Въпреки това той все още добавя поддръжка за *собственост*. +SmartObject подобряваше поведението на обектите в PHP в продължение на много години. От версия PHP 8.4 всички негови функции са вече вградена част от самия PHP, с което завършва историческата му мисия да бъде пионер на модерния обектно-ориентиран подход в PHP. -Настройка: +Инсталация: ```shell composer require nette/utils ``` +SmartObject се появи през 2007 година като революционно решение на недостатъците на обектния модел на PHP по това време. Когато PHP страдаше от редица проблеми с обектно-ориентирания дизайн, той донесе значителни подобрения и опрости работата на разработчиците. Превърна се в легендарна част от Nette framework. Предлагаше функционалност, която PHP щеше да получи едва години по-късно - от валидация на достъпа до свойствата на обектите до усъвършенствана обработка на грешки. С появата на PHP 8.4 завърши своята историческа мисия, тъй като всичките му функции станаха вградена част от езика. Изпревари развитието на PHP със забележителни 17 години. -Свойства, getteri и setteri .[#toc-properties-getters-and-setters] -================================================================== +SmartObject премина през интересна техническа еволюция. Първоначално беше реализиран като клас `Nette\Object`, от който другите класове наследяваха необходимата функционалност. Значителна промяна настъпи с PHP 5.4, който въведе поддръжка на traits. Това позволи трансформацията в trait `Nette\SmartObject`, което донесе по-голяма гъвкавост - разработчиците можеха да използват функционалността дори в класове, които вече наследяваха от друг клас. Докато оригиналният клас `Nette\Object` престана да съществува с PHP 7.2 (който забрани именуването на класове с думата 'Object'), trait-ът `Nette\SmartObject` продължава да съществува. -В съвременните обектно-ориентирани езици (напр. C#, Python, Ruby, JavaScript) терминът *собственост* се отнася до [специални членове на класа |https://en.wikipedia.org/wiki/Property_(programming)], които изглеждат като променливи, но всъщност са представени като методи. Когато се присвоява или чете стойността на такава "променлива", се извиква съответният метод (наречен getter или setter). Това е много удобно, тъй като ни дава пълен контрол върху достъпа до променливите. Можем да проверяваме входни данни или да генерираме резултати само когато свойството е прочетено. +Нека разгледаме функциите, които `Nette\Object` и по-късно `Nette\SmartObject` предлагаха. Всяка от тези функции представляваше значителна стъпка напред в областта на обектно-ориентираното програмиране в PHP. -PHP свойствата не се поддържат, но чертите `Nette\SmartObject` могат да ги симулират. Как да го използвате? -- Добавяне на анотация към класа под формата на `@property $xyz` -- Създайте getter с име `getXyz()` или `isXyz()`, setter с име `setXyz()` -- Getter и setter трябва да са *публични* или *защитени* и незадължителни, така че може да има свойство *само за четене* или *само за писане*. +Последователни състояния на грешките +------------------------------------ +Един от най-сериозните проблеми на ранния PHP беше непоследователното поведение при работа с обекти. `Nette\Object` внесе ред и предвидимост в този хаос. Нека видим как се държеше PHP първоначално: -Ще използваме свойството за класа Circle, за да гарантираме, че в променливата `$radius` се поставят само неотрицателни числа. Заменете `public $radius` с имота: +```php +echo $obj->undeclared; // E_NOTICE, по-късно E_WARNING +$obj->undeclared = 1; // минава тихо без предупреждение +$obj->unknownMethod(); // Fatal error (неуловим с try/catch) +``` + +Fatal error прекратяваше приложението без възможност за реакция. Тихото записване в несъществуващи членове без предупреждение можеше да доведе до сериозни грешки, които бяха трудни за откриване. `Nette\Object` улавяше всички тези случаи и хвърляше изключение `MemberAccessException`, което позволяваше на програмистите да реагират и да обработват тези грешки: + +```php +echo $obj->undeclared; // хвърля Nette\MemberAccessException +$obj->undeclared = 1; // хвърля Nette\MemberAccessException +$obj->unknownMethod(); // хвърля Nette\MemberAccessException +``` + +От PHP 7.0 езикът вече не причинява неуловими fatal error, а от PHP 8.2 достъпът до недекларирани членове се счита за грешка. + + +"Did you mean?" Помощник +------------------------ +`Nette\Object` дойде с много удобна функция: интелигентни предложения при печатни грешки. Когато разработчик допуснеше грешка в името на метод или променлива, той не само съобщаваше за грешката, но и предлагаше помощ чрез предложение за правилното име. Това иконично съобщение, известно като "did you mean?", спести на програмистите часове търсене на печатни грешки: + +```php +class Foo extends Nette\Object +{ + public static function from($var) + { + } +} + +$foo = Foo::form($var); +// хвърля Nette\MemberAccessException +// "Call to undefined static method Foo::form(), did you mean from()?" +``` + +Въпреки че PHP няма собствена форма на "did you mean?", тази функция сега се предоставя от [Tracy|tracy:]. Той може дори да [поправя автоматично|tracy:open-files-in-ide#demos] такива грешки. + + +Properties с контролиран достъп +------------------------------- +Значителна иновация, която SmartObject донесе в PHP, бяха properties с контролиран достъп. Този концепт, обичаен в езици като C# или Python, позволи на разработчиците елегантно да контролират достъпа до данните на обекта и да осигуряват тяхната консистентност. Properties са мощен инструмент на обектно-ориентираното програмиране. Те функционират като променливи, но всъщност са представени чрез методи (getters и setters). Това позволява валидация на входа или генериране на стойности в момента на четене. + +За да използвате properties, трябва да: +- Добавите анотация `@property $xyz` към класа +- Създадете getter с име `getXyz()` или `isXyz()`, setter с име `setXyz()` +- Осигурите getter и setter да са *public* или *protected*. Те са опционални - следователно могат да съществуват като *read-only* или *write-only* properties + +Нека разгледаме практически пример с класа Circle, където ще използваме properties, за да гарантираме, че радиусът винаги е неотрицателно число. Ще заменим `public $radius` с property: ```php /** @@ -34,22 +79,22 @@ class Circle { use Nette\SmartObject; - private float $radius = 0.0; // не е публичен + private float $radius = 0.0; // не е public! - // getter за свойството $radius + // getter за property $radius protected function getRadius(): float { return $this->radius; } - // setter за свойството $radius + // setter за property $radius protected function setRadius(float $radius): void { - // обработване на стойността, преди да я запишем + // санитизираме стойността преди записване $this->radius = max(0.0, $radius); } - // getter за свойството $visible + // getter за property $visible protected function isVisible(): bool { return $this->radius > 0; @@ -57,69 +102,30 @@ class Circle } $circle = new Circle; -$circle->radius = 10; // всъщност се извиква setRadius(10) -echo $circle->radius; // извиква getRadius() +$circle->radius = 10; // всъщност извиква setRadius(10) +echo $circle->radius; // извиква getRadius() echo $circle->visible; // извиква isVisible() ``` -Свойствата са преди всичко "синтактична захар" и са предназначени да направят живота на програмиста по-сладък, като опростят кода. Ако нямате нужда от тях, не е нужно да ги използвате. - - -Поглед към историята .[#toc-a-glimpse-into-history] -=================================================== - -SmartObject усъвършенстваше поведението на обектите по множество начини, но днес PHP вече включва повечето от тези подобрения на роден език. Следващият текст е носталгичен поглед назад към историята, който ни напомня как са се развивали нещата. - -От самото си създаване обектният модел на PHP страдаше от множество сериозни недостатъци и пропуски. Това доведе до създаването на класа `Nette\Object` (през 2007 г.), който имаше за цел да поправи тези проблеми и да повиши удобството при използването на PHP. Всичко, което беше необходимо, беше други класове да наследят от него и да получат предимствата, които той предлагаше. Когато PHP 5.4 въведе поддръжка на черти, класът `Nette\Object` беше заменен с чертата `Nette\SmartObject`. Това премахна необходимостта от наследяване от общ предшественик. Освен това чертата можеше да се използва в класове, които вече наследяваха от друг клас. Окончателният край на `Nette\Object` настъпи с излизането на PHP 7.2, който забрани на класовете да се наричат `Object`. - -С развитието на PHP обектният модел и възможностите на езика се усъвършенстваха. Различните функции на класа `SmartObject` станаха излишни. След излизането на PHP 8.2 остана само една функция, която не се поддържа директно в PHP: възможността да се използват така наречените [свойства |#Properties, getters, and setters]. - -Какви функции предлагаха `Nette\Object` и, като следствие, `Nette\SmartObject`? Ето един преглед. (В примерите е използван класът `Nette\Object`, но повечето функции се отнасят и за признака `Nette\SmartObject` ). - - -Непоследователни грешки .[#toc-inconsistent-errors] ---------------------------------------------------- -PHP имаше непоследователно поведение при достъп до недекларирани членове. Към момента на публикуване на `Nette\Object` статусът е следният: - -```php -echo $obj->undeclared; // E_NOTICE, по-късно E_WARNING -$obj->undeclared = 1; // преминава безшумно, без да съобщава -$obj->unknownMethod(); // Фатална грешка (която не може да бъде уловена чрез try/catch) -``` - -Фатална грешка ще прекрати приложението без възможност за реакция. Тихото записване на несъществуващи членове без предупреждение можеше да доведе до сериозни грешки, които трудно се откриваха. `Nette\Object` Всички тези случаи бяха уловени и беше хвърлено изключение на адрес `MemberAccessException`. - -```php -echo $obj->undeclared; // throw Nette\MemberAccessException -$obj->undeclared = 1; // throw Nette\MemberAccessException -$obj->unknownMethod(); // throw Nette\MemberAccessException -``` -От PHP 7.0 PHP вече не причинява фатални грешки, които не могат да бъдат прихванати, а достъпът до необявени членове е грешка от PHP 8.2 насам. - - -Какво имаш предвид? .[#toc-did-you-mean] ----------------------------------------- -Ако се появи грешка в `Nette\MemberAccessException`, вероятно поради печатна грешка при достъп до променлива на обект или извикване на метод, `Nette\Object` се опитва да подскаже в съобщението за грешка как да се поправи грешката под формата на емблематичното допълнение "Искахте ли да кажете?". +От PHP 8.4 същата функционалност може да бъде постигната чрез property hooks, които предлагат много по-елегантен и кратък синтаксис: ```php -class Foo extends Nette\Object +class Circle { - public static function from($var) - { + public float $radius = 0.0 { + set => max(0.0, $value); } -} -$foo = Foo::form($var); -// throw Nette\MemberAccessException -// "Call to undefined static method Foo::form(), did you mean from()?" + public bool $visible { + get => $this->radius > 0; + } +} ``` -Въпреки че днешният PHP не разполага с функция "Искахте ли да кажете?", тази фраза може да бъде добавена към грешките от [Tracy |tracy:]. Тя дори може да [коригира такива грешки автоматично |tracy:open-files-in-ide#toc-demos]. - -Методи за разширение .[#toc-extension-methods] ----------------------------------------------- -Вдъхновено от методите за разширение от C#. Те ви позволяват да добавяте нови методи към съществуващи класове. Например можете да добавите метод `addDateTime()` към формуляр, за да добавите свой собствен DateTimePicker. +Extension Methods +----------------- +`Nette\Object` донесе в PHP друг интересен концепт, вдъхновен от модерните програмни езици - extension methods. Тази функция, заимствана от C#, позволи на разработчиците елегантно да разширяват съществуващите класове с нови методи без да ги модифицират или наследяват. Например, можехте да добавите метод `addDateTime()` към формуляр, който добавя персонализиран DateTimePicker: ```php Form::extensionMethod( @@ -131,22 +137,22 @@ $form = new Form; $form->addDateTime('date'); ``` -Методите за разширение се оказаха непрактични, тъй като имената им не се попълваха автоматично от редакторите, а вместо това те съобщаваха, че методът не съществува. Поради това тяхната подкрепа беше преустановена. +Extension методите се оказаха непрактични, защото редакторите не предлагаха техните имена и вместо това съобщаваха, че методът не съществува. Затова тяхната поддръжка беше прекратена. Днес е по-често срещано да се използва композиция или наследяване за разширяване на функционалността на класовете. -Получаване на името на класа .[#toc-getting-the-class-name] ------------------------------------------------------------ +Получаване на името на класа +---------------------------- +SmartObject предлагаше прост метод за получаване на името на класа: ```php -$class = $obj->getClass(); // използване на Nette\Object -$class = $obj::class; // от PHP 8.0 +$class = $obj->getClass(); // чрез Nette\Object +$class = $obj::class; // от PHP 8.0 ``` -Достъп до рефлексии и анотации .[#toc-access-to-reflection-and-annotations] ---------------------------------------------------------------------------- - -`Nette\Object` Достъп до размишленията и анотациите чрез методите `getReflection()` и `getAnnotation()`: +Достъп до рефлексия и анотации +------------------------------ +`Nette\Object` предоставяше достъп до рефлексия и анотации чрез методите `getReflection()` и `getAnnotation()`. Този подход значително опрости работата с мета-информация на класовете: ```php /** @@ -161,7 +167,7 @@ $reflection = $obj->getReflection(); $reflection->getAnnotation('author'); // връща 'John Doe' ``` -От версия 8.0 на PHP вече е възможен достъп до метаинформация под формата на атрибути: +От PHP 8.0 е възможно да се достъпва до мета-информация чрез атрибути, които предлагат още повече възможности и по-добра проверка на типовете: ```php #[Author('John Doe')] @@ -175,10 +181,9 @@ $reflection->getAttributes(Author::class)[0]; ``` -Получатели на методи .[#toc-method-getters] -------------------------------------------- - -`Nette\Object` предлагат елегантен начин за работа с методите, сякаш са променливи: +Method Getters +-------------- +`Nette\Object` предлагаше елегантен начин за предаване на методи, като че ли са променливи: ```php class Foo extends Nette\Object @@ -194,7 +199,7 @@ $method = $obj->adder; echo $method(2, 3); // 5 ``` -От версия 8.1 на PHP можете да използвате така наречения "синтаксис на извикване на метод от първи клас":https://www.php.net/manual/en/functions.first_class_callable_syntax: +От PHP 8.1 можете да използвате така наречения "first-class callable syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax, който развива този концепт още по-нататък: ```php $obj = new Foo; @@ -203,10 +208,9 @@ echo $method(2, 3); // 5 ``` -Събития .[#toc-events] ----------------------- - -`Nette\Object` предлага синтактична захар за задействане на [събитие |nette:glossary#events]: +Събития +------- +SmartObject предлага опростен синтаксис за работа със [събития|nette:glossary#events]. Събитията позволяват на обектите да информират други части на приложението за промени в тяхното състояние: ```php class Circle extends Nette\Object @@ -221,7 +225,7 @@ class Circle extends Nette\Object } ``` -Кодът `$this->onChange($this, $radius)` е еквивалентен на следното: +Кодът `$this->onChange($this, $radius)` е еквивалентен на следния цикъл: ```php foreach ($this->onChange as $callback) { @@ -229,7 +233,7 @@ foreach ($this->onChange as $callback) { } ``` -За по-голяма яснота препоръчваме да избягвате магическия метод `$this->onChange()`. Добър заместител би бил [Nette\Utils\Arrays::invoke: |arrays#invoke] +За по-голяма яснота препоръчваме да избягвате магическия метод `$this->onChange()`. Практична замяна е функцията [Nette\Utils\Arrays::invoke|arrays#invoke]: ```php Nette\Utils\Arrays::invoke($this->onChange, $this, $radius); diff --git a/utils/cs/smartobject.texy b/utils/cs/smartobject.texy index 7aeca5b7b2..93526bd1b5 100644 --- a/utils/cs/smartobject.texy +++ b/utils/cs/smartobject.texy @@ -2,7 +2,7 @@ SmartObject *********** .[perex] -SmartObject opravovala chování objektů v mnoha směrech, ale dnešní PHP již obsahuje většinu vylepšení nativně. Stále však přidává podporu pro tzv. *property*. +SmartObject po léta vylepšoval chování objektů v PHP. Od verze PHP 8.4 jsou již všechny jeho funkce součástí samotného PHP, čímž završil svou historickou misi být průkopníkem moderního objektového přístupu v PHP. Instalace: @@ -11,19 +11,64 @@ Instalace: composer require nette/utils ``` +SmartObject vznikl v roce 2007 jako revoluční řešení nedostatků tehdejšího objektového modelu PHP. V době, kdy PHP trpělo řadou problémů s objektovým návrhem, přinesl výrazné vylepšení a zjednodušení práce pro vývojáře. Stal se legendární součástí frameworku Nette. Nabízel funkcionalitu, kterou PHP získalo až o mnoho let později - od kontrolu přístupu k vlastnostem objektů až po sofistikované syntaktické cukrátka. S příchodem PHP 8.4 završil svou historickou misi, protože všechny jeho funkce se staly nativní součástí jazyka. Předběhl vývoj PHP o pozoruhodných 17 let. -Properties, gettery a settery -============================= +Technicky prošel SmartObject zajímavým vývojem. Původně byl implementován jako třída `Nette\Object`, od které ostatní třídy dědily potřebnou funkcionalitu. Zásadní změna přišla s PHP 5.4, které přineslo podporu trait. To umožnilo transformaci do podoby traity `Nette\SmartObject`, což přineslo větší flexibilitu - vývojáři mohli funkcionalitu využít i ve třídách, které již dědily od jiné třídy. Zatímco původní třída `Nette\Object` zanikla s příchodem PHP 7.2 (které zakázalo pojmenování tříd slovem `Object`), traita `Nette\SmartObject` žije dál. -Termínem *property* (česky vlastnost) se v moderních objektově orientovaných jazycích (např. C#, Python, Ruby, JavaScript) označují [speciální členy tříd|https://en.wikipedia.org/wiki/Property_(programming)], které se tváří jako proměnné, ale ve skutečnosti jsou reprezentovány metodami. Při přiřazení nebo čtení hodnoty této „proměnné“ se zavolá příslušná metoda (tzv. getter nebo setter). Jde o velice šikovnou věc, díky ní máme přístup k proměnným plně pod kontrolou. Můžeme tak validovat vstupy nebo generovat výsledky až ve chvíli, kdy se property čte. +Pojďme si projít vlastnosti, které kdysi `Nette\Object` a později `Nette\SmartObject` nabízeli. Každá z těchto funkcí ve své době představovala významný krok vpřed v oblasti objektově orientovaného programování v PHP. -PHP property nepodporují, ale traita `Nette\SmartObject` je umí imitovat. Jak na to? -- Přidejte třídě anotaci ve tvaru `@property $xyz` -- Vytvořte getter s názvem `getXyz()` nebo `isXyz()`, setter s názvem `setXyz()` -- Getter a setter musí být *public* nebo *protected* a jsou volitelné, mohou tedy existovat *read-only* nebo *write-only* property +Konzistentní chybové stavy +-------------------------- +Jedním z nejpalčivějších problémů raného PHP bylo nekonzistentní chování při práci s objekty. `Nette\Object` přinesl do tohoto chaosu řád a předvídatelnost. Podívejme se, jak vypadalo původní chování PHP: -Property využijeme u třídy Circle, abychom zajistili, že do proměnné `$radius` se dostanou jen nezáporná čísla. Nahradíme `public $radius` za property: +```php +echo $obj->undeclared; // E_NOTICE, později E_WARNING +$obj->undeclared = 1; // projde tiše bez hlášení +$obj->unknownMethod(); // Fatal error (nezachytitelný pomocí try/catch) +``` + +Fatal error ukončil aplikaci bez možnosti jakkoliv reagovat. Tichý zápis do neexistujících členů bez upozornění mohl vést k závažným chybám, které šly obtížné odhalit. `Nette\Object` všechny tyto případy zachytával a vyhazoval výjimku `MemberAccessException`, což umožnilo programátorům na chyby reagovat a řešit je. + +```php +echo $obj->undeclared; // vyhodí Nette\MemberAccessException +$obj->undeclared = 1; // vyhodí Nette\MemberAccessException +$obj->unknownMethod(); // vyhodí Nette\MemberAccessException +``` + +Od PHP 7.0 již jazyk nezpůsobuje nezachytitelné fatal error a od PHP 8.2 je přístup k nedeklarovaným členům považován za chybu. + + +Nápověda "Did you mean?" +------------------------ +`Nette\Object` přišel s velmi příjemnou funkcí: inteligentní nápovědou při překlepech. Když vývojář udělal chybu v názvu metody nebo proměnné, nejen oznámil chybu, ale také nabídl pomocnou ruku v podobě návrhu správného názvu. Tato ikonická hláška, známá jako "did you mean?", ušetřila programátorům hodiny hledání překlepů: + +```php +class Foo extends Nette\Object +{ + public static function from($var) + { + } +} + +$foo = Foo::form($var); +// vyhodí Nette\MemberAccessException +// "Call to undefined static method Foo::form(), did you mean from()?" +``` + +Dnešní PHP sice nemá žádnou podobu „did you mean?“, ale tento dovětek umí do chyb doplňovat [Tracy|tracy:]. A dokonce takové chyby i [samo opravovat |tracy:open-files-in-ide#Ukázky]. + + +Properties s kontrolovaným přístupem +------------------------------------ +Významnou inovací, kterou SmartObject přinesl do PHP, byly properties s kontrolovaným přístupem. Tento koncept, běžný v jazycích jako C# nebo Python, umožnil vývojářům elegantně kontrolovat přístup k datům objektu a zajistit jejich konzistenci. Properties jsou mocným nástrojem objektově orientovaného programování. Fungují jako proměnné, ale ve skutečnosti jsou reprezentovány metodami (gettery a settery). To umožňuje validovat vstupy nebo generovat hodnoty až v momentě čtení. + +Pro používání properties musíte: +- Přidat třídě anotaci ve tvaru `@property $xyz` +- Vytvořit getter s názvem `getXyz()` nebo `isXyz()`, setter s názvem `setXyz()` +- Zajistit, aby getter a setter byly *public* nebo *protected*. Jsou volitelné - mohou tedy existovat jako *read-only* nebo *write-only* property + +Ukažme si praktický příklad na třídě Circle, kde properties využijeme k zajištění, že poloměr bude vždy nezáporné číslo. Nahradíme původní `public $radius` za property: ```php /** @@ -62,64 +107,25 @@ echo $circle->radius; // volá getRadius() echo $circle->visible; // volá isVisible() ``` -Properties jsou především "syntaktickým cukříkem"((syntactic sugar)), jehož smyslem je zpřehlednit kód a osladit tak programátorovi život. Pokud nechcete, nemusíte je používat. - - -Pohled do historie -================== - -SmartObject opravovala chování objektů v mnoha směrech, ale dnešní PHP již obsahuje většinu vylepšení nativně. Následující text je tak nostalgickým pohledem do historie a připomínkou toho, jak se věci vyvíjely. - -Objektový model PHP trpěl od počátku celou řadou vážných nedostatků a necnostní. To byl důvod vzniku třídy `Nette\Object` (v roce 2007), která se je pokoušela napravovat a zlepšit komfort při používání PHP. Stačilo, aby ostatní třídy od ní dědily, a získaly výhody, které přinášela. Když PHP 5.4 přišlo s podporou trait, byla třída `Nette\Object` nahrazena traitou `Nette\SmartObject`. Nebylo tak nutné už dědit od společného předka. Navíc traita se dala použít i ve třídách, které již dědily od jiné třídy. Definitivní konec `Nette\Object` přišel s vydáním PHP 7.2, které zakázalo třídám jmenovat se `Object`. - -Jak šel vývoj PHP dál, objektový model a schopnosti jazyka se vylepšovaly. Jednotlivé funkce třídy `SmartObject` se stávaly zbytečnými. Od vydání PHP 8.2 zůstala jediná feature, která ještě není v PHP přímo podporována, a to možnost používat tzv. [property|#Properties, gettery a settery]. - -Jaké vlastnosti kdysi `Nette\Object` a potažmo `Nette\Object` nabízely? Nabízíme přehled. (V ukázkách se používá třída `Nette\Object`, ale většina vlastnosti se týká i traity `Nette\SmartObject`). - - -Nekonzistentní chyby --------------------- -PHP mělo nekonzistentní chování při přístupu k nedeklarovaným členům. Stav v době vzniku `Nette\Object` byl následující: - -```php -echo $obj->undeclared; // E_NOTICE, později E_WARNING -$obj->undeclared = 1; // projde tiše bez hlášení -$obj->unknownMethod(); // Fatal error (nezachytitelný pomocí try/catch) -``` - -Fatal error ukončil aplikaci bez možnosti jakkoliv reagovat. Tichý zápis do neexistujících členů bez upozornění mohl vést k závažným chybám, které šly obtížné odhalit. `Nette\Object` všechny tyto případy zachytával a vyhazoval výjimku `MemberAccessException`. +Od PHP 8.4 lze dosáhnout stejné funkcionality pomocí property hooks, které nabízí mnohem elegantnější a stručnější syntaxi: ```php -echo $obj->undeclared; // vyhodí Nette\MemberAccessException -$obj->undeclared = 1; // vyhodí Nette\MemberAccessException -$obj->unknownMethod(); // vyhodí Nette\MemberAccessException -``` -PHP od verze PHP 7.0 už nezachytitelné fatal error nezpůsobuje a přístup k nedeklarovaným členům se stává chybou od PHP 8.2. - - -Did you mean? -------------- -Pokud došlo k vyhození chyby `Nette\MemberAccessException`, třeba z důvodu překlepu při přístupu k proměnné objektu nebo volání metody, pokusilo se `Nette\Object` v chybové hlášce napovědět, jak chybu opravit, a to v podobě ikonického dovětku „did you mean?“. - -```php -class Foo extends Nette\Object +class Circle { - public static function from($var) - { + public float $radius = 0.0 { + set => max(0.0, $value); } -} -$foo = Foo::form($var); -// vyhodí Nette\MemberAccessException -// "Call to undefined static method Foo::form(), did you mean from()?" + public bool $visible { + get => $this->radius > 0; + } +} ``` -Dnešní PHP sice nemá žádnou podobu „did you mean?“, ale tento dovětek umí do chyb doplňovat [Tracy|tracy:]. A dokonce takové chyby i [samo opravovat |tracy:open-files-in-ide#Ukázky]. - Extension methods ----------------- -Inspirací byly extension methods z jazyka C#. Dávaly možnost do existujících tříd přidávat nové metody. Třeba jste si mohli do formuláře přidat metodu `addDateTime()`, která přidá vlastní DateTimePicker. +`Nette\Object` přinesl do PHP další zajímavý koncept inspirovaný moderními programovacími jazyky - extension methods. Tato funkce, převzatá z C#, umožnila vývojářům elegantně rozšiřovat existující třídy o nové metody bez nutnosti je upravovat nebo od nich dědit. Třeba jste si mohli do formuláře přidat metodu `addDateTime()`, která přidá vlastní DateTimePicker: ```php Form::extensionMethod( @@ -131,11 +137,12 @@ $form = new Form; $form->addDateTime('date'); ``` -Extension metody se ukázaly jako nepraktické, protože jejich názvy nenapovídaly editory, naopak hlásily, že metoda neexistuje. Proto byla jejich podpora ukončena. +Extension metody se ukázaly jako nepraktické, protože jejich názvy nenapovídaly editory, naopak hlásily, že metoda neexistuje. Proto byla jejich podpora ukončena. Dnes je běžnější využívat kompozici nebo dědičnost pro rozšíření funkcionality tříd. -Zjištění názvu třídy: ---------------------- +Zjištění názvu třídy +-------------------- +Pro zjištění názvu třídy nabízel SmartObject jednoduchou metodu: ```php $class = $obj->getClass(); // pomocí Nette\Object @@ -143,10 +150,9 @@ $class = $obj::class; // od PHP 8.0 ``` -Přístup k reflexi a anotacem +Přístup k reflexi a anotacím ---------------------------- - -`Nette\Object` nabízel přístup k reflexi a anotacím pomocí metod `getReflection()` a `getAnnotation()`: +`Nette\Object` nabízel přístup k reflexi a anotacím pomocí metod `getReflection()` a `getAnnotation()`. Tento přístup významně zjednodušil práci s metainformacemi tříd: ```php /** @@ -161,7 +167,7 @@ $reflection = $obj->getReflection(); $reflection->getAnnotation('author'); // vrátí 'John Doe' ``` -Od PHP 8.0 je možné přistupovat k metainformacím v podobě atributů: +Od PHP 8.0 je možné přistupovat k metainformacím v podobě atributů, které nabízí ještě větší možnosti a lepší typovou kontrolu: ```php #[Author('John Doe')] @@ -177,7 +183,6 @@ $reflection->getAttributes(Author::class)[0]; Method gettery -------------- - `Nette\Object` nabízel elegantní způsob, jak předávat metody jako kdyby šlo o proměnné: ```php @@ -194,7 +199,7 @@ $method = $obj->adder; echo $method(2, 3); // 5 ``` -Od PHP 8.1 je možné využít tzv. "first-class callable syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax: +Od PHP 8.1 je možné využít tzv. "first-class callable syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax, která tento koncept posouvá ještě dál: ```php $obj = new Foo; @@ -205,8 +210,7 @@ echo $method(2, 3); // 5 Události -------- - -`Nette\Object` nabízel syntaktický cukr pro vyvolání [události|nette:glossary#události]: +SmartObject nabízí zjednodušenou syntax pro práci s [událostmi|nette:glossary#události]. Události umožňují objektům informovat ostatní části aplikace o změnách svého stavu: ```php class Circle extends Nette\Object @@ -221,7 +225,7 @@ class Circle extends Nette\Object } ``` -Kód `$this->onChange($this, $radius)` je ekvivalentní následujícímu: +Kód `$this->onChange($this, $radius)` je ekvivalentní následujícímu cyklu: ```php foreach ($this->onChange as $callback) { diff --git a/utils/de/smartobject.texy b/utils/de/smartobject.texy index 65643bc2e0..a8edf977a8 100644 --- a/utils/de/smartobject.texy +++ b/utils/de/smartobject.texy @@ -2,7 +2,7 @@ SmartObject *********** .[perex] -SmartObject hat das Verhalten von Objekten in vielerlei Hinsicht verbessert, aber das heutige PHP enthält die meisten dieser Verbesserungen bereits von Haus aus. Es fügt jedoch noch Unterstützung für *Property* hinzu. +SmartObject verbesserte jahrelang das Verhalten von Objekten in PHP. Seit PHP 8.4 sind alle seine Funktionen nativ in PHP selbst integriert, womit er seine historische Mission als Wegbereiter des modernen objektorientierten Ansatzes in PHP erfüllt hat. Installation: @@ -11,19 +11,64 @@ Installation: composer require nette/utils ``` +SmartObject entstand 2007 als revolutionäre Lösung für die Mängel des damaligen PHP-Objektmodells. In einer Zeit, als PHP unter zahlreichen Problemen mit objektorientiertem Design litt, brachte er bedeutende Verbesserungen und vereinfachte die Arbeit der Entwickler. Er wurde zu einem legendären Bestandteil des Nette Frameworks. Er bot Funktionalitäten, die PHP erst Jahre später erhielt - von der Validierung des Eigenschaftszugriffs bis hin zur ausgefeilten Fehlerbehandlung. Mit der Einführung von PHP 8.4 hat er seine historische Mission erfüllt, da alle seine Funktionen zu nativen Bestandteilen der Sprache wurden. SmartObject war der PHP-Entwicklung um bemerkenswerte 17 Jahre voraus. -Eigenschaften, Getters und Setters .[#toc-properties-getters-and-setters] -========================================================================= +SmartObject durchlief eine interessante technische Entwicklung. Ursprünglich wurde er als Klasse `Nette\Object` implementiert, von der andere Klassen die benötigte Funktionalität erbten. Eine wesentliche Änderung kam mit PHP 5.4, das Trait-Unterstützung einführte. Dies ermöglichte die Umwandlung in den `Nette\SmartObject` Trait, was größere Flexibilität brachte - Entwickler konnten die Funktionalität auch in Klassen nutzen, die bereits von einer anderen Klasse erbten. Während die ursprüngliche `Nette\Object`-Klasse mit PHP 7.2 verschwand (das die Benennung von Klassen mit dem Wort 'Object' verbot), lebt der `Nette\SmartObject` Trait weiter. -In modernen objektorientierten Sprachen (z. B. C#, Python, Ruby, JavaScript) bezieht sich der Begriff *Eigenschaft* auf [spezielle Mitglieder von Klassen |https://en.wikipedia.org/wiki/Property_(programming)], die wie Variablen aussehen, aber eigentlich durch Methoden repräsentiert werden. Wenn der Wert dieser "Variablen" zugewiesen oder gelesen wird, wird die entsprechende Methode (Getter oder Setter genannt) aufgerufen. Das ist sehr praktisch, denn es gibt uns die volle Kontrolle über den Zugriff auf Variablen. Wir können die Eingabe validieren oder Ergebnisse nur dann erzeugen, wenn die Eigenschaft gelesen wird. +Schauen wir uns die Funktionen an, die `Nette\Object` und später `Nette\SmartObject` anboten. Jede dieser Funktionen stellte zu ihrer Zeit einen bedeutenden Fortschritt in der objektorientierten Programmierung in PHP dar. -PHP-Eigenschaften werden nicht unterstützt, aber Trait `Nette\SmartObject` kann sie imitieren. Wie verwendet man es? -- Fügen Sie der Klasse eine Annotation in der Form `@property $xyz` -- Erstellen Sie einen Getter namens `getXyz()` oder `isXyz()`, einen Setter namens `setXyz()` -- Die Getter und Setter müssen *public* oder *protected* sein und sind optional, d.h. es kann eine *read-only* oder *write-only* Eigenschaft geben +Konsistente Fehlerzustände +-------------------------- +Eines der größten Probleme des frühen PHP war das inkonsistente Verhalten bei der Arbeit mit Objekten. `Nette\Object` brachte Ordnung und Vorhersehbarkeit in dieses Chaos. Betrachten wir das ursprüngliche PHP-Verhalten: -Wir werden die Eigenschaft für die Klasse Circle verwenden, um sicherzustellen, dass nur nicht-negative Zahlen in die Variable `$radius` eingegeben werden. Ersetzen Sie `public $radius` durch property: +```php +echo $obj->undeclared; // E_NOTICE, später E_WARNING +$obj->undeclared = 1; // läuft still durch ohne Warnung +$obj->unknownMethod(); // Fatal error (nicht abfangbar mit try/catch) +``` + +Fatal Error beendete die Anwendung ohne Möglichkeit zu reagieren. Stilles Schreiben in nicht existierende Mitglieder ohne Warnung konnte zu schwerwiegenden Fehlern führen, die schwer zu erkennen waren. `Nette\Object` fing all diese Fälle ab und warf eine `MemberAccessException`, was Programmierern ermöglichte, auf Fehler zu reagieren: + +```php +echo $obj->undeclared; // wirft Nette\MemberAccessException +$obj->undeclared = 1; // wirft Nette\MemberAccessException +$obj->unknownMethod(); // wirft Nette\MemberAccessException +``` + +Seit PHP 7.0 verursacht die Sprache keine nicht abfangbaren Fatal Errors mehr, und seit PHP 8.2 wird der Zugriff auf nicht deklarierte Mitglieder als Fehler betrachtet. + + +"Did you mean?" Hilfe +--------------------- +`Nette\Object` kam mit einer sehr praktischen Funktion: intelligenten Vorschlägen bei Tippfehlern. Wenn ein Entwickler einen Fehler im Namen einer Methode oder Variable machte, wurde nicht nur der Fehler gemeldet, sondern auch eine Hilfestellung in Form eines Vorschlags für den richtigen Namen angeboten. Diese ikonische Meldung, bekannt als "did you mean?", ersparte Programmierern stundenlange Suche nach Tippfehlern: + +```php +class Foo extends Nette\Object +{ + public static function from($var) + { + } +} + +$foo = Foo::form($var); +// wirft Nette\MemberAccessException +// "Call to undefined static method Foo::form(), did you mean from()?" +``` + +Während PHP selbst keine Form von "did you mean?" hat, wird diese Funktion jetzt von [Tracy|tracy:] bereitgestellt. Es kann solche Fehler sogar [automatisch korrigieren|tracy:open-files-in-ide#demos]. + + +Properties mit kontrolliertem Zugriff +------------------------------------- +Eine bedeutende Innovation, die SmartObject in PHP einführte, waren Properties mit kontrolliertem Zugriff. Dieses Konzept, das in Sprachen wie C# oder Python üblich ist, ermöglichte Entwicklern eine elegante Kontrolle über den Zugriff auf Objektdaten und deren Konsistenz. Properties sind ein mächtiges Werkzeug der objektorientierten Programmierung. Sie funktionieren wie Variablen, werden aber tatsächlich durch Methoden (Getter und Setter) repräsentiert. Dies ermöglicht die Validierung von Eingaben oder die Generierung von Werten zum Zeitpunkt des Lesens. + +Für die Verwendung von Properties müssen Sie: +- Der Klasse die Annotation `@property $xyz` hinzufügen +- Einen Getter mit Namen `getXyz()` oder `isXyz()`, einen Setter mit Namen `setXyz()` erstellen +- Sicherstellen, dass Getter und Setter *public* oder *protected* sind. Sie sind optional - können also als *read-only* oder *write-only* Properties existieren + +Schauen wir uns ein praktisches Beispiel an der Circle-Klasse an, wo wir Properties verwenden, um sicherzustellen, dass der Radius immer nicht-negativ ist. Wir ersetzen `public $radius` durch eine Property: ```php /** @@ -34,22 +79,22 @@ class Circle { use Nette\SmartObject; - private float $radius = 0.0; // not public + private float $radius = 0.0; // nicht public! - // getter for property $radius + // Getter für Property $radius protected function getRadius(): float { return $this->radius; } - // setter for property $radius + // Setter für Property $radius protected function setRadius(float $radius): void { - // sanitizing value before saving it + // Wert vor dem Speichern bereinigen $this->radius = max(0.0, $radius); } - // getter for property $visible + // Getter für Property $visible protected function isVisible(): bool { return $this->radius > 0; @@ -57,69 +102,30 @@ class Circle } $circle = new Circle; -$circle->radius = 10; // actually calls setRadius(10) -echo $circle->radius; // calls getRadius() -echo $circle->visible; // calls isVisible() -``` - -Eigenschaften sind in erster Linie "syntaktischer Zucker" ((syntactic sugar)), der das Leben des Programmierers durch Vereinfachung des Codes versüßen soll. Wenn Sie sie nicht wollen, müssen Sie sie nicht verwenden. - - -Ein Blick in die Geschichte .[#toc-a-glimpse-into-history] -========================================================== - -SmartObject verfeinerte das Verhalten von Objekten auf zahlreiche Arten, aber das heutige PHP enthält die meisten dieser Erweiterungen bereits von Haus aus. Der folgende Text ist ein nostalgischer Blick zurück in die Geschichte, der uns daran erinnert, wie sich die Dinge entwickelt haben. - -Seit seinen Anfängen litt das Objektmodell von PHP unter einer Vielzahl von ernsthaften Mängeln und Unzulänglichkeiten. Dies führte zur Schaffung der Klasse `Nette\Object` (im Jahr 2007), die diese Probleme beheben und den Komfort bei der Verwendung von PHP erhöhen sollte. Andere Klassen brauchten nur von dieser Klasse zu erben, um die Vorteile zu nutzen, die sie bot. Als mit PHP 5.4 die Unterstützung für Traits eingeführt wurde, wurde die Klasse `Nette\Object` durch den Trait `Nette\SmartObject` ersetzt. Damit entfiel die Notwendigkeit, von einem gemeinsamen Vorfahren zu erben. Außerdem konnte der Trait in Klassen verwendet werden, die bereits von einer anderen Klasse geerbt hatten. Das endgültige Ende von `Nette\Object` kam mit der Veröffentlichung von PHP 7.2, die es verbot, Klassen den Namen `Object` zu geben. - -Mit der weiteren Entwicklung von PHP wurden das Objektmodell und die Sprachfähigkeiten verbessert. Verschiedene Funktionen der Klasse `SmartObject` wurden überflüssig. Seit der Veröffentlichung von PHP 8.2 gibt es nur noch eine Funktion, die in PHP nicht direkt unterstützt wird: die Möglichkeit, so genannte [Properties |#Properties, getters, and setters] zu verwenden. - -Welche Funktionen boten `Nette\Object` und in der Folge `Nette\SmartObject`? Hier ist ein Überblick. (In den Beispielen wird die Klasse `Nette\Object` verwendet, aber die meisten Funktionen gelten auch für den Trait `Nette\SmartObject` ). - - -Inkonsistente Fehler .[#toc-inconsistent-errors] ------------------------------------------------- -PHP hatte ein inkonsistentes Verhalten beim Zugriff auf nicht deklarierte Mitglieder. Der Zustand zum Zeitpunkt von `Nette\Object` war wie folgt: - -```php -echo $obj->undeclared; // E_NOTICE, later E_WARNING -$obj->undeclared = 1; // passes silently without reporting -$obj->unknownMethod(); // Fatal error (not catchable by try/catch) +$circle->radius = 10; // ruft tatsächlich setRadius(10) auf +echo $circle->radius; // ruft getRadius() auf +echo $circle->visible; // ruft isVisible() auf ``` -Ein schwerwiegender Fehler beendete die Anwendung, ohne dass eine Möglichkeit zur Reaktion bestand. Das stille Schreiben auf nicht existierende Mitglieder ohne Warnung konnte zu schwerwiegenden Fehlern führen, die schwer zu erkennen waren. `Nette\Object` Alle diese Fälle wurden abgefangen und eine Ausnahme `MemberAccessException` wurde ausgelöst. - -```php -echo $obj->undeclared; // throw Nette\MemberAccessException -$obj->undeclared = 1; // throw Nette\MemberAccessException -$obj->unknownMethod(); // throw Nette\MemberAccessException -``` -Seit PHP 7.0 verursacht PHP keine nicht abfangbaren fatalen Fehler mehr, und der Zugriff auf nicht deklarierte Member ist seit PHP 8.2 ein Fehler. - - -Haben Sie gemeint? .[#toc-did-you-mean] ---------------------------------------- -Wenn ein `Nette\MemberAccessException` -Fehler ausgelöst wurde, etwa aufgrund eines Tippfehlers beim Zugriff auf eine Objektvariable oder beim Aufruf einer Methode, versuchte `Nette\Object`, in der Fehlermeldung einen Hinweis darauf zu geben, wie der Fehler zu beheben ist, und zwar in Form des ikonischen Zusatzes "Meinten Sie?". +Seit PHP 8.4 kann die gleiche Funktionalität mit Property Hooks erreicht werden, die eine elegantere und kürzere Syntax bieten: ```php -class Foo extends Nette\Object +class Circle { - public static function from($var) - { + public float $radius = 0.0 { + set => max(0.0, $value); } -} -$foo = Foo::form($var); -// throw Nette\MemberAccessException -// "Call to undefined static method Foo::form(), did you mean from()?" + public bool $visible { + get => $this->radius > 0; + } +} ``` -Das heutige PHP hat zwar keine "Meinten Sie?"-Funktion, aber dieser Satz kann von [Tracy |tracy:] zu Fehlern hinzugefügt werden. Es kann [solche Fehler |tracy:open-files-in-ide#toc-demos] sogar [automatisch korrigieren |tracy:open-files-in-ide#toc-demos]. - -Erweiterungsmethoden .[#toc-extension-methods] ----------------------------------------------- -Inspiriert von Erweiterungsmethoden aus C#. Sie bieten die Möglichkeit, neue Methoden zu bestehenden Klassen hinzuzufügen. Zum Beispiel könnten Sie die Methode `addDateTime()` zu einem Formular hinzufügen, um Ihren eigenen DateTimePicker hinzuzufügen. +Extension Methods +----------------- +`Nette\Object` brachte ein weiteres interessantes Konzept nach PHP, inspiriert von modernen Programmiersprachen - Extension Methods. Diese Funktion, die von C# übernommen wurde, ermöglichte Entwicklern, bestehende Klassen elegant um neue Methoden zu erweitern, ohne sie zu modifizieren oder von ihnen zu erben. Zum Beispiel konnten Sie einem Formular eine `addDateTime()`-Methode hinzufügen, die einen benutzerdefinierten DateTimePicker hinzufügt: ```php Form::extensionMethod( @@ -131,22 +137,22 @@ $form = new Form; $form->addDateTime('date'); ``` -Erweiterungsmethoden erwiesen sich als unpraktisch, da ihre Namen von Editoren nicht automatisch vervollständigt wurden, sondern sie meldeten, dass die Methode nicht existierte. Daher wurde ihre Unterstützung eingestellt. +Extension Methods erwiesen sich als unpraktisch, da Editoren ihre Namen nicht vorschlugen und stattdessen meldeten, dass die Methode nicht existiert. Daher wurde ihre Unterstützung eingestellt. Heute ist es üblicher, Komposition oder Vererbung zu verwenden, um Klassenfunktionalität zu erweitern. -Ermitteln des Klassennamens .[#toc-getting-the-class-name] ----------------------------------------------------------- +Klassennamen ermitteln +---------------------- +SmartObject bot eine einfache Methode zum Ermitteln des Klassennamens: ```php -$class = $obj->getClass(); // using Nette\Object -$class = $obj::class; // since PHP 8.0 +$class = $obj->getClass(); // mit Nette\Object +$class = $obj::class; // seit PHP 8.0 ``` -Zugang zu Reflexion und Anmerkungen .[#toc-access-to-reflection-and-annotations] --------------------------------------------------------------------------------- - -`Nette\Object` bietet den Zugang zu Reflexion und Kommentaren mit den Methoden `getReflection()` und `getAnnotation()`: +Zugriff auf Reflection und Annotationen +--------------------------------------- +`Nette\Object` bot Zugriff auf Reflection und Annotationen durch die Methoden `getReflection()` und `getAnnotation()`. Dieser Ansatz vereinfachte die Arbeit mit Klassen-Metainformationen erheblich: ```php /** @@ -158,10 +164,10 @@ class Foo extends Nette\Object $obj = new Foo; $reflection = $obj->getReflection(); -$reflection->getAnnotation('author'); // returns 'John Doe' +$reflection->getAnnotation('author'); // gibt 'John Doe' zurück ``` -Seit PHP 8.0 ist es möglich, auf Metainformationen in Form von Attributen zuzugreifen: +Seit PHP 8.0 ist es möglich, auf Metainformationen durch Attribute zuzugreifen, die noch mehr Möglichkeiten und bessere Typenprüfung bieten: ```php #[Author('John Doe')] @@ -175,10 +181,9 @@ $reflection->getAttributes(Author::class)[0]; ``` -Methoden-Getter .[#toc-method-getters] --------------------------------------- - -`Nette\Object` boten eine elegante Möglichkeit, mit Methoden so umzugehen, als wären sie Variablen: +Method Getters +-------------- +`Nette\Object` bot eine elegante Möglichkeit, Methoden wie Variablen zu übergeben: ```php class Foo extends Nette\Object @@ -194,7 +199,7 @@ $method = $obj->adder; echo $method(2, 3); // 5 ``` -Seit PHP 8.1 können Sie die sogenannte "First-Class-Callable-Syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax verwenden: +Seit PHP 8.1 können Sie die "first-class callable syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax verwenden, die dieses Konzept noch weiter führt: ```php $obj = new Foo; @@ -203,10 +208,9 @@ echo $method(2, 3); // 5 ``` -Ereignisse .[#toc-events] -------------------------- - -`Nette\Object` bietet syntaktischen Zucker zum Auslösen des [Ereignisses |nette:glossary#events]: +Events +------ +SmartObject bietet eine vereinfachte Syntax für die Arbeit mit [Events|nette:glossary#events]. Events ermöglichen es Objekten, andere Teile der Anwendung über Änderungen ihres Zustands zu informieren: ```php class Circle extends Nette\Object @@ -221,7 +225,7 @@ class Circle extends Nette\Object } ``` -Der Code `$this->onChange($this, $radius)` entspricht folgendem: +Der Code `$this->onChange($this, $radius)` ist äquivalent zu folgender Schleife: ```php foreach ($this->onChange as $callback) { @@ -229,7 +233,7 @@ foreach ($this->onChange as $callback) { } ``` -Aus Gründen der Übersichtlichkeit wird empfohlen, die magische Methode `$this->onChange()` zu vermeiden. Ein guter Ersatz ist [Nette\Utils\Arrays::invoke |arrays#invoke]: +Der Übersichtlichkeit halber empfehlen wir, die magische Methode `$this->onChange()` zu vermeiden. Ein praktischer Ersatz ist die Funktion [Nette\Utils\Arrays::invoke|arrays#invoke]: ```php Nette\Utils\Arrays::invoke($this->onChange, $this, $radius); diff --git a/utils/el/smartobject.texy b/utils/el/smartobject.texy index e73cc73d15..d824b22108 100644 --- a/utils/el/smartobject.texy +++ b/utils/el/smartobject.texy @@ -2,7 +2,7 @@ SmartObject *********** .[perex] -Το SmartObject διόρθωνε τη συμπεριφορά των αντικειμένων με πολλούς τρόπους, αλλά η σημερινή PHP περιλαμβάνει ήδη τις περισσότερες από αυτές τις βελτιώσεις εγγενώς. Ωστόσο, εξακολουθεί να προσθέτει υποστήριξη για *property*. +Το SmartObject βελτίωνε για χρόνια τη συμπεριφορά των αντικειμένων στην PHP. Από την έκδοση PHP 8.4, όλες οι λειτουργίες του έχουν ενσωματωθεί στην ίδια την PHP, ολοκληρώνοντας έτσι την ιστορική του αποστολή ως πρωτοπόρος του σύγχρονου αντικειμενοστρεφούς προγραμματισμού στην PHP. Εγκατάσταση: @@ -11,19 +11,64 @@ SmartObject composer require nette/utils ``` +Το SmartObject δημιουργήθηκε το 2007 ως μια επαναστατική λύση στις ελλείψεις του τότε μοντέλου αντικειμένων της PHP. Σε μια εποχή που η PHP αντιμετώπιζε πολλά προβλήματα με τον αντικειμενοστρεφή σχεδιασμό, έφερε σημαντικές βελτιώσεις και απλοποίησε την εργασία των προγραμματιστών. Έγινε θρυλικό μέρος του framework Nette. Πρόσφερε λειτουργικότητα που η PHP απέκτησε πολλά χρόνια αργότερα - από την επικύρωση πρόσβασης σε ιδιότητες αντικειμένων μέχρι τον εξελιγμένο χειρισμό σφαλμάτων. Με την έλευση της PHP 8.4, ολοκλήρωσε την ιστορική του αποστολή, καθώς όλες οι λειτουργίες του έγιναν εγγενή μέρη της γλώσσας. Προηγήθηκε της εξέλιξης της PHP κατά αξιοσημείωτα 17 χρόνια. -Ιδιότητες, Getters και Setters .[#toc-properties-getters-and-setters] -===================================================================== +Τεχνικά, το SmartObject πέρασε από μια ενδιαφέρουσα εξέλιξη. Αρχικά υλοποιήθηκε ως κλάση `Nette\Object`, από την οποία άλλες κλάσεις κληρονομούσαν την απαιτούμενη λειτουργικότητα. Μια σημαντική αλλαγή ήρθε με την PHP 5.4, η οποία έφερε την υποστήριξη για traits. Αυτό επέτρεψε τη μετατροπή του σε trait `Nette\SmartObject`, προσφέροντας μεγαλύτερη ευελιξία - οι προγραμματιστές μπορούσαν να χρησιμοποιήσουν τη λειτουργικότητα ακόμη και σε κλάσεις που ήδη κληρονομούσαν από άλλη κλάση. Ενώ η αρχική κλάση `Nette\Object` έπαψε να υπάρχει με την PHP 7.2 (η οποία απαγόρευσε την ονομασία κλάσεων με τη λέξη 'Object'), το trait `Nette\SmartObject` συνεχίζει να υπάρχει. -Στις σύγχρονες αντικειμενοστραφείς γλώσσες (π.χ. C#, Python, Ruby, JavaScript), ο όρος *ιδιότητα* αναφέρεται σε [ειδικά μέλη των κλάσεων |https://en.wikipedia.org/wiki/Property_(programming)] που μοιάζουν με μεταβλητές αλλά στην πραγματικότητα αντιπροσωπεύονται από μεθόδους. Όταν η τιμή αυτής της "μεταβλητής" εκχωρείται ή διαβάζεται, καλείται η αντίστοιχη μέθοδος (που ονομάζεται getter ή setter). Αυτό είναι κάτι πολύ βολικό, μας δίνει πλήρη έλεγχο της πρόσβασης στις μεταβλητές. Μπορούμε να επικυρώσουμε την είσοδο ή να δημιουργήσουμε αποτελέσματα μόνο όταν διαβάζεται η ιδιότητα. +Ας εξερευνήσουμε τις λειτουργίες που προσέφεραν το `Nette\Object` και αργότερα το `Nette\SmartObject`. Κάθε μία από αυτές τις λειτουργίες αποτελούσε ένα σημαντικό βήμα προόδου στον αντικειμενοστρεφή προγραμματισμό της PHP. -Οι ιδιότητες της PHP δεν υποστηρίζονται, αλλά το trait `Nette\SmartObject` μπορεί να τις μιμηθεί. Πώς να το χρησιμοποιήσετε; -- Προσθέστε ένα σχόλιο στην κλάση με τη μορφή `@property $xyz` -- Δημιουργήστε έναν getter με όνομα `getXyz()` ή `isXyz()`, έναν setter με όνομα `setXyz()` -- Ο getter και ο setter πρέπει να είναι *δημόσιος* ή *προστατευμένος* και είναι προαιρετικοί, οπότε μπορεί να υπάρχει μια ιδιότητα *read-only* ή *write-only*. +Συνεπής Διαχείριση Σφαλμάτων +---------------------------- +Ένα από τα πιο επείγοντα προβλήματα της πρώιμης PHP ήταν η ασυνεπής συμπεριφορά κατά την εργασία με αντικείμενα. Το `Nette\Object` έφερε τάξη και προβλεψιμότητα σε αυτό το χάος. Ας δούμε πώς συμπεριφερόταν αρχικά η PHP: -Θα χρησιμοποιήσουμε την ιδιότητα για την κλάση Circle για να διασφαλίσουμε ότι μόνο μη αρνητικοί αριθμοί μπαίνουν στη μεταβλητή `$radius`. Αντικαταστήστε το `public $radius` με το property: +```php +echo $obj->undeclared; // E_NOTICE, αργότερα E_WARNING +$obj->undeclared = 1; // περνάει σιωπηλά χωρίς προειδοποίηση +$obj->unknownMethod(); // Fatal error (μη πιάσιμο με try/catch) +``` + +Το Fatal error τερμάτιζε την εφαρμογή χωρίς δυνατότητα αντίδρασης. Η σιωπηλή εγγραφή σε μη υπάρχοντα μέλη χωρίς προειδοποίηση μπορούσε να οδηγήσει σε σοβαρά σφάλματα που ήταν δύσκολο να εντοπιστούν. Το `Nette\Object` έπιανε όλες αυτές τις περιπτώσεις και έριχνε μια εξαίρεση `MemberAccessException`, επιτρέποντας στους προγραμματιστές να αντιδρούν και να χειρίζονται αυτά τα σφάλματα: + +```php +echo $obj->undeclared; // ρίχνει Nette\MemberAccessException +$obj->undeclared = 1; // ρίχνει Nette\MemberAccessException +$obj->unknownMethod(); // ρίχνει Nette\MemberAccessException +``` + +Από την PHP 7.0, η γλώσσα δεν προκαλεί πλέον μη πιάσιμα fatal errors και από την PHP 8.2, η πρόσβαση σε μη δηλωμένα μέλη θεωρείται σφάλμα. + + +Βοήθεια "Did you mean?" +----------------------- +Το `Nette\Object` ήρθε με μια πολύ βολική λειτουργία: έξυπνες προτάσεις για τυπογραφικά λάθη. Όταν ένας προγραμματιστής έκανε λάθος στο όνομα μιας μεθόδου ή μεταβλητής, όχι μόνο ανέφερε το σφάλμα αλλά πρόσφερε και βοήθεια προτείνοντας το σωστό όνομα. Αυτό το εμβληματικό μήνυμα, γνωστό ως "did you mean?", εξοικονόμησε στους προγραμματιστές ώρες αναζήτησης τυπογραφικών λαθών: + +```php +class Foo extends Nette\Object +{ + public static function from($var) + { + } +} + +$foo = Foo::form($var); +// ρίχνει Nette\MemberAccessException +// "Call to undefined static method Foo::form(), did you mean from()?" +``` + +Ενώ η PHP δεν έχει καμία μορφή "did you mean?", αυτή η λειτουργία παρέχεται τώρα από το [Tracy|tracy:]. Μπορεί ακόμη και να [διορθώνει αυτόματα|tracy:open-files-in-ide#demos] τέτοια σφάλματα. + + +Ιδιότητες με Ελεγχόμενη Πρόσβαση +-------------------------------- +Μια σημαντική καινοτομία που έφερε το SmartObject στην PHP ήταν οι ιδιότητες με ελεγχόμενη πρόσβαση (properties). Αυτή η έννοια, κοινή σε γλώσσες όπως η C# ή η Python, επέτρεψε στους προγραμματιστές να ελέγχουν κομψά την πρόσβαση στα δεδομένα αντικειμένων και να διασφαλίζουν τη συνέπειά τους. Οι ιδιότητες είναι ένα ισχυρό εργαλείο αντικειμενοστρεφούς προγραμματισμού. Λειτουργούν ως μεταβλητές αλλά στην πραγματικότητα αντιπροσωπεύονται από μεθόδους (getters και setters). Αυτό επιτρέπει την επικύρωση εισόδων ή τη δημιουργία τιμών τη στιγμή της ανάγνωσης. + +Για να χρησιμοποιήσετε τις ιδιότητες, πρέπει να: +- Προσθέσετε στην κλάση την επισήμανση `@property $xyz` +- Δημιουργήσετε getter με όνομα `getXyz()` ή `isXyz()`, setter με όνομα `setXyz()` +- Διασφαλίσετε ότι ο getter και ο setter είναι *public* ή *protected*. Είναι προαιρετικοί - άρα μπορούν να υπάρχουν ως ιδιότητες *μόνο-ανάγνωσης* ή *μόνο-εγγραφής* + +Ας δούμε ένα πρακτικό παράδειγμα χρησιμοποιώντας την κλάση Circle, όπου θα χρησιμοποιήσουμε ιδιότητες για να διασφαλίσουμε ότι η ακτίνα είναι πάντα μη αρνητική. Θα αντικαταστήσουμε το `public $radius` με μια ιδιότητα: ```php /** @@ -34,7 +79,7 @@ class Circle { use Nette\SmartObject; - private float $radius = 0.0; // όχι δημόσια + private float $radius = 0.0; // όχι public! // getter για την ιδιότητα $radius protected function getRadius(): float @@ -45,7 +90,7 @@ class Circle // setter για την ιδιότητα $radius protected function setRadius(float $radius): void { - // εξυγίανση της τιμής πριν από την αποθήκευση + // καθαρίζουμε την τιμή πριν την αποθήκευση $this->radius = max(0.0, $radius); } @@ -57,69 +102,30 @@ class Circle } $circle = new Circle; -$circle->radius = 10; // στην πραγματικότητα καλεί την setRadius(10) -echo $circle->radius; // καλεί την getRadius() -echo $circle->visible; // καλεί την isVisible() -``` - -Οι ιδιότητες είναι κατά κύριο λόγο "συντακτική ζάχαρη"((syntactic sugar)), η οποία έχει σκοπό να κάνει τη ζωή του προγραμματιστή πιο γλυκιά απλοποιώντας τον κώδικα. Αν δεν τις θέλετε, δεν χρειάζεται να τις χρησιμοποιήσετε. - - -Μια ματιά στην ιστορία .[#toc-a-glimpse-into-history] -===================================================== - -Το SmartObject χρησιμοποιείται για να βελτιώσει τη συμπεριφορά των αντικειμένων με πολλούς τρόπους, αλλά η σημερινή PHP ενσωματώνει ήδη τις περισσότερες από αυτές τις βελτιώσεις εγγενώς. Το κείμενο που ακολουθεί είναι μια νοσταλγική αναδρομή στην ιστορία, υπενθυμίζοντάς μας πώς εξελίχθηκαν τα πράγματα. - -Από την αρχή της δημιουργίας του, το μοντέλο αντικειμένων της PHP υπέφερε από μυριάδες σοβαρές ελλείψεις και αδυναμίες. Αυτό οδήγησε στη δημιουργία της κλάσης `Nette\Object` (το 2007), η οποία είχε ως στόχο να διορθώσει αυτά τα προβλήματα και να βελτιώσει την άνεση της χρήσης της PHP. Το μόνο που χρειαζόταν ήταν άλλες κλάσεις να κληρονομήσουν από αυτήν και θα αποκτούσαν τα οφέλη που προσέφερε. Όταν η PHP 5.4 εισήγαγε την υποστήριξη για γνωρίσματα, η κλάση `Nette\Object` αντικαταστάθηκε από το γνώρισμα `Nette\SmartObject`. Αυτό εξάλειψε την ανάγκη να κληρονομήσετε από έναν κοινό πρόγονο. Επιπλέον, το γνώρισμα μπορούσε να χρησιμοποιηθεί σε κλάσεις που ήδη κληρονομούσαν από μια άλλη κλάση. Το οριστικό τέλος του `Nette\Object` ήρθε με την κυκλοφορία της PHP 7.2, η οποία απαγόρευσε στις κλάσεις να ονομάζονται `Object`. - -Καθώς η ανάπτυξη της PHP συνεχιζόταν, το μοντέλο αντικειμένων και οι δυνατότητες της γλώσσας βελτιώνονταν. Διάφορες λειτουργίες της κλάσης `SmartObject` έγιναν περιττές. Από την έκδοση της PHP 8.2, παραμένει μόνο ένα χαρακτηριστικό που δεν υποστηρίζεται άμεσα στην PHP: η δυνατότητα χρήσης των λεγόμενων [ιδιοτήτων |#Properties, getters, and setters]. - -Ποια χαρακτηριστικά προσέφερε η `Nette\Object` και, κατ' επέκταση, η `Nette\SmartObject`; Ακολουθεί μια επισκόπηση. (Στα παραδείγματα χρησιμοποιείται η κλάση `Nette\Object`, αλλά τα περισσότερα χαρακτηριστικά ισχύουν και για την ιδιότητα `Nette\SmartObject` ). - - -Ασυνεπή σφάλματα .[#toc-inconsistent-errors] --------------------------------------------- -Η PHP είχε ασυνεπή συμπεριφορά κατά την πρόσβαση σε μη δηλωμένα μέλη. Η κατάσταση κατά τη στιγμή του `Nette\Object` ήταν η εξής: - -```php -echo $obj->undeclared; // E_NOTICE, αργότερα E_WARNING -$obj->undeclared = 1; // περνάει σιωπηλά χωρίς αναφορά -$obj->unknownMethod(); // Μοιραίο σφάλμα (δεν μπορεί να πιαστεί από try/catch) +$circle->radius = 10; // στην πραγματικότητα καλεί το setRadius(10) +echo $circle->radius; // καλεί το getRadius() +echo $circle->visible; // καλεί το isVisible() ``` -Το μοιραίο σφάλμα τερμάτισε την εφαρμογή χωρίς καμία δυνατότητα αντίδρασης. Η σιωπηλή εγγραφή σε ανύπαρκτα μέλη χωρίς προειδοποίηση θα μπορούσε να οδηγήσει σε σοβαρά σφάλματα που ήταν δύσκολο να εντοπιστούν. `Nette\Object` Όλες αυτές οι περιπτώσεις εντοπίστηκαν και απορρίφθηκε μια εξαίρεση `MemberAccessException`. +Από την PHP 8.4, η ίδια λειτουργικότητα μπορεί να επιτευχθεί χρησιμοποιώντας property hooks, που προσφέρουν πολύ πιο κομψή και συνοπτική σύνταξη: ```php -echo $obj->undeclared; // throw Nette\MemberAccessException -$obj->undeclared = 1; // throw Nette\MemberAccessException -$obj->unknownMethod(); // throw Nette\MemberAccessException -``` -Από την PHP 7.0, η PHP δεν προκαλεί πλέον μη πιασμένα μοιραία σφάλματα, ενώ η πρόσβαση σε μη δηλωμένα μέλη αποτελεί σφάλμα από την PHP 8.2. - - -Εννοείτε? .[#toc-did-you-mean] ------------------------------- -Εάν εμφανιζόταν ένα σφάλμα `Nette\MemberAccessException`, ίσως λόγω τυπογραφικού λάθους κατά την προσπέλαση μιας μεταβλητής αντικειμένου ή την κλήση μιας μεθόδου, το `Nette\Object` προσπαθούσε να δώσει μια υπόδειξη στο μήνυμα σφάλματος για το πώς να διορθωθεί το σφάλμα, με τη μορφή της εικονικής προσθήκης "εννοούσες;". - -```php -class Foo extends Nette\Object +class Circle { - public static function from($var) - { + public float $radius = 0.0 { + set => max(0.0, $value); } -} -$foo = Foo::form($var); -// throw Nette\MemberAccessException -// "Call to undefined static method Foo::form(), did you mean from()?" + public bool $visible { + get => $this->radius > 0; + } +} ``` -Αν και η σημερινή PHP δεν διαθέτει τη δυνατότητα "εννοούσατε;", αυτή η φράση μπορεί να προστεθεί στα σφάλματα από [την Tracy |tracy:]. Μπορεί ακόμη και να [διορθώσει αυτόματα τέτοια σφάλματα |tracy:open-files-in-ide#toc-demos]. - -Μέθοδοι επέκτασης .[#toc-extension-methods] -------------------------------------------- -Εμπνευσμένο από τις μεθόδους επέκτασης της C#. Έδιναν τη δυνατότητα προσθήκης νέων μεθόδων σε υπάρχουσες κλάσεις. Για παράδειγμα, θα μπορούσατε να προσθέσετε τη μέθοδο `addDateTime()` σε μια φόρμα για να προσθέσετε το δικό σας DateTimePicker. +Extension Methods +----------------- +Το `Nette\Object` έφερε στην PHP άλλη μια ενδιαφέρουσα έννοια εμπνευσμένη από σύγχρονες γλώσσες προγραμματισμού - τις extension methods. Αυτή η λειτουργία, δανεισμένη από τη C#, επέτρεψε στους προγραμματιστές να επεκτείνουν κομψά υπάρχουσες κλάσεις με νέες μεθόδους χωρίς να τις τροποποιούν ή να κληρονομούν από αυτές. Για παράδειγμα, θα μπορούσατε να προσθέσετε μια μέθοδο `addDateTime()` σε μια φόρμα που προσθέτει ένα προσαρμοσμένο DateTimePicker: ```php Form::extensionMethod( @@ -131,22 +137,22 @@ $form = new Form; $form->addDateTime('date'); ``` -Οι μέθοδοι επέκτασης αποδείχθηκαν ανεφάρμοστες επειδή τα ονόματά τους δεν συμπληρώνονταν αυτόματα από τους συντάκτες, αλλά ανέφεραν ότι η μέθοδος δεν υπήρχε. Ως εκ τούτου, η υποστήριξή τους διακόπηκε. +Οι extension methods αποδείχθηκαν μη πρακτικές επειδή οι επεξεργαστές δεν πρότειναν τα ονόματά τους και αντίθετα ανέφεραν ότι η μέθοδος δεν υπάρχει. Επομένως, η υποστήριξή τους διακόπηκε. Σήμερα, είναι πιο συνηθισμένο να χρησιμοποιείται σύνθεση ή κληρονομικότητα για την επέκταση της λειτουργικότητας των κλάσεων. -Λήψη του ονόματος της κλάσης .[#toc-getting-the-class-name] ------------------------------------------------------------ +Λήψη Ονόματος Κλάσης +-------------------- +Το SmartObject πρόσφερε μια απλή μέθοδο για τη λήψη του ονόματος της κλάσης: ```php -$class = $obj->getClass(); // χρησιμοποιώντας το Nette\Object +$class = $obj->getClass(); // χρησιμοποιώντας Nette\Object $class = $obj::class; // από την PHP 8.0 ``` -Πρόσβαση στον Αναστοχασμό και τις Σημειώσεις .[#toc-access-to-reflection-and-annotations] ------------------------------------------------------------------------------------------ - -`Nette\Object` προσφέρεται πρόσβαση στον προβληματισμό και τον σχολιασμό με τη χρήση των μεθόδων `getReflection()` και `getAnnotation()`: +Πρόσβαση σε Reflection και Annotations +-------------------------------------- +Το `Nette\Object` παρείχε πρόσβαση σε reflection και annotations μέσω των μεθόδων `getReflection()` και `getAnnotation()`. Αυτή η προσέγγιση απλοποίησε σημαντικά την εργασία με μετα-πληροφορίες κλάσεων: ```php /** @@ -158,10 +164,10 @@ class Foo extends Nette\Object $obj = new Foo; $reflection = $obj->getReflection(); -$reflection->getAnnotation('author'); // returns 'John Doe' +$reflection->getAnnotation('author'); // επιστρέφει 'John Doe' ``` -Από την PHP 8.0, είναι δυνατή η πρόσβαση σε μετα-πληροφορίες με τη μορφή χαρακτηριστικών: +Από την PHP 8.0, είναι δυνατή η πρόσβαση σε μετα-πληροφορίες μέσω attributes, τα οποία προσφέρουν ακόμη περισσότερες δυνατότητες και καλύτερο έλεγχο τύπων: ```php #[Author('John Doe')] @@ -175,10 +181,9 @@ $reflection->getAttributes(Author::class)[0]; ``` -Μέθοδοι Getters .[#toc-method-getters] --------------------------------------- - -`Nette\Object` προσέφερε έναν κομψό τρόπο για να χειρίζεστε τις μεθόδους σαν να ήταν μεταβλητές: +Method Getters +-------------- +Το `Nette\Object` πρόσφερε έναν κομψό τρόπο για να περνάμε μεθόδους σαν να ήταν μεταβλητές: ```php class Foo extends Nette\Object @@ -194,7 +199,7 @@ $method = $obj->adder; echo $method(2, 3); // 5 ``` -Από την PHP 8.1, μπορείτε να χρησιμοποιήσετε τη λεγόμενη "σύνταξη κλήσης πρώτης κατηγορίας":https://www.php.net/manual/en/functions.first_class_callable_syntax: +Από την PHP 8.1, μπορείτε να χρησιμοποιήσετε το "first-class callable syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax, το οποίο προχωράει αυτήν την έννοια ακόμη περισσότερο: ```php $obj = new Foo; @@ -203,10 +208,9 @@ echo $method(2, 3); // 5 ``` -Γεγονότα .[#toc-events] ------------------------ - -`Nette\Object` προσφέρεται συντακτική ζάχαρη για την ενεργοποίηση του [συμβάντος |nette:glossary#events]: +Συμβάντα (Events) +----------------- +Το SmartObject προσφέρει απλοποιημένη σύνταξη για εργασία με [συμβάντα|nette:glossary#events]. Τα συμβάντα επιτρέπουν στα αντικείμενα να ενημερώνουν άλλα μέρη της εφαρμογής για αλλαγές στην κατάστασή τους: ```php class Circle extends Nette\Object @@ -221,7 +225,7 @@ class Circle extends Nette\Object } ``` -Ο κώδικας `$this->onChange($this, $radius)` είναι ισοδύναμος με τα ακόλουθα: +Ο κώδικας `$this->onChange($this, $radius)` είναι ισοδύναμος με τον ακόλουθο βρόχο: ```php foreach ($this->onChange as $callback) { @@ -229,7 +233,7 @@ foreach ($this->onChange as $callback) { } ``` -Για λόγους σαφήνειας συνιστούμε να αποφύγετε τη μαγική μέθοδο `$this->onChange()`. Ένα πρακτικό υποκατάστατο είναι η συνάρτηση [Nette\Utils\Arrays::invoke |arrays#invoke]: +Για λόγους σαφήνειας, συνιστούμε να αποφεύγετε τη μαγική μέθοδο `$this->onChange()`. Μια πρακτική εναλλακτική είναι η συνάρτηση [Nette\Utils\Arrays::invoke|arrays#invoke]: ```php Nette\Utils\Arrays::invoke($this->onChange, $this, $radius); diff --git a/utils/en/smartobject.texy b/utils/en/smartobject.texy index 27ec6370bb..4a30efbf8b 100644 --- a/utils/en/smartobject.texy +++ b/utils/en/smartobject.texy @@ -2,7 +2,7 @@ SmartObject *********** .[perex] -SmartObject used to fix objects behavior in many ways, but today's PHP already includes most of these improvements natively. However, it still adds support for *properties*. +SmartObject enhanced PHP object behavior for many years. Since PHP 8.4, all of its features have become native parts of PHP itself, thus completing its historic mission as a pioneer of modern object-oriented approach in PHP. Installation: @@ -11,19 +11,64 @@ Installation: composer require nette/utils ``` +SmartObject was introduced in 2007 as a revolutionary solution to the shortcomings of PHP's object model at the time. In an era when PHP faced numerous issues with object-oriented design, it brought significant improvements and simplified developers' workflows. It became a legendary component of the Nette framework. SmartObject offered functionality that PHP only acquired many years later – from access control for object properties to sophisticated syntactic sugar. With the release of PHP 8.4, it fulfilled its historical mission, as all its features became a native part of the language. It was ahead of PHP's development by an impressive 17 years. -Properties, Getters and Setters -=============================== +SmartObject went through an interesting technical evolution. Initially, it was implemented as the `Nette\Object` class, from which other classes inherited the needed functionality. A significant change came with PHP 5.4, which introduced trait support. This enabled transformation into the `Nette\SmartObject` trait, bringing greater flexibility - developers could use the functionality even in classes that already inherited from another class. While the original `Nette\Object` class ceased to exist with PHP 7.2 (which prohibited naming classes with the word 'Object'), the `Nette\SmartObject` trait lives on. -In modern object-oriented languages (e.g. C#, Python, Ruby, JavaScript), the term *property* refers to [special members of classes |https://en.wikipedia.org/wiki/Property_(programming)] that look like variables but are actually represented by methods. When the value of this "variable" is assigned or read, the corresponding method (called getter or setter) is called. This is a very handy thing to do, it gives us full control over access to variables. We can validate the input or generate results only when the property is read. +Let's explore the features that `Nette\Object` and later `Nette\SmartObject` offered. Each of these functions represented a significant step forward in PHP object-oriented programming at the time. -PHP properties are not supported, but trait `Nette\SmartObject` can imitate them. How to use it? -- Add an annotation to the class in the form `@property $xyz` +Consistent Error States +----------------------- +One of the most pressing issues of early PHP was inconsistent behavior when working with objects. `Nette\Object` brought order and predictability to this chaos. Let's look at how PHP originally behaved: + +```php +echo $obj->undeclared; // E_NOTICE, later E_WARNING +$obj->undeclared = 1; // passes silently without warning +$obj->unknownMethod(); // Fatal error (uncatchable by try/catch) +``` + +Fatal error would terminate the application without any possibility to react. Silent writing to non-existent members without warning could lead to serious errors that were difficult to detect. `Nette\Object` caught all these cases and threw a `MemberAccessException`, allowing programmers to react to and handle these errors: + +```php +echo $obj->undeclared; // throws Nette\MemberAccessException +$obj->undeclared = 1; // throws Nette\MemberAccessException +$obj->unknownMethod(); // throws Nette\MemberAccessException +``` + +Since PHP 7.0, the language no longer causes uncatchable fatal errors, and since PHP 8.2, access to undeclared members is considered an error. + + +"Did you mean?" Helper +---------------------- +`Nette\Object` came with a very convenient feature: intelligent suggestions for typos. When a developer made a mistake in a method or variable name, it not only reported the error but also offered help by suggesting the correct name. This iconic message, known as "did you mean?", saved programmers hours of hunting for typos: + +```php +class Foo extends Nette\Object +{ + public static function from($var) + { + } +} + +$foo = Foo::form($var); +// throws Nette\MemberAccessException +// "Call to undefined static method Foo::form(), did you mean from()?" +``` + +While PHP itself doesn't have any form of "did you mean?", this feature is now provided by [Tracy|tracy:]. It can even [auto-fix|tracy:open-files-in-ide#demos] such errors. + + +Properties with Controlled Access +--------------------------------- +A significant innovation that SmartObject brought to PHP was properties with controlled access. This concept, common in languages like C# or Python, allowed developers to elegantly control access to object data and ensure their consistency. Properties are a powerful tool of object-oriented programming. They function like variables but are actually represented by methods (getters and setters). This allows input validation or value generation at the time of reading. + +To use properties, you must: +- Add the annotation `@property $xyz` to the class - Create a getter named `getXyz()` or `isXyz()`, a setter named `setXyz()` -- The getter and setter must be *public* or *protected* and are optional, so there can be a *read-only* or *write-only* property +- Ensure the getter and setter are *public* or *protected*. They are optional - thus can exist as *read-only* or *write-only* properties -We will use the property for the Circle class to ensure that only non-negative numbers are put into the `$radius` variable. Replace `public $radius` with property: +Let's look at a practical example using the Circle class, where we'll use properties to ensure that the radius is always non-negative. We'll replace `public $radius` with a property: ```php /** @@ -34,22 +79,22 @@ class Circle { use Nette\SmartObject; - private float $radius = 0.0; // not public + private float $radius = 0.0; // not public! - // getter for property $radius + // getter for $radius property protected function getRadius(): float { return $this->radius; } - // setter for property $radius + // setter for $radius property protected function setRadius(float $radius): void { - // sanitizing value before saving it + // sanitize the value before saving $this->radius = max(0.0, $radius); } - // getter for property $visible + // getter for $visible property protected function isVisible(): bool { return $this->radius > 0; @@ -62,64 +107,25 @@ echo $circle->radius; // calls getRadius() echo $circle->visible; // calls isVisible() ``` -Properties are primarily "syntactic sugar"((syntactic sugar)), which is intended to make the programmer's life sweeter by simplifying the code. If you don't want them, you don't have to use them. - - -A Glimpse into History -====================== - -SmartObject used to refine the behavior of objects in numerous ways, but today's PHP already incorporates most of these enhancements natively. The following text is a nostalgic look back at history, reminding us of how things evolved. - -From its inception, PHP's object model suffered from a myriad of serious shortcomings and deficiencies. This led to the creation of the `Nette\Object` class (in 2007), which aimed to rectify these issues and enhance the comfort of using PHP. All that was needed was for other classes to inherit from it, and they would gain the benefits it offered. When PHP 5.4 introduced support for traits, the `Nette\Object` class was replaced by the `Nette\SmartObject` trait. This eliminated the need to inherit from a common ancestor. Moreover, the trait could be used in classes that already inherited from another class. The definitive end of `Nette\Object` came with the release of PHP 7.2, which prohibited classes from being named `Object`. - -As PHP development continued, its object model and language capabilities improved. Various functions of the `SmartObject` class became redundant. Since the release of PHP 8.2, there remains only one feature not directly supported in PHP: the ability to use so-called [properties|#Properties, getters, and setters]. - -What features did `Nette\Object` and, by extension, `Nette\SmartObject` offer? Here's an overview. (In the examples, the `Nette\Object` class is used, but most features also apply to the `Nette\SmartObject` trait). - - -Inconsistent Errors -------------------- -PHP had inconsistent behavior when accessing undeclared members. The state at the time of `Nette\Object` was as follows: - -```php -echo $obj->undeclared; // E_NOTICE, later E_WARNING -$obj->undeclared = 1; // passes silently without reporting -$obj->unknownMethod(); // Fatal error (not catchable by try/catch) -``` - -A fatal error would terminate the application without any chance of response. Silently writing to non-existent members without warning could lead to serious errors that were hard to detect. `Nette\Object` caught all these cases and threw a `MemberAccessException` exception. - -```php -echo $obj->undeclared; // throws Nette\MemberAccessException -$obj->undeclared = 1; // throws Nette\MemberAccessException -$obj->unknownMethod(); // throws Nette\MemberAccessException -``` -From PHP version 7.0 onwards, uncatchable fatal errors no longer occur, and accessing undeclared members becomes an error from PHP 8.2. - - -Did you mean? -------------- -If an `Nette\MemberAccessException` error was thrown, perhaps due to a typo when accessing an object variable or calling a method, `Nette\Object` attempted to give a hint in the error message on how to fix the error, in the form of the iconic "did you mean?" addendum. +Since PHP 8.4, the same functionality can be achieved using property hooks, which offer a much more elegant and concise syntax: ```php -class Foo extends Nette\Object +class Circle { - public static function from($var) - { + public float $radius = 0.0 { + set => max(0.0, $value); } -} -$foo = Foo::form($var); -// throws Nette\MemberAccessException -// "Call to undefined static method Foo::form(), did you mean from()?" + public bool $visible { + get => $this->radius > 0; + } +} ``` -While today's PHP doesn't have a "did you mean?" feature, this phrase can be added to errors by [Tracy|tracy:]. It can even [auto-correct such errors|tracy:open-files-in-ide#toc-demos]. - Extension Methods ----------------- -Inspired by the extension methods from the C# language, they provided the ability to add new methods to existing classes. For instance, you could add a `addDateTime()` method to a form, which would introduce a custom DateTimePicker. +`Nette\Object` brought another interesting concept to PHP inspired by modern programming languages - extension methods. This feature, borrowed from C#, allowed developers to elegantly extend existing classes with new methods without modifying them or inheriting from them. For instance, you could add an `addDateTime()` method to a form that adds a custom DateTimePicker: ```php Form::extensionMethod( @@ -131,22 +137,22 @@ $form = new Form; $form->addDateTime('date'); ``` -Extension methods turned out to be impractical because their names were not suggested by editors; on the contrary, they reported that the method did not exist. Therefore, their support was discontinued. +Extension methods proved impractical because editors wouldn't suggest their names and would instead report that the method doesn't exist. Therefore, their support was discontinued. Today, it's more common to use composition or inheritance to extend class functionality. -Determining the Class Name --------------------------- +Getting Class Name +------------------ +SmartObject offered a simple method for getting the class name: ```php $class = $obj->getClass(); // using Nette\Object -$class = $obj::class; // from PHP 8.0 +$class = $obj::class; // since PHP 8.0 ``` -Access to Reflection and Annotations ------------------------------------- - -`Nette\Object` offered access to reflection and annotation using the methods `getReflection()` and `getAnnotation()`: +Reflection and Annotation Access +-------------------------------- +`Nette\Object` provided access to reflection and annotations through methods `getReflection()` and `getAnnotation()`. This approach significantly simplified working with class meta-information: ```php /** @@ -161,7 +167,7 @@ $reflection = $obj->getReflection(); $reflection->getAnnotation('author'); // returns 'John Doe' ``` -As of PHP 8.0, it is possible to access meta-information in the form of attributes: +Since PHP 8.0, it's possible to access meta-information through attributes, which offer even more possibilities and better type checking: ```php #[Author('John Doe')] @@ -177,8 +183,7 @@ $reflection->getAttributes(Author::class)[0]; Method Getters -------------- - -`Nette\Object` offered an elegant way to deal with methods as if they were variables: +`Nette\Object` offered an elegant way to pass methods as if they were variables: ```php class Foo extends Nette\Object @@ -194,7 +199,7 @@ $method = $obj->adder; echo $method(2, 3); // 5 ``` -As of PHP 8.1, you can use the so-called "first-class callable syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax: +Since PHP 8.1, you can use the "first-class callable syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax, which takes this concept even further: ```php $obj = new Foo; @@ -205,8 +210,7 @@ echo $method(2, 3); // 5 Events ------ - -`Nette\Object` offered syntactic sugar to trigger the [event |nette:glossary#events]: +SmartObject offers simplified syntax for working with [events|nette:glossary#events]. Events allow objects to inform other parts of the application about changes in their state: ```php class Circle extends Nette\Object @@ -221,7 +225,7 @@ class Circle extends Nette\Object } ``` -The code `$this->onChange($this, $radius)` is equivalent to the following: +The code `$this->onChange($this, $radius)` is equivalent to the following loop: ```php foreach ($this->onChange as $callback) { @@ -229,7 +233,7 @@ foreach ($this->onChange as $callback) { } ``` -For clarity, we recommend avoiding the magic method `$this->onChange()`. A practical alternative is the [Nette\Utils\Arrays::invoke |arrays#invoke] function: +For clarity, we recommend avoiding the magic `$this->onChange()` method. A practical replacement is the [Nette\Utils\Arrays::invoke|arrays#invoke] function: ```php Nette\Utils\Arrays::invoke($this->onChange, $this, $radius); diff --git a/utils/es/smartobject.texy b/utils/es/smartobject.texy index b3b4cbc5b3..5da55a227a 100644 --- a/utils/es/smartobject.texy +++ b/utils/es/smartobject.texy @@ -2,7 +2,7 @@ SmartObject *********** .[perex] -SmartObject solía arreglar el comportamiento de los objetos de muchas maneras, pero el PHP actual ya incluye la mayoría de estas mejoras de forma nativa. Sin embargo, aún añade soporte para *property*. +SmartObject mejoró durante años el comportamiento de los objetos en PHP. Desde la versión PHP 8.4, todas sus funciones forman parte nativa del propio PHP, completando así su misión histórica como pionero del enfoque orientado a objetos moderno en PHP. Instalación: @@ -11,19 +11,64 @@ Instalación: composer require nette/utils ``` +SmartObject surgió en 2007 como una solución revolucionaria a las deficiencias del modelo de objetos de PHP de la época. En un momento en que PHP sufría numerosos problemas con el diseño orientado a objetos, aportó mejoras significativas y simplificó el trabajo de los desarrolladores. Se convirtió en una parte legendaria del framework Nette. Ofrecía funcionalidades que PHP no obtendría hasta muchos años después: desde la validación del acceso a propiedades hasta el manejo sofisticado de errores. Con la llegada de PHP 8.4, completó su misión histórica, ya que todas sus funciones se convirtieron en partes nativas del lenguaje. Se adelantó al desarrollo de PHP en notables 17 años. -Propiedades, getters y setters .[#toc-properties-getters-and-setters] -===================================================================== +SmartObject pasó por una interesante evolución técnica. Inicialmente, se implementó como la clase `Nette\Object`, de la cual otras clases heredaban la funcionalidad necesaria. Un cambio significativo llegó con PHP 5.4, que introdujo el soporte para traits. Esto permitió la transformación al trait `Nette\SmartObject`, aportando mayor flexibilidad - los desarrolladores podían utilizar la funcionalidad incluso en clases que ya heredaban de otra clase. Mientras que la clase original `Nette\Object` dejó de existir con PHP 7.2 (que prohibió nombrar clases con la palabra 'Object'), el trait `Nette\SmartObject` sigue vigente. -En los lenguajes modernos orientados a objetos (por ejemplo, C#, Python, Ruby, JavaScript), el término *propiedad* se refiere a [miembros especiales de las clases |https://en.wikipedia.org/wiki/Property_(programming)] que parecen variables pero que en realidad están representados por métodos. Cuando se asigna o se lee el valor de esta "variable", se llama al método correspondiente (llamado getter o setter). Esto es muy práctico, nos da un control total sobre el acceso a las variables. Podemos validar la entrada o generar resultados sólo cuando la propiedad es leída. +Veamos las características que `Nette\Object` y posteriormente `Nette\SmartObject` ofrecían. Cada una de estas funciones representó un paso significativo en la programación orientada a objetos en PHP de su época. -Las propiedades PHP no están soportadas, pero trait `Nette\SmartObject` puede imitarlas. ¿Cómo usarlo? -- Añade una anotación a la clase de la forma `@property $xyz` -- Crea un getter llamado `getXyz()` o `isXyz()`, un setter llamado `setXyz()` -- El getter y el setter deben ser *public* o *protected* y son opcionales, por lo que puede haber una propiedad *read-only* o *write-only +Estados de Error Consistentes +----------------------------- +Uno de los problemas más apremiantes del PHP temprano era el comportamiento inconsistente al trabajar con objetos. `Nette\Object` trajo orden y previsibilidad a este caos. Veamos cómo se comportaba PHP originalmente: -Utilizaremos la propiedad de la clase Circle para asegurarnos de que sólo se introducen números no negativos en la variable `$radius`. Sustituye `public $radius` por propiedad: +```php +echo $obj->undeclared; // E_NOTICE, después E_WARNING +$obj->undeclared = 1; // pasa silenciosamente sin advertencia +$obj->unknownMethod(); // Error fatal (no capturable con try/catch) +``` + +El error fatal terminaba la aplicación sin posibilidad de reaccionar. La escritura silenciosa en miembros inexistentes sin advertencia podía llevar a errores graves difíciles de detectar. `Nette\Object` capturaba todos estos casos y lanzaba una `MemberAccessException`, permitiendo a los programadores reaccionar y manejar estos errores: + +```php +echo $obj->undeclared; // lanza Nette\MemberAccessException +$obj->undeclared = 1; // lanza Nette\MemberAccessException +$obj->unknownMethod(); // lanza Nette\MemberAccessException +``` + +Desde PHP 7.0, el lenguaje ya no causa errores fatales no capturables, y desde PHP 8.2, el acceso a miembros no declarados se considera un error. + + +Ayudante "Did you mean?" +------------------------ +`Nette\Object` vino con una característica muy conveniente: sugerencias inteligentes para errores de escritura. Cuando un desarrollador cometía un error en el nombre de un método o variable, no solo informaba del error, sino que también ofrecía ayuda sugiriendo el nombre correcto. Este mensaje icónico, conocido como "did you mean?", ahorró a los programadores horas de búsqueda de errores tipográficos: + +```php +class Foo extends Nette\Object +{ + public static function from($var) + { + } +} + +$foo = Foo::form($var); +// lanza Nette\MemberAccessException +// "Call to undefined static method Foo::form(), did you mean from()?" +``` + +Aunque PHP en sí no tiene ninguna forma de "did you mean?", esta característica ahora la proporciona [Tracy|tracy:]. Incluso puede [auto-corregir|tracy:open-files-in-ide#demos] estos errores. + + +Propiedades con Acceso Controlado +--------------------------------- +Una innovación significativa que SmartObject trajo a PHP fueron las propiedades con acceso controlado. Este concepto, común en lenguajes como C# o Python, permitió a los desarrolladores controlar elegantemente el acceso a los datos del objeto y asegurar su consistencia. Las propiedades son una herramienta poderosa de la programación orientada a objetos. Funcionan como variables pero en realidad están representadas por métodos (getters y setters). Esto permite validar las entradas o generar valores en el momento de la lectura. + +Para usar propiedades, debes: +- Agregar la anotación `@property $xyz` a la clase +- Crear un getter llamado `getXyz()` o `isXyz()`, un setter llamado `setXyz()` +- Asegurar que el getter y setter sean *public* o *protected*. Son opcionales - por lo tanto pueden existir como propiedades de *solo lectura* o *solo escritura* + +Veamos un ejemplo práctico usando la clase Circle, donde usaremos propiedades para asegurar que el radio sea siempre no negativo. Reemplazaremos `public $radius` con una propiedad: ```php /** @@ -34,22 +79,22 @@ class Circle { use Nette\SmartObject; - private float $radius = 0.0; // not public + private float $radius = 0.0; // ¡no es public! - // getter for property $radius + // getter para la propiedad $radius protected function getRadius(): float { return $this->radius; } - // setter for property $radius + // setter para la propiedad $radius protected function setRadius(float $radius): void { - // sanitizing value before saving it + // sanitizamos el valor antes de guardarlo $this->radius = max(0.0, $radius); } - // getter for property $visible + // getter para la propiedad $visible protected function isVisible(): bool { return $this->radius > 0; @@ -57,69 +102,30 @@ class Circle } $circle = new Circle; -$circle->radius = 10; // actually calls setRadius(10) -echo $circle->radius; // calls getRadius() -echo $circle->visible; // calls isVisible() -``` - -Las propiedades son principalmente "azúcar sintáctico"((syntactic sugar)), que pretende hacer la vida del programador más dulce simplificando el código. Si no las quieres, no tienes por qué usarlas. - - -Un vistazo a la Historia .[#toc-a-glimpse-into-history] -======================================================= - -SmartObject solía refinar el comportamiento de los objetos de numerosas maneras, pero el PHP actual ya incorpora la mayoría de estas mejoras de forma nativa. El siguiente texto es una mirada nostálgica a la historia, recordándonos como evolucionaron las cosas. - -Desde sus inicios, el modelo de objetos de PHP sufrió de una miríada de serios defectos y deficiencias. Esto llevó a la creación de la clase `Nette\Object` (en 2007), que pretendía rectificar estos problemas y mejorar la comodidad de uso de PHP. Todo lo que se necesitaba era que otras clases heredaran de ella, y obtendrían los beneficios que ofrecía. Cuando PHP 5.4 introdujo el soporte para traits, la clase `Nette\Object` fue reemplazada por el trait `Nette\SmartObject`. Esto eliminó la necesidad de heredar de un ancestro común. Además, el trait podía ser usado en clases que ya heredaban de otra clase. El fin definitivo de `Nette\Object` llegó con el lanzamiento de PHP 7.2, que prohibió que las clases se llamaran `Object`. - -A medida que el desarrollo de PHP continuaba, su modelo de objetos y las capacidades del lenguaje mejoraron. Varias funciones de la clase `SmartObject` se volvieron redundantes. Desde el lanzamiento de PHP 8.2, sólo queda una característica no soportada directamente en PHP: la capacidad de usar las llamadas [propiedades |#Properties, getters, and setters]. - -¿Qué características ofrecían `Nette\Object` y, por extensión, `Nette\SmartObject`? He aquí un resumen. (En los ejemplos, se usa la clase `Nette\Object`, pero la mayoría de las características también se aplican al rasgo `Nette\SmartObject` ). - - -Errores incoherentes .[#toc-inconsistent-errors] ------------------------------------------------- -PHP tenía un comportamiento inconsistente al acceder a miembros no declarados. El estado en el momento de `Nette\Object` era el siguiente: - -```php -echo $obj->undeclared; // E_NOTICE, later E_WARNING -$obj->undeclared = 1; // passes silently without reporting -$obj->unknownMethod(); // Fatal error (not catchable by try/catch) -``` - -Un error fatal terminaba la aplicación sin posibilidad de reaccionar. La escritura silenciosa en miembros inexistentes sin previo aviso podía dar lugar a errores graves difíciles de detectar. `Nette\Object` Todos estos casos eran detectados y se lanzaba una excepción `MemberAccessException`. - -```php -echo $obj->undeclared; // throw Nette\MemberAccessException -$obj->undeclared = 1; // throw Nette\MemberAccessException -$obj->unknownMethod(); // throw Nette\MemberAccessException +$circle->radius = 10; // en realidad llama a setRadius(10) +echo $circle->radius; // llama a getRadius() +echo $circle->visible; // llama a isVisible() ``` -Desde PHP 7.0, PHP ya no causa errores fatales no capturables, y acceder a miembros no declarados ha sido un error desde PHP 8.2. - -¿Te refieres a? .[#toc-did-you-mean] ------------------------------------- -Si se lanzaba un error `Nette\MemberAccessException`, quizás debido a un error tipográfico al acceder a una variable de objeto o al llamar a un método, `Nette\Object` intentaba dar una pista en el mensaje de error sobre cómo solucionar el error, en la forma del icónico apéndice "¿querías decir?". +Desde PHP 8.4, se puede lograr la misma funcionalidad usando property hooks, que ofrecen una sintaxis mucho más elegante y concisa: ```php -class Foo extends Nette\Object +class Circle { - public static function from($var) - { + public float $radius = 0.0 { + set => max(0.0, $value); } -} -$foo = Foo::form($var); -// throw Nette\MemberAccessException -// "Call to undefined static method Foo::form(), did you mean from()?" + public bool $visible { + get => $this->radius > 0; + } +} ``` -Aunque el PHP actual no tiene la función "¿Querías decir?", esta frase puede ser añadida a los errores por [Tracy |tracy:]. Incluso puede [autocorregir dichos errores |tracy:open-files-in-ide#toc-demos]. - -Métodos de extensión .[#toc-extension-methods] ----------------------------------------------- -Inspirado en los métodos de extensión de C#. Ofrecen la posibilidad de añadir nuevos métodos a clases existentes. Por ejemplo, podrías añadir el método `addDateTime()` a un formulario para añadir tu propio DateTimePicker. +Métodos de Extensión +-------------------- +`Nette\Object` trajo otro concepto interesante a PHP inspirado en lenguajes de programación modernos - los métodos de extensión. Esta característica, tomada de C#, permitía a los desarrolladores extender elegantemente las clases existentes con nuevos métodos sin modificarlas ni heredar de ellas. Por ejemplo, podías agregar un método `addDateTime()` a un formulario que añade un DateTimePicker personalizado: ```php Form::extensionMethod( @@ -131,22 +137,22 @@ $form = new Form; $form->addDateTime('date'); ``` -Los métodos de extensión resultaron ser poco prácticos porque sus nombres no eran autocompletados por los editores, sino que informaban de que el método no existía. Por lo tanto, su soporte fue descontinuado. +Los métodos de extensión resultaron poco prácticos porque los editores no sugerían sus nombres y, en cambio, informaban que el método no existía. Por lo tanto, se descontinuó su soporte. Hoy en día, es más común usar composición o herencia para extender la funcionalidad de las clases. -Obtención del nombre de la clase .[#toc-getting-the-class-name] ---------------------------------------------------------------- +Obtener el Nombre de la Clase +----------------------------- +SmartObject ofrecía un método simple para obtener el nombre de la clase: ```php -$class = $obj->getClass(); // using Nette\Object -$class = $obj::class; // since PHP 8.0 +$class = $obj->getClass(); // usando Nette\Object +$class = $obj::class; // desde PHP 8.0 ``` -Acceso a la reflexión y a las anotaciones .[#toc-access-to-reflection-and-annotations] --------------------------------------------------------------------------------------- - -`Nette\Object` ofrece acceso a la reflexión y a las anotaciones mediante los métodos `getReflection()` y `getAnnotation()`: +Acceso a Reflexión y Anotaciones +-------------------------------- +`Nette\Object` proporcionaba acceso a la reflexión y anotaciones a través de los métodos `getReflection()` y `getAnnotation()`. Este enfoque simplificó significativamente el trabajo con la metainformación de las clases: ```php /** @@ -158,10 +164,10 @@ class Foo extends Nette\Object $obj = new Foo; $reflection = $obj->getReflection(); -$reflection->getAnnotation('author'); // returns 'John Doe' +$reflection->getAnnotation('author'); // devuelve 'John Doe' ``` -A partir de PHP 8.0, es posible acceder a meta-información en forma de atributos: +Desde PHP 8.0, es posible acceder a la metainformación a través de atributos, que ofrecen aún más posibilidades y mejor verificación de tipos: ```php #[Author('John Doe')] @@ -175,10 +181,9 @@ $reflection->getAttributes(Author::class)[0]; ``` -Método getters .[#toc-method-getters] -------------------------------------- - -`Nette\Object` ofrecían una forma elegante de tratar los métodos como si fueran variables: +Getters de Métodos +------------------ +`Nette\Object` ofrecía una forma elegante de pasar métodos como si fueran variables: ```php class Foo extends Nette\Object @@ -194,7 +199,7 @@ $method = $obj->adder; echo $method(2, 3); // 5 ``` -A partir de PHP 8.1, se puede utilizar la llamada "sintaxis callable de primera clase":https://www.php.net/manual/en/functions.first_class_callable_syntax: +Desde PHP 8.1, puedes usar la "first-class callable syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax, que lleva este concepto aún más lejos: ```php $obj = new Foo; @@ -203,10 +208,9 @@ echo $method(2, 3); // 5 ``` -Eventos .[#toc-events] ----------------------- - -`Nette\Object` ofrece azúcar sintáctico para activar el [evento |nette:glossary#events]: +Eventos +------- +SmartObject ofrece una sintaxis simplificada para trabajar con [eventos|nette:glossary#events]. Los eventos permiten a los objetos informar a otras partes de la aplicación sobre cambios en su estado: ```php class Circle extends Nette\Object @@ -221,7 +225,7 @@ class Circle extends Nette\Object } ``` -El código `$this->onChange($this, $radius)` es equivalente al siguiente: +El código `$this->onChange($this, $radius)` es equivalente al siguiente bucle: ```php foreach ($this->onChange as $callback) { @@ -229,7 +233,7 @@ foreach ($this->onChange as $callback) { } ``` -Por claridad, recomendamos evitar el método mágico `$this->onChange()`. Un buen sustituto es [Nette\Utils\Arrays::invoke |arrays#invoke]: +Por claridad, recomendamos evitar el método mágico `$this->onChange()`. Un reemplazo práctico es la función [Nette\Utils\Arrays::invoke|arrays#invoke]: ```php Nette\Utils\Arrays::invoke($this->onChange, $this, $radius); diff --git a/utils/fr/smartobject.texy b/utils/fr/smartobject.texy index 9458d913bb..35972fd95f 100644 --- a/utils/fr/smartobject.texy +++ b/utils/fr/smartobject.texy @@ -2,7 +2,7 @@ SmartObject *********** .[perex] -SmartObject corrigeait le comportement des objets de plusieurs façons, mais le PHP d'aujourd'hui inclut déjà la plupart de ces améliorations de façon native. Cependant, il ajoute encore le support des *propriétés*. +SmartObject a amélioré pendant des années le comportement des objets en PHP. Depuis PHP 8.4, toutes ses fonctionnalités font partie intégrante de PHP, accomplissant ainsi sa mission historique de pionnier de l'approche orientée objet moderne en PHP. Installation : @@ -11,19 +11,64 @@ Installation : composer require nette/utils ``` +SmartObject est né en 2007 comme une solution révolutionnaire aux limitations du modèle objet de PHP de l'époque. À une période où PHP souffrait de nombreux problèmes de conception orientée objet, il a apporté des améliorations significatives et simplifié le travail des développeurs. Il est devenu une partie légendaire du framework Nette. Il proposait des fonctionnalités que PHP n'obtiendrait que de nombreuses années plus tard - de la validation d'accès aux propriétés jusqu'à la gestion sophistiquée des erreurs. Avec l'arrivée de PHP 8.4, il a achevé sa mission historique, car toutes ses fonctionnalités sont devenues des parties natives du langage. Il était en avance sur le développement de PHP de 17 années remarquables. -Propriétés, getters et setters .[#toc-properties-getters-and-setters] -===================================================================== +SmartObject a connu une évolution technique intéressante. Initialement, il était implémenté comme une classe `Nette\Object`, dont les autres classes héritaient les fonctionnalités nécessaires. Un changement majeur est survenu avec PHP 5.4, qui a introduit le support des traits. Cela a permis sa transformation en trait `Nette\SmartObject`, apportant plus de flexibilité - les développeurs pouvaient utiliser ses fonctionnalités même dans les classes qui héritaient déjà d'une autre classe. Alors que la classe originale `Nette\Object` a cessé d'exister avec PHP 7.2 (qui interdisait de nommer les classes avec le mot 'Object'), le trait `Nette\SmartObject` continue d'exister. -Dans les langages modernes orientés objet (par exemple C#, Python, Ruby, JavaScript), le terme *propriété* fait référence aux [membres spéciaux des classes |https://en.wikipedia.org/wiki/Property_(programming)] qui ressemblent à des variables mais sont en fait représentés par des méthodes. Lorsque la valeur de cette "variable" est assignée ou lue, la méthode correspondante (appelée getter ou setter) est appelée. C'est très pratique, cela nous donne un contrôle total sur l'accès aux variables. Nous pouvons valider l'entrée ou générer des résultats uniquement lorsque la propriété est lue. +Examinons les fonctionnalités que `Nette\Object` et plus tard `Nette\SmartObject` offraient. Chacune de ces fonctions représentait à l'époque une avancée significative dans la programmation orientée objet en PHP. -Les propriétés PHP ne sont pas prises en charge, mais le trait `Nette\SmartObject` peut les imiter. Comment l'utiliser ? -- Ajoutez une annotation à la classe sous la forme `@property $xyz` -- Créez un getter nommé `getXyz()` ou `isXyz()`, un setter nommé `setXyz()` -- Le getter et le setter doivent être *public* ou *protégé* et sont optionnels, donc il peut y avoir une propriété *lire seulement* ou *écrire seulement*. +États d'erreur cohérents +------------------------ +L'un des problèmes les plus pressants du PHP initial était le comportement incohérent lors du travail avec les objets. `Nette\Object` a apporté ordre et prévisibilité dans ce chaos. Voici comment PHP se comportait à l'origine : -Nous utiliserons la propriété de la classe Circle pour nous assurer que seuls des nombres non négatifs sont placés dans la variable `$radius`. Remplacez `public $radius` par la propriété : +```php +echo $obj->undeclared; // E_NOTICE, plus tard E_WARNING +$obj->undeclared = 1; // passe silencieusement sans avertissement +$obj->unknownMethod(); // Fatal error (non capturable par try/catch) +``` + +Une erreur fatale arrêtait l'application sans possibilité de réaction. L'écriture silencieuse dans des membres non existants sans avertissement pouvait conduire à des erreurs graves difficiles à détecter. `Nette\Object` capturait tous ces cas et lançait une exception `MemberAccessException`, permettant aux programmeurs de réagir et de gérer ces erreurs : + +```php +echo $obj->undeclared; // lance Nette\MemberAccessException +$obj->undeclared = 1; // lance Nette\MemberAccessException +$obj->unknownMethod(); // lance Nette\MemberAccessException +``` + +Depuis PHP 7.0, le langage ne provoque plus d'erreurs fatales non capturables, et depuis PHP 8.2, l'accès aux membres non déclarés est considéré comme une erreur. + + +Assistant « Did you mean ? » +---------------------------- +`Nette\Object` est venu avec une fonctionnalité très pratique : des suggestions intelligentes pour les fautes de frappe. Quand un développeur faisait une erreur dans le nom d'une méthode ou d'une variable, il ne signalait pas seulement l'erreur mais proposait aussi une aide en suggérant le nom correct. Ce message iconique, connu sous le nom de « did you mean ? », a fait gagner aux programmeurs des heures de recherche de fautes de frappe : + +```php +class Foo extends Nette\Object +{ + public static function from($var) + { + } +} + +$foo = Foo::form($var); +// lance Nette\MemberAccessException +// "Call to undefined static method Foo::form(), did you mean from()?" +``` + +Bien que PHP lui-même n'ait aucune forme de « did you mean ? », cette fonctionnalité est maintenant fournie par [Tracy|tracy:]. Il peut même [auto-corriger|tracy:open-files-in-ide#demos] ces erreurs. + + +Propriétés avec accès contrôlé +------------------------------ +Une innovation significative que SmartObject a apportée à PHP était les propriétés avec accès contrôlé. Ce concept, courant dans des langages comme C# ou Python, permettait aux développeurs de contrôler élégamment l'accès aux données d'objet et d'assurer leur cohérence. Les propriétés sont un outil puissant de la programmation orientée objet. Elles fonctionnent comme des variables mais sont en réalité représentées par des méthodes (getters et setters). Cela permet la validation des entrées ou la génération de valeurs au moment de la lecture. + +Pour utiliser les propriétés, vous devez : +- Ajouter l'annotation `@property $xyz` à la classe +- Créer un getter nommé `getXyz()` ou `isXyz()`, un setter nommé `setXyz()` +- Vous assurer que le getter et le setter sont *public* ou *protected*. Ils sont optionnels - peuvent donc exister comme propriétés *read-only* ou *write-only* + +Voyons un exemple pratique avec la classe Circle, où nous utiliserons les propriétés pour garantir que le rayon est toujours non négatif. Nous remplacerons `public $radius` par une propriété : ```php /** @@ -34,22 +79,22 @@ class Circle { use Nette\SmartObject; - private float $radius = 0.0; // not public + private float $radius = 0.0; // pas public ! - // getter for property $radius + // getter pour la propriété $radius protected function getRadius(): float { return $this->radius; } - // setter for property $radius + // setter pour la propriété $radius protected function setRadius(float $radius): void { - // sanitizing value before saving it + // nous assainissons la valeur avant de la sauvegarder $this->radius = max(0.0, $radius); } - // getter for property $visible + // getter pour la propriété $visible protected function isVisible(): bool { return $this->radius > 0; @@ -57,69 +102,30 @@ class Circle } $circle = new Circle; -$circle->radius = 10; // actually calls setRadius(10) -echo $circle->radius; // calls getRadius() -echo $circle->visible; // calls isVisible() -``` - -Les propriétés sont principalement du "sucre syntaxique" ((sucre syntaxique)), destiné à rendre la vie du programmeur plus douce en simplifiant le code. Si vous n'en voulez pas, vous n'êtes pas obligé de les utiliser. - - -Un aperçu de l'histoire .[#toc-a-glimpse-into-history] -====================================================== - -SmartObject permettait d'affiner le comportement des objets de nombreuses manières, mais le PHP d'aujourd'hui incorpore déjà la plupart de ces améliorations de manière native. Le texte suivant est un regard nostalgique sur l'histoire, nous rappelant comment les choses ont évolué. - -Dès le début, le modèle objet de PHP a souffert d'une myriade de lacunes et de déficiences. Cela a conduit à la création de la classe `Nette\Object` (en 2007), qui visait à corriger ces problèmes et à améliorer le confort d'utilisation de PHP. Il suffisait que d'autres classes héritent de cette classe pour bénéficier des avantages qu'elle offrait. Lorsque PHP 5.4 a introduit le support des traits, la classe `Nette\Object` a été remplacée par le trait `Nette\SmartObject`. Cela a éliminé le besoin d'hériter d'un ancêtre commun. De plus, le trait pouvait être utilisé dans des classes qui héritaient déjà d'une autre classe. La fin définitive de `Nette\Object` est intervenue avec la publication de PHP 7.2, qui a interdit aux classes d'être nommées `Object`. - -Au fur et à mesure du développement de PHP, le modèle d'objet et les capacités du langage se sont améliorés. Plusieurs fonctions de la classe `SmartObject` sont devenues redondantes. Depuis la sortie de PHP 8.2, il ne reste plus qu'une seule fonctionnalité non directement supportée par PHP : la possibilité d'utiliser ce que l'on appelle des [propriétés |#Properties, getters, and setters]. - -Quelles sont les fonctionnalités offertes par `Nette\Object` et, par extension, par `Nette\SmartObject`? En voici un aperçu. (Dans les exemples, la classe `Nette\Object` est utilisée, mais la plupart des fonctionnalités s'appliquent également au trait `Nette\SmartObject` ). - - -Erreurs de cohérence .[#toc-inconsistent-errors] ------------------------------------------------- -PHP avait un comportement incohérent lors de l'accès aux membres non déclarés. L'état au moment de `Nette\Object` était le suivant : - -```php -echo $obj->undeclared; // E_NOTICE, later E_WARNING -$obj->undeclared = 1; // passes silently without reporting -$obj->unknownMethod(); // Fatal error (not catchable by try/catch) +$circle->radius = 10; // appelle en réalité setRadius(10) +echo $circle->radius; // appelle getRadius() +echo $circle->visible; // appelle isVisible() ``` -Une erreur fatale terminait l'application sans possibilité de réagir. L'écriture silencieuse dans des membres inexistants sans avertissement pouvait entraîner des erreurs graves difficiles à détecter. `Nette\Object` Tous ces cas ont été détectés et une exception `MemberAccessException` a été levée. - -```php -echo $obj->undeclared; // throw Nette\MemberAccessException -$obj->undeclared = 1; // throw Nette\MemberAccessException -$obj->unknownMethod(); // throw Nette\MemberAccessException -``` -Depuis PHP 7.0, PHP ne provoque plus d'erreurs fatales non capturables, et l'accès à des membres non déclarés est un bug depuis PHP 8.2. - - -Voulez-vous dire ? .[#toc-did-you-mean] ---------------------------------------- -Si une erreur `Nette\MemberAccessException` était déclenchée, peut-être à cause d'une faute de frappe lors de l'accès à une variable d'objet ou de l'appel d'une méthode, `Nette\Object` tentait de donner un indice dans le message d'erreur sur la façon de corriger l'erreur, sous la forme de l'addendum emblématique "Did you mean ?". +Depuis PHP 8.4, la même fonctionnalité peut être réalisée en utilisant les property hooks, qui offrent une syntaxe beaucoup plus élégante et concise : ```php -class Foo extends Nette\Object +class Circle { - public static function from($var) - { + public float $radius = 0.0 { + set => max(0.0, $value); } -} -$foo = Foo::form($var); -// throw Nette\MemberAccessException -// "Call to undefined static method Foo::form(), did you mean from()?" + public bool $visible { + get => $this->radius > 0; + } +} ``` -Bien que le PHP d'aujourd'hui n'ait pas de fonction "did you mean ?", cette phrase peut être ajoutée aux erreurs par [Tracy |tracy:]. Il peut même [corriger automatiquement ces erreurs |tracy:open-files-in-ide#toc-demos]. - -Méthodes d'extension .[#toc-extension-methods] ----------------------------------------------- -Inspiré par les méthodes d'extension de C#. Elles donnaient la possibilité d'ajouter de nouvelles méthodes à des classes existantes. Par exemple, vous pouvez ajouter la méthode `addDateTime()` à un formulaire pour ajouter votre propre DateTimePicker. +Extension Methods +----------------- +`Nette\Object` a apporté un autre concept intéressant à PHP inspiré des langages de programmation modernes - les extension methods. Cette fonctionnalité, empruntée à C#, permettait aux développeurs d'étendre élégamment les classes existantes avec de nouvelles méthodes sans les modifier ni en hériter. Par exemple, vous pouviez ajouter une méthode `addDateTime()` à un formulaire qui ajoute un DateTimePicker personnalisé : ```php Form::extensionMethod( @@ -131,22 +137,22 @@ $form = new Form; $form->addDateTime('date'); ``` -Les méthodes d'extension se sont avérées peu pratiques car leurs noms n'étaient pas autocomplétés par les éditeurs, qui signalaient au contraire que la méthode n'existait pas. Par conséquent, leur prise en charge a été abandonnée. +Les extension methods se sont révélées peu pratiques car les éditeurs ne suggéraient pas leurs noms et signalaient au contraire que la méthode n'existait pas. Par conséquent, leur support a été abandonné. Aujourd'hui, il est plus courant d'utiliser la composition ou l'héritage pour étendre les fonctionnalités des classes. -Obtention du nom de la classe .[#toc-getting-the-class-name] ------------------------------------------------------------- +Obtention du nom de la classe +----------------------------- +SmartObject proposait une méthode simple pour obtenir le nom de la classe : ```php -$class = $obj->getClass(); // using Nette\Object -$class = $obj::class; // since PHP 8.0 +$class = $obj->getClass(); // avec Nette\Object +$class = $obj::class; // depuis PHP 8.0 ``` -Accès à la réflexion et aux annotations .[#toc-access-to-reflection-and-annotations] ------------------------------------------------------------------------------------- - -`Nette\Object` a proposé un accès à la réflexion et aux annotations en utilisant les méthodes `getReflection()` et `getAnnotation()`: +Accès à la réflexion et aux annotations +--------------------------------------- +`Nette\Object` fournissait un accès à la réflexion et aux annotations via les méthodes `getReflection()` et `getAnnotation()`. Cette approche simplifiait significativement le travail avec les méta-informations des classes : ```php /** @@ -158,10 +164,10 @@ class Foo extends Nette\Object $obj = new Foo; $reflection = $obj->getReflection(); -$reflection->getAnnotation('author'); // returns 'John Doe' +$reflection->getAnnotation('author'); // renvoie 'John Doe' ``` -Depuis PHP 8.0, il est possible d'accéder aux méta-informations sous forme d'attributs : +Depuis PHP 8.0, il est possible d'accéder aux méta-informations via les attributs, qui offrent encore plus de possibilités et un meilleur contrôle de type : ```php #[Author('John Doe')] @@ -175,10 +181,9 @@ $reflection->getAttributes(Author::class)[0]; ``` -Les récupérateurs de méthodes .[#toc-method-getters] ----------------------------------------------------- - -`Nette\Object` offraient un moyen élégant de traiter les méthodes comme s'il s'agissait de variables : +Getters de méthodes +------------------- +`Nette\Object` offrait une façon élégante de passer des méthodes comme s'il s'agissait de variables : ```php class Foo extends Nette\Object @@ -194,7 +199,7 @@ $method = $obj->adder; echo $method(2, 3); // 5 ``` -Depuis PHP 8.1, vous pouvez utiliser la syntaxe:https://www.php.net/manual/en/functions.first_class_callable_syntax dite "first-class callable":https://www.php.net/manual/en/functions.first_class_callable_syntax: +Depuis PHP 8.1, vous pouvez utiliser la "first-class callable syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax, qui pousse ce concept encore plus loin : ```php $obj = new Foo; @@ -203,10 +208,9 @@ echo $method(2, 3); // 5 ``` -Événements .[#toc-events] -------------------------- - -`Nette\Object` a offert un sucre syntaxique pour déclencher l'[événement |nette:glossary#events]: +Événements +---------- +SmartObject offre une syntaxe simplifiée pour travailler avec les [événements|nette:glossary#events]. Les événements permettent aux objets d'informer les autres parties de l'application des changements de leur état : ```php class Circle extends Nette\Object @@ -221,7 +225,7 @@ class Circle extends Nette\Object } ``` -Le code `$this->onChange($this, $radius)` est équivalent à ce qui suit : +Le code `$this->onChange($this, $radius)` est équivalent à la boucle suivante : ```php foreach ($this->onChange as $callback) { @@ -229,7 +233,7 @@ foreach ($this->onChange as $callback) { } ``` -Pour des raisons de clarté, nous vous recommandons d'éviter la méthode magique `$this->onChange()`. Un bon substitut est [Nette\Utils\Arrays::invoke |arrays#invoke]: +Pour plus de clarté, nous recommandons d'éviter la méthode magique `$this->onChange()`. Un remplacement pratique est la fonction [Nette\Utils\Arrays::invoke|arrays#invoke] : ```php Nette\Utils\Arrays::invoke($this->onChange, $this, $radius); diff --git a/utils/hu/smartobject.texy b/utils/hu/smartobject.texy index eb81664c98..7b1d52dbbe 100644 --- a/utils/hu/smartobject.texy +++ b/utils/hu/smartobject.texy @@ -2,7 +2,7 @@ SmartObject *********** .[perex] -A SmartObject korábban sokféleképpen javította az objektumok viselkedését, de a mai PHP már natívan tartalmazza ezen fejlesztések nagy részét. Azonban még mindig hozzáadja a *tulajdonságok* támogatását. +A SmartObject éveken át fejlesztette a PHP objektumok viselkedését. A PHP 8.4 verziótól kezdve minden funkciója beépült magába a PHP nyelvbe, így teljesítve történelmi küldetését a modern objektumorientált megközelítés úttörőjeként. Telepítés: @@ -11,19 +11,64 @@ Telepítés: composer require nette/utils ``` +A SmartObject 2007-ben jött létre, mint forradalmi megoldás az akkori PHP objektummodell hiányosságaira. Amikor a PHP számos objektumorientált tervezési problémával küzdött, jelentős fejlesztéseket és egyszerűsítéseket hozott a fejlesztők munkájába. A Nette framework legendás részévé vált. Olyan funkcionalitást kínált, amelyet a PHP csak sok évvel később ért el - az objektumtulajdonságok validálásától a kifinomult hibakezelésig. A PHP 8.4 megjelenésével befejezte történelmi küldetését, mivel minden funkciója a nyelv natív részévé vált. Figyelemreméltó módon 17 évvel előzte meg a PHP fejlődését. -Tulajdonságok, Getterek és Setterek .[#toc-properties-getters-and-setters] -========================================================================== +A SmartObject érdekes technikai fejlődésen ment keresztül. Eredetileg `Nette\Object` osztályként implementálták, amelyből más osztályok örökölték a szükséges funkcionalitást. Jelentős változás jött a PHP 5.4-gyel, amely bevezette a trait-ek támogatását. Ez lehetővé tette az átalakulást `Nette\SmartObject` trait-té, ami nagyobb rugalmasságot hozott - a fejlesztők olyan osztályokban is használhatták a funkcionalitást, amelyek már örököltek egy másik osztályból. Míg az eredeti `Nette\Object` osztály megszűnt a PHP 7.2 megjelenésével (amely megtiltotta az osztályok 'Object' szóval való elnevezését), a `Nette\SmartObject` trait tovább él. -A modern objektumorientált nyelvekben (pl. C#, Python, Ruby, JavaScript) a *tulajdonság* kifejezés az [osztályok speciális tagjaira |https://en.wikipedia.org/wiki/Property_(programming)] utal, amelyek változóknak tűnnek, de valójában metódusok képviselik őket. Amikor ennek a "változónak" az értékét hozzárendeljük vagy kiolvassuk, a megfelelő metódust (az úgynevezett gettert vagy settert) hívjuk meg. Ez egy nagyon praktikus dolog, teljes kontrollt biztosít számunkra a változókhoz való hozzáférés felett. Csak akkor tudjuk érvényesíteni a bemenetet, vagy csak akkor generálhatunk eredményt, ha a tulajdonságot kiolvassuk. +Nézzük át azokat a tulajdonságokat, amelyeket egykor a `Nette\Object`, majd később a `Nette\SmartObject` kínált. Mindegyik funkció jelentős előrelépést jelentett a PHP objektumorientált programozásában a maga idejében. -A PHP tulajdonságok nem támogatottak, de a `Nette\SmartObject` trait képes utánozni őket. Hogyan használjuk? -- Adjunk hozzá egy megjegyzést az osztályhoz a következő formában `@property $xyz` -- Hozzon létre egy `getXyz()` vagy `isXyz()` nevű gettert, egy settert, amelynek a neve `setXyz()` -- A getter és a setter *nyilvános* vagy *védett* kell, hogy legyen, és opcionális, tehát lehet *read-only* vagy *write-only* tulajdonság. +Konzisztens hibaállapotok +------------------------- +A korai PHP egyik legégetőbb problémája az objektumokkal való munka következetlen viselkedése volt. A `Nette\Object` rendet és kiszámíthatóságot hozott ebbe a káoszba. Nézzük meg, hogyan működött eredetileg a PHP: -A Circle osztály tulajdonságát fogjuk használni annak biztosítására, hogy a `$radius` változóba csak nem negatív számok kerüljenek. Helyettesítsük a `public $radius` címet a tulajdonsággal: +```php +echo $obj->undeclared; // E_NOTICE, később E_WARNING +$obj->undeclared = 1; // csendben lefut, figyelmeztetés nélkül +$obj->unknownMethod(); // Fatal error (nem elfogható try/catch-csel) +``` + +A Fatal error leállította az alkalmazást anélkül, hogy bármilyen reakcióra lehetőség lett volna. A nem létező tagok csendes írása figyelmeztetés nélkül súlyos hibákhoz vezethetett, amelyeket nehéz volt felderíteni. A `Nette\Object` minden ilyen esetet elkapott és `MemberAccessException` kivételt dobott, lehetővé téve a programozóknak, hogy reagáljanak és kezeljék ezeket a hibákat: + +```php +echo $obj->undeclared; // Nette\MemberAccessException kivételt dob +$obj->undeclared = 1; // Nette\MemberAccessException kivételt dob +$obj->unknownMethod(); // Nette\MemberAccessException kivételt dob +``` + +A PHP 7.0 óta a nyelv már nem okoz elfoghatatlan fatal error-t, és a PHP 8.2 óta a nem deklarált tagok elérése hibaként kezelendő. + + +"Did you mean?" segítség +------------------------ +A `Nette\Object` egy nagyon hasznos funkcióval érkezett: intelligens javaslatokkal elgépelések esetén. Amikor egy fejlesztő hibát vétett egy metódus vagy változó nevében, nemcsak jelezte a hibát, hanem segítséget is nyújtott a helyes név javaslatával. Ez az ikonikus üzenet, amely "did you mean?" néven vált ismertté, órákat spórolt meg a programozóknak az elgépelések keresésében: + +```php +class Foo extends Nette\Object +{ + public static function from($var) + { + } +} + +$foo = Foo::form($var); +// Nette\MemberAccessException kivételt dob +// "Call to undefined static method Foo::form(), did you mean from()?" +``` + +Bár a mai PHP-nek nincs beépített "did you mean?" funkciója, ezt a kiegészítést a [Tracy|tracy:] biztosítja. Sőt, az ilyen hibákat [automatikusan javítani|tracy:open-files-in-ide#demos] is tudja. + + +Tulajdonságok ellenőrzött hozzáféréssel +--------------------------------------- +Jelentős újítás, amit a SmartObject hozott a PHP-ba, az ellenőrzött hozzáféréssel rendelkező tulajdonságok voltak. Ez a koncepció, amely olyan nyelvekben általános, mint a C# vagy Python, lehetővé tette a fejlesztőknek, hogy elegánsan szabályozzák az objektumadatok elérését és biztosítsák azok konzisztenciáját. A tulajdonságok az objektumorientált programozás hatékony eszközei. Változókként működnek, de valójában metódusok (getter-ek és setter-ek) reprezentálják őket. Ez lehetővé teszi a bemenetek validálását vagy az értékek generálását olvasás időpontjában. + +A tulajdonságok használatához szükséges: +- A `@property $xyz` annotáció hozzáadása az osztályhoz +- Getter létrehozása `getXyz()` vagy `isXyz()` néven, setter létrehozása `setXyz()` néven +- A getter és setter *public* vagy *protected* láthatóságú legyen. Opcionálisak - így létezhetnek *csak olvasható* vagy *csak írható* tulajdonságokként + +Nézzünk egy gyakorlati példát a Circle osztályon, ahol a tulajdonságokat használjuk annak biztosítására, hogy a sugár mindig nem negatív szám legyen. A `public $radius`-t tulajdonságra cseréljük: ```php /** @@ -34,7 +79,7 @@ class Circle { use Nette\SmartObject; - private float $radius = 0.0; // nem nyilvános + private float $radius = 0.0; // nem public! // getter a $radius tulajdonsághoz protected function getRadius(): float @@ -45,7 +90,7 @@ class Circle // setter a $radius tulajdonsághoz protected function setRadius(float $radius): void { - // az érték mentés előtti szanálása + // érték sanitizálása mentés előtt $this->radius = max(0.0, $radius); } @@ -57,69 +102,30 @@ class Circle } $circle = new Circle; -$circle->radius = 10; // valójában a setRadius(10) hívása. -echo $circle->radius; // meghívja a getRadius() függvényt. -echo $circle->visible; // hívja az isVisible() függvényt -``` - -A tulajdonságok elsősorban "szintaktikai cukor"((syntactic sugar)), amelynek célja, hogy a kód egyszerűsítésével megédesítse a programozó életét. Ha nem akarod őket, nem kell használni őket. - - -Pillantás a történelembe .[#toc-a-glimpse-into-history] -======================================================= - -A SmartObject korábban számos módon finomította az objektumok viselkedését, de a mai PHP már natívan tartalmazza ezen fejlesztések nagy részét. A következő szöveg egy nosztalgikus visszatekintés a történelembe, emlékeztetve minket a dolgok fejlődésére. - -A PHP objektummodellje a kezdetektől fogva számtalan komoly hiányosságtól és hiányosságtól szenvedett. Ez vezetett a `Nette\Object` osztály létrehozásához (2007-ben), amelynek célja ezen problémák orvoslása és a PHP használatának kényelmesebbé tétele volt. Mindössze arra volt szükség, hogy más osztályok is örököljenek belőle, és máris élvezhették az általa kínált előnyöket. Amikor a PHP 5.4 bevezette a tulajdonságok támogatását, a `Nette\Object` osztály helyébe a `Nette\SmartObject` tulajdonság lépett. Ezzel megszűnt a közös őstől való öröklés szükségessége. Sőt, a tulajdonságot olyan osztályokban is lehetett használni, amelyek már örököltek egy másik osztálytól. A `Nette\Object` végleges megszűnését a PHP 7.2 kiadása jelentette, amely megtiltotta, hogy az osztályok neve `Object` legyen. - -A PHP fejlesztésének előrehaladtával az objektummodell és a nyelvi képességek tovább fejlődtek. A `SmartObject` osztály különböző funkciói feleslegessé váltak. A PHP 8.2 kiadása óta csak egyetlen olyan funkció maradt, amelyet a PHP közvetlenül nem támogat: az úgynevezett [tulajdonságok |#Properties, getters, and setters] használatának lehetősége. - -Milyen funkciókat kínált a `Nette\Object` és ennek folytán a `Nette\SmartObject`? Íme egy áttekintés. (A példákban a `Nette\Object` osztályt használjuk, de a legtöbb funkció a `Nette\SmartObject` tulajdonságra is vonatkozik). - - -Inkonzisztens hibák .[#toc-inconsistent-errors] ------------------------------------------------ -A PHP következetlenül viselkedett a nem deklarált tagok elérésekor. Az állapot a `Nette\Object` idején a következő volt: - -```php -echo $obj->undeclared; // E_NOTICE, később E_WARNING -$obj->undeclared = 1; // csendben átmegy jelentés nélkül. -$obj->unknownMethod(); // Végzetes hiba (try/catch-el nem fogható) +$circle->radius = 10; // valójában a setRadius(10)-et hívja +echo $circle->radius; // getRadius()-t hív +echo $circle->visible; // isVisible()-t hív ``` -A végzetes hiba mindenféle reagálási lehetőség nélkül megszakította az alkalmazást. A nem létező tagokba való csendes írás figyelmeztetés nélkül súlyos, nehezen észlelhető hibákhoz vezethetett. `Nette\Object` Minden ilyen esetet elkaptunk, és a `MemberAccessException` címen egy kivételt dobtunk. - -```php -echo $obj->undeclared; // throw Nette\MemberAccessException -$obj->undeclared = 1; // throw Nette\MemberAccessException -$obj->unknownMethod(); // throw Nette\MemberAccessException -``` -A PHP 7.0 óta a PHP már nem okoz nem fogható halálos hibákat, a nem deklarált tagokhoz való hozzáférés pedig a PHP 8.2 óta hiba. - - -Úgy értetted? .[#toc-did-you-mean] ----------------------------------- -Ha egy `Nette\MemberAccessException` hiba lépett fel, például egy objektumváltozó elérésekor vagy egy metódus hívásakor elírás miatt, a `Nette\Object` megpróbált a hibaüzenetben egy tippet adni a hiba kijavítására, az ikonikus "did you mean?" kiegészítés formájában. +A PHP 8.4 óta ugyanez a funkcionalitás elérhető property hooks segítségével, amely sokkal elegánsabb és tömörebb szintaxist kínál: ```php -class Foo extends Nette\Object +class Circle { - public static function from($var) - { + public float $radius = 0.0 { + set => max(0.0, $value); } -} -$foo = Foo::form($var); -// throw Nette\MemberAccessException -// "Call to undefined static method Foo::form(), did you mean from()?" + public bool $visible { + get => $this->radius > 0; + } +} ``` -Bár a mai PHP nem rendelkezik "úgy értetted?" funkcióval, ez a mondat hozzáadható a hibákhoz a [Tracy |tracy:] által. Még az [ilyen hibákat |tracy:open-files-in-ide#toc-demos] is képes [automatikusan kijavítani |tracy:open-files-in-ide#toc-demos]. - -Bővítési módszerek .[#toc-extension-methods] --------------------------------------------- -A C# bővítési metódusok által inspirálva. Lehetőséget adtak új metódusok hozzáadására a meglévő osztályokhoz. Például a `addDateTime()` metódust hozzáadhatta egy űrlaphoz, hogy saját DateTimePickert adjon hozzá. +Extension methods (Kiterjesztő metódusok) +----------------------------------------- +A `Nette\Object` egy másik érdekes koncepciót hozott a PHP-ba a modern programozási nyelvekből - az extension methods-t. Ez a C#-ból kölcsönzött funkció lehetővé tette a fejlesztőknek, hogy elegánsan bővítsék a meglévő osztályokat új metódusokkal anélkül, hogy módosítaniuk kellene azokat vagy örökölniük kellene belőlük. Például hozzáadhattak egy `addDateTime()` metódust egy űrlaphoz, amely egy egyéni DateTimePicker-t ad hozzá: ```php Form::extensionMethod( @@ -131,22 +137,22 @@ $form = new Form; $form->addDateTime('date'); ``` -A kiterjesztési metódusok nem bizonyultak praktikusnak, mert a nevüket a szerkesztők nem töltötték ki automatikusan, hanem azt jelentették, hogy a metódus nem létezik. Ezért a támogatásuk megszűnt. +Az extension metódusok nem bizonyultak praktikusnak, mert az editorok nem ajánlották fel a nevüket, sőt jelezték, hogy a metódus nem létezik. Ezért a támogatásuk megszűnt. Ma már általánosabb a kompozíció vagy öröklődés használata az osztályfunkcionalitás kiterjesztésére. -Az osztály nevének megadása .[#toc-getting-the-class-name] ----------------------------------------------------------- +Osztálynév lekérdezése +---------------------- +A SmartObject egyszerű metódust kínált az osztálynév lekérdezésére: ```php -$class = $obj->getClass(); // using Nette\Object -$class = $obj::class; // PHP 8.0 óta +$class = $obj->getClass(); // Nette\Object használatával +$class = $obj::class; // PHP 8.0 óta ``` -Hozzáférés a reflexióhoz és a megjegyzésekhez .[#toc-access-to-reflection-and-annotations] ------------------------------------------------------------------------------------------- - -`Nette\Object` a `getReflection()` és a `getAnnotation()` metódusok segítségével kínált hozzáférést a reflexióhoz és a megjegyzésekhez: +Reflexió és annotáció hozzáférés +-------------------------------- +A `Nette\Object` hozzáférést biztosított a reflexióhoz és az annotációkhoz a `getReflection()` és `getAnnotation()` metódusok segítségével. Ez a megközelítés jelentősen egyszerűsítette az osztály metainformációkkal való munkát: ```php /** @@ -158,10 +164,10 @@ class Foo extends Nette\Object $obj = new Foo; $reflection = $obj->getReflection(); -$reflection->getAnnotation('author'); // visszaadja 'John Doe' +$reflection->getAnnotation('author'); // 'John Doe'-t ad vissza ``` -A PHP 8.0-tól kezdve a metainformációkat attribútumok formájában is elérhetjük: +A PHP 8.0 óta lehetséges a metainformációk elérése attribútumok formájában, amelyek még több lehetőséget és jobb típusellenőrzést kínálnak: ```php #[Author('John Doe')] @@ -175,10 +181,9 @@ $reflection->getAttributes(Author::class)[0]; ``` -Metódus Getterek .[#toc-method-getters] ---------------------------------------- - -`Nette\Object` elegáns módot kínált arra, hogy a módszereket úgy kezeljük, mintha változók lennének: +Method getterek +--------------- +A `Nette\Object` elegáns módot kínált metódusok átadására, mintha változók lennének: ```php class Foo extends Nette\Object @@ -194,7 +199,7 @@ $method = $obj->adder; echo $method(2, 3); // 5 ``` -A PHP 8.1-től kezdve használhatod az úgynevezett "első osztályú hívható szintaxist":https://www.php.net/manual/en/functions.first_class_callable_syntax: +A PHP 8.1 óta használható az úgynevezett "first-class callable syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax, amely még tovább viszi ezt a koncepciót: ```php $obj = new Foo; @@ -203,10 +208,9 @@ echo $method(2, 3); // 5 ``` -Események .[#toc-events] ------------------------- - -`Nette\Object` szintaktikai cukrot kínált az [esemény |nette:glossary#events] kiváltásához: +Események +--------- +A SmartObject egyszerűsített szintaxist kínál az [események|nette:glossary#events] kezeléséhez. Az események lehetővé teszik az objektumoknak, hogy értesítsék az alkalmazás többi részét állapotuk változásairól: ```php class Circle extends Nette\Object @@ -221,7 +225,7 @@ class Circle extends Nette\Object } ``` -A `$this->onChange($this, $radius)` kód a következővel egyenértékű: +A `$this->onChange($this, $radius)` kód egyenértékű a következő ciklussal: ```php foreach ($this->onChange as $callback) { @@ -229,7 +233,7 @@ foreach ($this->onChange as $callback) { } ``` -Az áttekinthetőség kedvéért javasoljuk, hogy kerüljük a `$this->onChange()` varázsmódszert. Ennek praktikus helyettesítője a [Nette\Utils\Arrays::invoke |arrays#invoke] függvény: +Az átláthatóság érdekében javasoljuk a `$this->onChange()` mágikus metódus kerülését. Praktikus helyettesítője a [Nette\Utils\Arrays::invoke|arrays#invoke] függvény: ```php Nette\Utils\Arrays::invoke($this->onChange, $this, $radius); diff --git a/utils/it/smartobject.texy b/utils/it/smartobject.texy index a9247d68bc..5bf08dac64 100644 --- a/utils/it/smartobject.texy +++ b/utils/it/smartobject.texy @@ -2,7 +2,7 @@ SmartObject *********** .[perex] -SmartObject correggeva il comportamento degli oggetti in molti modi, ma il PHP di oggi include già la maggior parte di questi miglioramenti in modo nativo. Tuttavia, aggiunge ancora il supporto per le *proprietà*. +SmartObject ha migliorato per anni il comportamento degli oggetti in PHP. Dalla versione PHP 8.4, tutte le sue funzionalità sono diventate parte nativa di PHP stesso, completando così la sua missione storica di essere pioniere dell'approccio orientato agli oggetti moderno in PHP. Installazione: @@ -11,19 +11,64 @@ Installazione: composer require nette/utils ``` +SmartObject è nato nel 2007 come soluzione rivoluzionaria alle carenze del modello a oggetti di PHP dell'epoca. In un periodo in cui PHP soffriva di numerosi problemi di design orientato agli oggetti, ha portato significativi miglioramenti e semplificazioni nel lavoro degli sviluppatori. È diventato una parte leggendaria del framework Nette. Ha offerto funzionalità che PHP avrebbe acquisito solo molti anni dopo - dalla validazione dell'accesso alle proprietà alla gestione sofisticata degli errori. Con l'arrivo di PHP 8.4, ha completato la sua missione storica, poiché tutte le sue funzionalità sono diventate parti native del linguaggio. Ha anticipato lo sviluppo di PHP di ben 17 anni. -Proprietà, Getter e Setter .[#toc-properties-getters-and-setters] -================================================================= +SmartObject ha attraversato un'interessante evoluzione tecnica. Inizialmente, è stato implementato come classe `Nette\Object`, dalla quale altre classi ereditavano la funzionalità necessaria. Un cambiamento significativo è arrivato con PHP 5.4, che ha introdotto il supporto per i trait. Questo ha permesso la trasformazione nel trait `Nette\SmartObject`, portando maggiore flessibilità - gli sviluppatori potevano utilizzare la funzionalità anche nelle classi che già ereditavano da un'altra classe. Mentre la classe originale `Nette\Object` ha cessato di esistere con PHP 7.2 (che ha proibito di nominare le classi con la parola 'Object'), il trait `Nette\SmartObject` continua a esistere. -Nei moderni linguaggi orientati agli oggetti (ad esempio, C#, Python, Ruby, JavaScript), il termine *property* si riferisce a [membri speciali delle classi |https://en.wikipedia.org/wiki/Property_(programming)] che sembrano variabili, ma in realtà sono rappresentati da metodi. Quando il valore di questa "variabile" viene assegnato o letto, viene richiamato il metodo corrispondente (chiamato getter o setter). Si tratta di una cosa molto comoda, che ci dà il pieno controllo sull'accesso alle variabili. Possiamo convalidare l'input o generare risultati solo quando la proprietà viene letta. +Esaminiamo le funzionalità che `Nette\Object` e successivamente `Nette\SmartObject` offrivano. Ognuna di queste funzioni rappresentava un significativo passo avanti nella programmazione orientata agli oggetti in PHP. -Le proprietà PHP non sono supportate, ma il trait `Nette\SmartObject` può imitarle. Come si usa? -- Aggiungere un'annotazione alla classe nella forma `@property $xyz` +Stati di Errore Consistenti +--------------------------- +Uno dei problemi più urgenti del primo PHP era il comportamento inconsistente nel lavoro con gli oggetti. `Nette\Object` ha portato ordine e prevedibilità in questo caos. Vediamo come si comportava PHP originariamente: + +```php +echo $obj->undeclared; // E_NOTICE, successivamente E_WARNING +$obj->undeclared = 1; // passa silenziosamente senza avviso +$obj->unknownMethod(); // Fatal error (non catturabile con try/catch) +``` + +Fatal error terminava l'applicazione senza possibilità di reazione. La scrittura silenziosa su membri non esistenti senza avviso poteva portare a errori gravi difficili da rilevare. `Nette\Object` catturava tutti questi casi e lanciava una `MemberAccessException`, permettendo ai programmatori di reagire e gestire questi errori: + +```php +echo $obj->undeclared; // lancia Nette\MemberAccessException +$obj->undeclared = 1; // lancia Nette\MemberAccessException +$obj->unknownMethod(); // lancia Nette\MemberAccessException +``` + +Da PHP 7.0, il linguaggio non causa più errori fatali non catturabili e da PHP 8.2, l'accesso a membri non dichiarati è considerato un errore. + + +Suggerimento "Did you mean?" +---------------------------- +`Nette\Object` è arrivato con una funzionalità molto conveniente: i suggerimenti intelligenti per gli errori di battitura. Quando uno sviluppatore commetteva un errore nel nome di un metodo o di una variabile, non solo segnalava l'errore ma offriva anche aiuto suggerendo il nome corretto. Questo messaggio iconico, noto come "did you mean?", ha risparmiato agli sviluppatori ore di ricerca degli errori di battitura: + +```php +class Foo extends Nette\Object +{ + public static function from($var) + { + } +} + +$foo = Foo::form($var); +// lancia Nette\MemberAccessException +// "Call to undefined static method Foo::form(), did you mean from()?" +``` + +Mentre PHP stesso non ha alcuna forma di "did you mean?", questa funzionalità è ora fornita da [Tracy|tracy:]. Può persino [correggere automaticamente|tracy:open-files-in-ide#demos] questi errori. + + +Proprietà con Accesso Controllato +--------------------------------- +Un'innovazione significativa che SmartObject ha portato in PHP sono state le proprietà con accesso controllato. Questo concetto, comune in linguaggi come C# o Python, ha permesso agli sviluppatori di controllare elegantemente l'accesso ai dati dell'oggetto e garantire la loro consistenza. Le proprietà sono uno strumento potente della programmazione orientata agli oggetti. Funzionano come variabili ma sono in realtà rappresentate da metodi (getter e setter). Questo permette la validazione degli input o la generazione dei valori al momento della lettura. + +Per utilizzare le proprietà, è necessario: +- Aggiungere l'annotazione `@property $xyz` alla classe - Creare un getter chiamato `getXyz()` o `isXyz()`, un setter chiamato `setXyz()` -- Il getter e il setter devono essere *pubblici* o *protetti* e sono opzionali, quindi può esserci una proprietà *di sola lettura* o *di sola scrittura*. +- Assicurarsi che getter e setter siano *public* o *protected*. Sono opzionali - quindi possono esistere come proprietà *read-only* o *write-only* -Utilizzeremo la proprietà per la classe Circle per garantire che nella variabile `$radius` vengano inseriti solo numeri non negativi. Sostituire `public $radius` con la proprietà: +Vediamo un esempio pratico usando la classe Circle, dove useremo le proprietà per garantire che il raggio sia sempre non negativo. Sostituiremo `public $radius` con una proprietà: ```php /** @@ -34,7 +79,7 @@ class Circle { use Nette\SmartObject; - private float $radius = 0.0; // non pubblico + private float $radius = 0.0; // non public! // getter per la proprietà $radius protected function getRadius(): float @@ -45,7 +90,7 @@ class Circle // setter per la proprietà $radius protected function setRadius(float $radius): void { - // sanitizza il valore prima di salvarlo + // sanitizziamo il valore prima del salvataggio $this->radius = max(0.0, $radius); } @@ -57,69 +102,30 @@ class Circle } $circle = new Circle; -$circle->radius = 10; // in realtà chiama setRadius(10) -echo $circle->radius; // chiama getRadius() +$circle->radius = 10; // in realtà chiama setRadius(10) +echo $circle->radius; // chiama getRadius() echo $circle->visible; // chiama isVisible() ``` -Le proprietà sono principalmente "zucchero sintattico" ((syntactic sugar)), che ha lo scopo di rendere più dolce la vita del programmatore semplificando il codice. Se non le si vuole, non è necessario usarle. - - -Uno sguardo alla storia .[#toc-a-glimpse-into-history] -====================================================== - -SmartObject era solito perfezionare il comportamento degli oggetti in molti modi, ma il PHP di oggi incorpora già la maggior parte di questi miglioramenti in modo nativo. Il testo che segue è uno sguardo nostalgico alla storia, che ci ricorda come si sono evolute le cose. - -Fin dall'inizio, il modello a oggetti di PHP soffriva di una miriade di gravi mancanze e carenze. Questo ha portato alla creazione della classe `Nette\Object` (nel 2007), che mirava a correggere questi problemi e a migliorare il comfort dell'utilizzo di PHP. Bastava che altre classi ereditassero da essa per ottenere i vantaggi che offriva. Quando PHP 5.4 ha introdotto il supporto ai tratti, la classe `Nette\Object` è stata sostituita dal tratto `Nette\SmartObject`. Questo ha eliminato la necessità di ereditare da un antenato comune. Inoltre, il tratto poteva essere usato in classi che già ereditavano da un'altra classe. La fine definitiva di `Nette\Object` avvenne con il rilascio di PHP 7.2, che proibiva alle classi di chiamarsi `Object`. - -Con il proseguire dello sviluppo di PHP, il suo modello di oggetti e le capacità del linguaggio sono migliorati. Diverse funzioni della classe `SmartObject` sono diventate superflue. Dal rilascio di PHP 8.2, rimane solo una caratteristica non supportata direttamente da PHP: la possibilità di usare le cosiddette [proprietà |#Properties, getters, and setters]. - -Quali caratteristiche offrivano `Nette\Object` e, per estensione, `Nette\SmartObject`? Ecco una panoramica. (Negli esempi viene utilizzata la classe `Nette\Object`, ma la maggior parte delle caratteristiche si applicano anche al tratto `Nette\SmartObject` ). - - -Errori inconsistenti .[#toc-inconsistent-errors] ------------------------------------------------- -PHP aveva un comportamento incoerente quando si accedeva a membri non dichiarati. Lo stato al momento di `Nette\Object` era il seguente: - -```php -echo $obj->undeclared; // E_NOTICE, successivamente E_WARNING -$obj->undeclared = 1; // passa in modo silenzioso, senza segnalare nulla -$obj->unknownMethod(); // Errore fatale (non catturabile con try/catch) -``` - -L'errore fatale terminava l'applicazione senza alcuna possibilità di reagire. Scrivere silenziosamente su membri inesistenti senza preavviso poteva portare a errori gravi, difficili da individuare. `Nette\Object` Tutti questi casi sono stati catturati ed è stata lanciata l'eccezione `MemberAccessException`. - -```php -echo $obj->undeclared; // lancia l'eccezione Nette\MemberAccessException -$obj->undeclared = 1; // lanciare l'eccezione Nette\MemberAccessException -$obj->unknownMethod(); // lanciare l'eccezione Nette\MemberAccessException -``` -A partire da PHP 7.0, PHP non causa più errori fatali non catturabili e l'accesso a membri non dichiarati è un bug da PHP 8.2. - - -Intendevi dire? .[#toc-did-you-mean] ------------------------------------- -Se veniva lanciato un errore `Nette\MemberAccessException`, magari a causa di un errore di battitura nell'accesso a una variabile oggetto o nella chiamata di un metodo, `Nette\Object` cercava di dare un suggerimento nel messaggio di errore su come correggere l'errore, sotto forma dell'iconico addendum "intendevi? +Da PHP 8.4, la stessa funzionalità può essere ottenuta usando i property hooks, che offrono una sintassi molto più elegante e concisa: ```php -class Foo extends Nette\Object +class Circle { - public static function from($var) - { + public float $radius = 0.0 { + set => max(0.0, $value); } -} -$foo = Foo::form($var); -// throw Nette\MemberAccessException -// "Call to undefined static method Foo::form(), did you mean from()?" + public bool $visible { + get => $this->radius > 0; + } +} ``` -Sebbene il PHP di oggi non disponga di una funzione di "hai inteso?", questa frase può essere aggiunta agli errori da [Tracy |tracy:]. Può anche [correggere automaticamente tali errori |tracy:open-files-in-ide#toc-demos]. - -Metodi di estensione .[#toc-extension-methods] ----------------------------------------------- -Ispirato ai metodi di estensione di C#. Offrono la possibilità di aggiungere nuovi metodi a classi esistenti. Ad esempio, si può aggiungere il metodo `addDateTime()` a un modulo per aggiungere il proprio DateTimePicker. +Extension Methods +----------------- +`Nette\Object` ha portato in PHP un altro concetto interessante ispirato ai linguaggi di programmazione moderni - i metodi di estensione. Questa funzionalità, presa in prestito da C#, permetteva agli sviluppatori di estendere elegantemente le classi esistenti con nuovi metodi senza modificarle o ereditare da esse. Per esempio, si poteva aggiungere un metodo `addDateTime()` a un form che aggiungesse un DateTimePicker personalizzato: ```php Form::extensionMethod( @@ -131,22 +137,22 @@ $form = new Form; $form->addDateTime('date'); ``` -I metodi di estensione si sono rivelati poco pratici, perché i loro nomi non venivano autocompilati dagli editor, che invece segnalavano che il metodo non esisteva. Pertanto, il loro supporto è stato interrotto. +I metodi di estensione si sono rivelati poco pratici perché gli editor non suggerivano i loro nomi e invece segnalavano che il metodo non esisteva. Pertanto, il loro supporto è stato interrotto. Oggi, è più comune utilizzare la composizione o l'ereditarietà per estendere la funzionalità delle classi. -Ottenere il nome della classe .[#toc-getting-the-class-name] ------------------------------------------------------------- +Ottenere il Nome della Classe +----------------------------- +SmartObject offriva un metodo semplice per ottenere il nome della classe: ```php $class = $obj->getClass(); // usando Nette\Object -$class = $obj::class; // da PHP 8.0 +$class = $obj::class; // da PHP 8.0 ``` -Accesso alla riflessione e alle annotazioni .[#toc-access-to-reflection-and-annotations] ----------------------------------------------------------------------------------------- - -`Nette\Object` ha offerto l'accesso alla riflessione e alle annotazioni utilizzando i metodi `getReflection()` e `getAnnotation()`: +Accesso a Reflection e Annotazioni +---------------------------------- +`Nette\Object` forniva accesso a reflection e annotazioni attraverso i metodi `getReflection()` e `getAnnotation()`. Questo approccio semplificava significativamente il lavoro con le meta-informazioni delle classi: ```php /** @@ -158,10 +164,10 @@ class Foo extends Nette\Object $obj = new Foo; $reflection = $obj->getReflection(); -$reflection->getAnnotation('author'); // restituisce 'John Doe'. +$reflection->getAnnotation('author'); // restituisce 'John Doe' ``` -A partire da PHP 8.0, è possibile accedere alle meta-informazioni sotto forma di attributi: +Da PHP 8.0, è possibile accedere alle meta-informazioni attraverso gli attributi, che offrono ancora più possibilità e un migliore controllo dei tipi: ```php #[Author('John Doe')] @@ -175,10 +181,9 @@ $reflection->getAttributes(Author::class)[0]; ``` -Metodi Getter .[#toc-method-getters] ------------------------------------- - -`Nette\Object` offre un modo elegante per trattare i metodi come se fossero variabili: +Method Getters +-------------- +`Nette\Object` offriva un modo elegante per passare i metodi come se fossero variabili: ```php class Foo extends Nette\Object @@ -194,7 +199,7 @@ $method = $obj->adder; echo $method(2, 3); // 5 ``` -A partire da PHP 8.1, è possibile utilizzare la cosiddetta "sintassi callable di prima classe":https://www.php.net/manual/en/functions.first_class_callable_syntax: +Da PHP 8.1, è possibile utilizzare la "first-class callable syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax, che porta questo concetto ancora più avanti: ```php $obj = new Foo; @@ -203,10 +208,9 @@ echo $method(2, 3); // 5 ``` -Eventi .[#toc-events] ---------------------- - -`Nette\Object` ha offerto uno zucchero sintattico per innescare l'[evento |nette:glossary#events]: +Eventi +------ +SmartObject offre una sintassi semplificata per lavorare con gli [eventi|nette:glossary#events]. Gli eventi permettono agli oggetti di informare altre parti dell'applicazione sui cambiamenti del loro stato: ```php class Circle extends Nette\Object @@ -221,7 +225,7 @@ class Circle extends Nette\Object } ``` -Il codice `$this->onChange($this, $radius)` è equivalente al seguente: +Il codice `$this->onChange($this, $radius)` è equivalente al seguente ciclo: ```php foreach ($this->onChange as $callback) { @@ -229,7 +233,7 @@ foreach ($this->onChange as $callback) { } ``` -Per motivi di chiarezza si consiglia di evitare il metodo magico `$this->onChange()`. Un sostituto pratico è la funzione [Nette\Utils\Arrays::invoke |arrays#invoke]: +Per chiarezza, raccomandiamo di evitare il metodo magico `$this->onChange()`. Un'alternativa pratica è la funzione [Nette\Utils\Arrays::invoke|arrays#invoke]: ```php Nette\Utils\Arrays::invoke($this->onChange, $this, $radius); diff --git a/utils/pl/smartobject.texy b/utils/pl/smartobject.texy index 199dd1fd8c..8a9811d045 100644 --- a/utils/pl/smartobject.texy +++ b/utils/pl/smartobject.texy @@ -2,7 +2,7 @@ SmartObject *********** .[perex] -SmartObject poprawiał zachowanie obiektów na wiele sposobów, ale dzisiejszy PHP zawiera już większość tych ulepszeń natywnie. Wciąż jednak dodaje wsparcie dla *property*. +SmartObject przez lata usprawniał zachowanie obiektów w PHP. Od wersji PHP 8.4 wszystkie jego funkcje są już częścią samego PHP, tym samym kończąc swoją historyczną misję jako pionier nowoczesnego podejścia obiektowego w PHP. Instalacja: @@ -11,19 +11,64 @@ Instalacja: composer require nette/utils ``` +SmartObject powstał w 2007 roku jako rewolucyjne rozwiązanie niedoskonałości ówczesnego modelu obiektowego PHP. W czasie, gdy PHP borykało się z wieloma problemami w projektowaniu obiektowym, wprowadził znaczące usprawnienia i uproszczenia w pracy programistów. Stał się legendarną częścią frameworka Nette. Oferował funkcjonalności, które PHP zyskało dopiero wiele lat później - od walidacji dostępu do właściwości obiektów po zaawansowaną obsługę błędów. Wraz z nadejściem PHP 8.4 zakończył swoją historyczną misję, ponieważ wszystkie jego funkcje stały się natywną częścią języka. Wyprzedził rozwój PHP o imponujące 17 lat. -Właściwości, gettery i settery .[#toc-properties-gettery-a-settery] -=================================================================== +SmartObject przeszedł ciekawą ewolucję techniczną. Początkowo był zaimplementowany jako klasa `Nette\Object`, po której inne klasy dziedziczyły potrzebną funkcjonalność. Znacząca zmiana nastąpiła wraz z PHP 5.4, które wprowadziło obsługę trait. Umożliwiło to transformację w trait `Nette\SmartObject`, co przyniosło większą elastyczność - programiści mogli wykorzystywać funkcjonalność nawet w klasach, które już dziedziczyły po innej klasie. Podczas gdy oryginalna klasa `Nette\Object` przestała istnieć wraz z PHP 7.2 (które zabroniło nazywania klas słowem 'Object'), trait `Nette\SmartObject` żyje nadal. -W nowoczesnych językach obiektowych (np. C#, Python, Ruby, JavaScript) termin *property* odnosi się do [specjalnych członków klas |https://en.wikipedia.org/wiki/Property_(programming)], które wyglądają jak zmienne, ale w rzeczywistości są reprezentowane przez metody. Kiedy wartość tej "zmiennej" jest przypisywana lub odczytywana, wywoływana jest odpowiednia metoda (zwana getterem lub setterem). Jest to bardzo przydatna rzecz, daje nam pełną kontrolę nad dostępem do zmiennych. Możemy zatwierdzić dane wejściowe lub wygenerować wyniki tylko wtedy, gdy właściwość zostanie odczytana. +Przyjrzyjmy się funkcjom, które kiedyś oferował `Nette\Object`, a później `Nette\SmartObject`. Każda z tych funkcji stanowiła w swoim czasie znaczący krok naprzód w programowaniu obiektowym w PHP. -Właściwości PHP nie są obsługiwane, ale traita `Nette\SmartObject` może je imitować. Jak to zrobić? -- Dodaj adnotację do klasy w postaci `@property $xyz` -- Utwórz getter o nazwie `getXyz()` lub `isXyz()`, setter o nazwie `setXyz()` -- Getter i setter muszą być *public* lub *protected* i są opcjonalne, więc może być właściwość *read-only* lub *write-only*. +Spójne stany błędów +------------------- +Jednym z najbardziej palących problemów wczesnego PHP było niespójne zachowanie podczas pracy z obiektami. `Nette\Object` wprowadził porządek i przewidywalność do tego chaosu. Zobaczmy, jak wyglądało oryginalne zachowanie PHP: -Wykorzystamy własność dla klasy Circle, aby zapewnić, że do zmiennej `$radius` wstawiane są tylko liczby nieujemne. Zamień `public $radius` na własność: +```php +echo $obj->undeclared; // E_NOTICE, później E_WARNING +$obj->undeclared = 1; // przechodzi bez ostrzeżenia +$obj->unknownMethod(); // Fatal error (nieprzechwytywany przez try/catch) +``` + +Fatal error powodował zakończenie aplikacji bez możliwości reakcji. Ciche zapisywanie do nieistniejących członków bez ostrzeżenia mogło prowadzić do poważnych błędów, które trudno było wykryć. `Nette\Object` przechwytywał wszystkie te przypadki i rzucał wyjątek `MemberAccessException`, co pozwalało programistom reagować na błędy i je obsługiwać: + +```php +echo $obj->undeclared; // rzuca Nette\MemberAccessException +$obj->undeclared = 1; // rzuca Nette\MemberAccessException +$obj->unknownMethod(); // rzuca Nette\MemberAccessException +``` + +Od PHP 7.0 język nie powoduje już nieprzechwytywanych błędów krytycznych, a od PHP 8.2 dostęp do niezadeklarowanych członków jest traktowany jako błąd. + + +Podpowiedź "Did you mean?" +-------------------------- +`Nette\Object` wprowadził bardzo przydatną funkcję: inteligentne podpowiedzi przy literówkach. Gdy programista popełnił błąd w nazwie metody lub zmiennej, nie tylko zgłaszał błąd, ale także oferował pomoc w postaci sugestii prawidłowej nazwy. Ta charakterystyczna wiadomość, znana jako "did you mean?", zaoszczędziła programistom godziny szukania literówek: + +```php +class Foo extends Nette\Object +{ + public static function from($var) + { + } +} + +$foo = Foo::form($var); +// rzuca Nette\MemberAccessException +// "Call to undefined static method Foo::form(), did you mean from()?" +``` + +Dzisiejsze PHP nie ma wprawdzie żadnej formy „did you mean?", ale ten dodatek potrafi uzupełniać [Tracy|tracy:]. A nawet [automatycznie poprawiać|tracy:open-files-in-ide#demos] takie błędy. + + +Properties z kontrolowanym dostępem +----------------------------------- +Znaczącą innowacją, którą SmartObject wprowadził do PHP, były properties z kontrolowanym dostępem. Ta koncepcja, powszechna w językach takich jak C# czy Python, pozwoliła programistom elegancko kontrolować dostęp do danych obiektu i zapewnić ich spójność. Properties są potężnym narzędziem programowania obiektowego. Działają jak zmienne, ale w rzeczywistości są reprezentowane przez metody (gettery i settery). Umożliwia to walidację danych wejściowych lub generowanie wartości w momencie odczytu. + +Aby używać properties, musisz: +- Dodać do klasy adnotację w formacie `@property $xyz` +- Utworzyć getter o nazwie `getXyz()` lub `isXyz()`, setter o nazwie `setXyz()` +- Zapewnić, aby getter i setter były *public* lub *protected*. Są opcjonalne - mogą więc istnieć jako *read-only* lub *write-only* property + +Zobaczmy praktyczny przykład na klasie Circle, gdzie użyjemy properties, aby zapewnić, że promień będzie zawsze nieujemny. Zastąpimy oryginalne `public $radius` przez property: ```php /** @@ -34,22 +79,22 @@ class Circle { use Nette\SmartObject; - private float $radius = 0.0; // není publiczne! + private float $radius = 0.0; // nie jest public! - // getter pro właściwość $radius + // getter dla property $radius protected function getRadius(): float { return $this->radius; } - // setter pro właściwość $radius + // setter dla property $radius protected function setRadius(float $radius): void { - // hodnotu před uložením sanitizujeme + // sanityzacja wartości przed zapisem $this->radius = max(0.0, $radius); } - // getter pro właściwość $visible + // getter dla property $visible protected function isVisible(): bool { return $this->radius > 0; @@ -57,69 +102,30 @@ class Circle } $circle = new Circle; -$circle->radius = 10; // ve skutečnosti volá setRadius(10) -echo $circle->radius; // volá getRadius() -echo $circle->visible; // volá isVisible() -``` - -Właściwości to przede wszystkim "cukier syntaktyczny"((syntactic sugar)), który ma uczynić życie programisty słodszym poprzez uproszczenie kodu. Jeśli ich nie chcesz, nie musisz z nich korzystać. - - -Rzut oka na historię .[#toc-a-glimpse-into-history] -=================================================== - -SmartObject udoskonalał zachowanie obiektów na wiele sposobów, ale dzisiejszy PHP zawiera już większość tych ulepszeń natywnie. Poniższy tekst jest nostalgicznym spojrzeniem wstecz na historię, przypominającym nam, jak rzeczy ewoluowały. - -Od samego początku model obiektowy PHP cierpiał na niezliczoną ilość poważnych niedociągnięć i braków. Doprowadziło to do stworzenia klasy `Nette\Object` (w 2007 roku), która miała na celu naprawienie tych problemów i zwiększenie komfortu korzystania z PHP. Wystarczyło tylko, by inne klasy po niej dziedziczyły, a zyskałyby oferowane przez nią korzyści. Gdy w PHP 5.4 wprowadzono obsługę cech, klasa `Nette\Object` została zastąpiona cechą `Nette\SmartObject`. Wyeliminowało to potrzebę dziedziczenia po wspólnym przodku. Co więcej, cecha mogła być używana w klasach, które już dziedziczyły po innej klasie. Ostateczny koniec `Nette\Object` nastąpił wraz z wydaniem PHP 7.2, które zabroniło klasom nazywania się `Object`. - -W miarę rozwoju PHP, jego model obiektowy i możliwości językowe ulegały poprawie. Różne funkcje klasy `SmartObject` stały się zbędne. Od wydania PHP 8.2 pozostała tylko jedna funkcja nieobsługiwana bezpośrednio w PHP: możliwość korzystania z tak zwanych [właściwości |#Properties, getters, and setters]. - -Jakie funkcje oferowały `Nette\Object` i, rozszerzając, `Nette\SmartObject`? Oto przegląd. (W przykładach użyto klasy `Nette\Object`, ale większość funkcji dotyczy również cechy `Nette\SmartObject` ). - - -Niespójne błędy .[#toc-nekonzistentni-chyby] --------------------------------------------- -PHP zachowywał się niespójnie podczas dostępu do niezadeklarowanych członków. Stan w momencie wejścia na stronę `Nette\Object` był następujący: - -```php -echo $obj->undeclared; // E_NOTICE, później E_WARNING -$obj->undeclared = 1; // przechodzi cicho bez zgłaszania -$obj->unknownMethod(); // Błąd fatalny (nie do wychwycenia przez try/catch) -``` - -Fatal error zakończył działanie aplikacji bez możliwości reakcji. Ciche pisanie do nieistniejących członków bez ostrzeżenia mogło prowadzić do poważnych błędów trudnych do wykrycia. `Nette\Object` Wszystkie te przypadki zostały złapane i wyjątek rzucony przez `MemberAccessException`. - -```php -echo $obj->undeclared; // vyhodí Nette\MemberAccessException -$obj->undeclared = 1; // vyhodí Nette\MemberAccessException -$obj->unknownMethod(); // vyhodí Nette\MemberAccessException +$circle->radius = 10; // w rzeczywistości wywołuje setRadius(10) +echo $circle->radius; // wywołuje getRadius() +echo $circle->visible; // wywołuje isVisible() ``` -Od PHP 7.0, PHP nie powoduje już nieśledzonych błędów fatalnych, a dostęp do niezadeklarowanych członków jest błędem od PHP 8.2. - -Miałeś na myśli? .[#toc-did-you-mean] -------------------------------------- -Jeśli został rzucony błąd `Nette\MemberAccessException`, być może z powodu literówki przy dostępie do zmiennej obiektu lub wywołaniu metody, `Nette\Object` próbował w komunikacie o błędzie dać podpowiedź, jak naprawić błąd, w postaci ikonicznego dodatku "czy miałeś na myśli?". +Od PHP 8.4 można osiągnąć tę samą funkcjonalność za pomocą property hooks, które oferują znacznie elegantszą i zwięzłą składnię: ```php -class Foo extends Nette\Object +class Circle { - public static function from($var) - { + public float $radius = 0.0 { + set => max(0.0, $value); } -} -$foo = Foo::form($var); -// vyhodí Nette\MemberAccessException -// "Call to undefined static method Foo::form(), did you mean from()?" + public bool $visible { + get => $this->radius > 0; + } +} ``` -Podczas gdy dzisiejszy PHP nie ma funkcji "czy miałeś na myśli?", ta fraza może być dodawana do błędów przez [Tracy |tracy:]. Może nawet [automatycznie korygować takie błędy |tracy:open-files-in-ide#toc-demos]. - -Metody rozszerzania .[#toc-extension-methods] ---------------------------------------------- -Zainspirowany metodami rozszerzającymi z języka C#. Dawały one możliwość dodawania nowych metod do istniejących klas. Na przykład możesz dodać metodę `addDateTime()` do formularza, aby dodać własny DateTimePicker. +Extension methods +----------------- +`Nette\Object` wprowadził do PHP kolejną interesującą koncepcję zainspirowaną nowoczesnymi językami programowania - extension methods. Ta funkcja, zapożyczona z C#, pozwoliła programistom elegancko rozszerzać istniejące klasy o nowe metody bez konieczności ich modyfikacji lub dziedziczenia. Na przykład można było dodać do formularza metodę `addDateTime()`, która dodaje własny DateTimePicker: ```php Form::extensionMethod( @@ -131,22 +137,22 @@ $form = new Form; $form->addDateTime('date'); ``` -Metody rozszerzania okazały się niepraktyczne, ponieważ ich nazwy nie sugerowały redaktorów, zamiast tego informowały, że dana metoda nie istnieje. Dlatego też zaprzestano ich wspierania. +Extension methods okazały się niepraktyczne, ponieważ ich nazwy nie były podpowiadane przez edytory, przeciwnie - zgłaszały, że metoda nie istnieje. Dlatego ich wsparcie zostało zakończone. Obecnie częściej stosuje się kompozycję lub dziedziczenie do rozszerzania funkcjonalności klas. -Uzyskanie nazwy klasy: +Pobieranie nazwy klasy ---------------------- +Do pobrania nazwy klasy SmartObject oferował prostą metodę: ```php -$class = $obj->getClass(); // używając Nette. -$class = $obj::class; // od PHP 8.0 +$class = $obj->getClass(); // za pomocą Nette\Object +$class = $obj::class; // od PHP 8.0 ``` -Dostęp do refleksji i adnotacji -------------------------------- - -`Nette\Object` zaoferował dostęp do refleksji i adnotacji za pomocą metod `getReflection()` i `getAnnotation()`: +Dostęp do reflection i adnotacji +-------------------------------- +`Nette\Object` oferował dostęp do reflection i adnotacji za pomocą metod `getReflection()` i `getAnnotation()`. To podejście znacząco uprościło pracę z metainformacjami klas: ```php /** @@ -158,10 +164,10 @@ class Foo extends Nette\Object $obj = new Foo; $reflection = $obj->getReflection(); -$reflection->getAnnotation('author'); // vrátí 'John Doe' +$reflection->getAnnotation('author'); // zwraca 'John Doe' ``` -Od PHP 8.0 możliwy jest dostęp do metainformacji w postaci atrybutów: +Od PHP 8.0 można uzyskiwać dostęp do metainformacji za pomocą atrybutów, które oferują jeszcze większe możliwości i lepszą kontrolę typów: ```php #[Author('John Doe')] @@ -175,10 +181,9 @@ $reflection->getAttributes(Author::class)[0]; ``` -Metoda gettery +Method gettery -------------- - -`Nette\Object` oferował elegancki sposób przekazywania metod tak, jakby były one zmiennymi: +`Nette\Object` oferował elegancki sposób przekazywania metod, jakby były zmiennymi: ```php class Foo extends Nette\Object @@ -194,7 +199,7 @@ $method = $obj->adder; echo $method(2, 3); // 5 ``` -Od PHP 8.1 można używać tzw. składni wywoływalnej pierwszej klasy:https://www.php.net/manual/en/functions.first_class_callable_syntax: +Od PHP 8.1 można wykorzystać tzw. "first-class callable syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax, która rozwija ten koncept jeszcze dalej: ```php $obj = new Foo; @@ -205,8 +210,7 @@ echo $method(2, 3); // 5 Wydarzenia ---------- - -`Nette\Object` zaoferował cukier syntaktyczny do wywołania [zdarzenia |nette:glossary#Events]: +SmartObject oferuje uproszczoną składnię do pracy z [wydarzeniami|nette:glossary#events]. Wydarzenia pozwalają obiektom informować inne części aplikacji o zmianach swojego stanu: ```php class Circle extends Nette\Object @@ -221,7 +225,7 @@ class Circle extends Nette\Object } ``` -Kod `$this->onChange($this, $radius)` jest równoważny z następującym: +Kod `$this->onChange($this, $radius)` jest równoważny następującej pętli: ```php foreach ($this->onChange as $callback) { @@ -229,7 +233,7 @@ foreach ($this->onChange as $callback) { } ``` -Dla jasności, zalecamy unikanie metody magicznej `$this->onChange()`. Praktycznym substytutem jest funkcja [Nette\Utils\Arrays::invoke |arrays#invoke]: +Ze względu na przejrzystość zalecamy unikanie magicznej metody `$this->onChange()`. Praktycznym zamiennikiem jest funkcja [Nette\Utils\Arrays::invoke|arrays#invoke]: ```php Nette\Utils\Arrays::invoke($this->onChange, $this, $radius); diff --git a/utils/pt/smartobject.texy b/utils/pt/smartobject.texy index e3f7e5f255..4363751d91 100644 --- a/utils/pt/smartobject.texy +++ b/utils/pt/smartobject.texy @@ -2,7 +2,7 @@ SmartObject *********** .[perex] -O SmartObject costumava corrigir o comportamento dos objetos de várias maneiras, mas o PHP atual já inclui a maioria desses aprimoramentos nativamente. No entanto, ele ainda adiciona suporte para *property*. +O SmartObject aprimorou o comportamento dos objetos em PHP durante muitos anos. Desde o PHP 8.4, todas as suas funcionalidades se tornaram parte nativa do próprio PHP, concluindo assim sua missão histórica como pioneiro da abordagem orientada a objetos moderna em PHP. Instalação: @@ -11,19 +11,64 @@ Instalação: composer require nette/utils ``` +O SmartObject surgiu em 2007 como uma solução revolucionária para as limitações do modelo de objetos do PHP da época. Quando o PHP sofria com vários problemas de design orientado a objetos, ele trouxe melhorias significativas e simplificou o trabalho dos desenvolvedores. Tornou-se uma parte lendária do framework Nette. Oferecia funcionalidades que o PHP só obteria muitos anos depois - desde a validação de acesso às propriedades até o tratamento sofisticado de erros. Com a chegada do PHP 8.4, completou sua missão histórica, pois todas as suas funcionalidades se tornaram partes nativas da linguagem. Esteve à frente do desenvolvimento do PHP por notáveis 17 anos. -Propriedades, Getters e Setters .[#toc-properties-getters-and-setters] -====================================================================== +O SmartObject passou por uma evolução técnica interessante. Inicialmente, foi implementado como a classe `Nette\Object`, da qual outras classes herdavam a funcionalidade necessária. Uma mudança significativa veio com o PHP 5.4, que introduziu o suporte a traits. Isso permitiu a transformação em um trait `Nette\SmartObject`, trazendo maior flexibilidade - os desenvolvedores podiam usar a funcionalidade mesmo em classes que já herdavam de outra classe. Enquanto a classe original `Nette\Object` deixou de existir com o PHP 7.2 (que proibiu nomear classes com a palavra 'Object'), o trait `Nette\SmartObject` continua vivo. -Em linguagens modernas orientadas a objetos (por exemplo, C#, Python, Ruby, JavaScript), o termo *propriedade* se refere a [membros especiais de classes |https://en.wikipedia.org/wiki/Property_(programming)] que se parecem com variáveis, mas que na verdade são representadas por métodos. Quando o valor desta "variável" é atribuído ou lido, o método correspondente (chamado getter ou setter) é chamado. Isto é uma coisa muito útil de se fazer, nos dá total controle sobre o acesso às variáveis. Podemos validar a entrada ou gerar resultados somente quando a propriedade é lida. +Vamos explorar as funcionalidades que o `Nette\Object` e depois o `Nette\SmartObject` ofereciam. Cada uma dessas funções representava um passo significativo na programação orientada a objetos em PHP na época. -As propriedades do PHP não são suportadas, mas o traço `Nette\SmartObject` pode imitá-las. Como utilizá-lo? -- Acrescentar uma anotação à classe no formulário `@property $xyz` -- Crie um getter chamado `getXyz()` ou `isXyz()`, um setter chamado `setXyz()` -- O getter e o setter devem ser *públicos* ou *protegidos* e são opcionais, portanto pode haver uma propriedade *somente de leitura* ou *somente de escrita*. +Estados de Erro Consistentes +---------------------------- +Um dos problemas mais críticos do PHP inicial era o comportamento inconsistente ao trabalhar com objetos. O `Nette\Object` trouxe ordem e previsibilidade a esse caos. Vejamos como o PHP se comportava originalmente: -Utilizaremos a propriedade da classe Circle para garantir que somente números não-negativos sejam colocados na variável `$radius`. Substituir `public $radius` por propriedade: +```php +echo $obj->undeclared; // E_NOTICE, depois E_WARNING +$obj->undeclared = 1; // passa silenciosamente sem aviso +$obj->unknownMethod(); // Fatal error (não capturável por try/catch) +``` + +O fatal error terminava a aplicação sem possibilidade de reação. A escrita silenciosa em membros inexistentes sem aviso poderia levar a erros graves difíceis de detectar. O `Nette\Object` capturava todos esses casos e lançava uma `MemberAccessException`, permitindo que os programadores reagissem e tratassem esses erros: + +```php +echo $obj->undeclared; // lança Nette\MemberAccessException +$obj->undeclared = 1; // lança Nette\MemberAccessException +$obj->unknownMethod(); // lança Nette\MemberAccessException +``` + +Desde o PHP 7.0, a linguagem não causa mais fatal errors não capturáveis, e desde o PHP 8.2, o acesso a membros não declarados é considerado um erro. + + +Sugestão "Did you mean?" +------------------------ +O `Nette\Object` veio com uma funcionalidade muito conveniente: sugestões inteligentes para erros de digitação. Quando um desenvolvedor cometia um erro no nome de um método ou variável, ele não apenas relatava o erro, mas também oferecia ajuda sugerindo o nome correto. Esta mensagem icônica, conhecida como "did you mean?", poupou horas de busca por erros de digitação: + +```php +class Foo extends Nette\Object +{ + public static function from($var) + { + } +} + +$foo = Foo::form($var); +// lança Nette\MemberAccessException +// "Call to undefined static method Foo::form(), did you mean from()?" +``` + +Embora o PHP em si não tenha nenhuma forma de "did you mean?", essa funcionalidade agora é fornecida pelo [Tracy|tracy:]. E ele pode até mesmo [corrigir automaticamente|tracy:open-files-in-ide#demos] esses erros. + + +Properties com Acesso Controlado +-------------------------------- +Uma inovação significativa que o SmartObject trouxe ao PHP foram as properties com acesso controlado. Esse conceito, comum em linguagens como C# ou Python, permitiu que os desenvolvedores controlassem elegantemente o acesso aos dados do objeto e garantissem sua consistência. Properties são uma ferramenta poderosa da programação orientada a objetos. Funcionam como variáveis, mas na verdade são representadas por métodos (getters e setters). Isso permite validar entradas ou gerar valores no momento da leitura. + +Para usar properties, você deve: +- Adicionar a anotação `@property $xyz` à classe +- Criar um getter chamado `getXyz()` ou `isXyz()`, um setter chamado `setXyz()` +- Garantir que o getter e setter sejam *public* ou *protected*. Eles são opcionais - assim podem existir como properties *read-only* ou *write-only* + +Vejamos um exemplo prático usando a classe Circle, onde usaremos properties para garantir que o raio seja sempre não negativo. Substituiremos `public $radius` por uma property: ```php /** @@ -34,22 +79,22 @@ class Circle { use Nette\SmartObject; - private float $radius = 0.0; // não público + private float $radius = 0.0; // não é public! - // getter para propriedade $radius + // getter para a property $radius protected function getRadius(): float { return $this->radius; } - // setter para propriedade $radius + // setter para a property $radius protected function setRadius(float $radius): void { - // valor higienizante antes de salvá-lo + // sanitiza o valor antes de salvar $this->radius = max(0.0, $radius); } - // adquirente por propriedade $visível + // getter para a property $visible protected function isVisible(): bool { return $this->radius > 0; @@ -57,69 +102,30 @@ class Circle } $circle = new Circle; -$circle->radius = 10; // na verdade chama setRadius(10) -echo $circle->radius; // chama getRadius() -echo $circle->visible; // chamadas isVisible() -``` - -As propriedades são principalmente o "açúcar sintático"((açúcar sintático)), que se destina a tornar a vida do programador mais doce, simplificando o código. Se você não os quer, não precisa usá-los. - - -Um vislumbre da história .[#toc-a-glimpse-into-history] -======================================================= - -O SmartObject costumava refinar o comportamento dos objetos de várias maneiras, mas o PHP atual já incorpora a maioria desses aprimoramentos de forma nativa. O texto a seguir é um olhar nostálgico para a história, lembrando-nos de como as coisas evoluíram. - -Desde seu início, o modelo de objeto do PHP sofria de uma infinidade de falhas e deficiências graves. Isso levou à criação da classe `Nette\Object` (em 2007), cujo objetivo era corrigir esses problemas e aumentar o conforto do uso do PHP. Tudo o que era necessário era que outras classes herdassem essa classe e obtivessem os benefícios que ela oferecia. Quando o PHP 5.4 introduziu o suporte a características, a classe `Nette\Object` foi substituída pela característica `Nette\SmartObject`. Isso eliminou a necessidade de herdar de um ancestral comum. Além disso, a característica poderia ser usada em classes que já herdavam de outra classe. O fim definitivo de `Nette\Object` veio com o lançamento do PHP 7.2, que proibiu que as classes fossem nomeadas `Object`. - -À medida que o desenvolvimento do PHP continuava, seu modelo de objeto e os recursos da linguagem foram aprimorados. Várias funções da classe `SmartObject` tornaram-se redundantes. Desde o lançamento do PHP 8.2, resta apenas um recurso não suportado diretamente no PHP: a capacidade de usar as chamadas [propriedades |#Properties, getters, and setters]. - -Quais recursos o `Nette\Object` e, por extensão, o `Nette\SmartObject` ofereceram? Aqui está uma visão geral. (Nos exemplos, a classe `Nette\Object` é usada, mas a maioria dos recursos também se aplica à característica `Nette\SmartObject` ). - - -Erros Inconsistentes .[#toc-inconsistent-errors] ------------------------------------------------- -O PHP tinha um comportamento inconsistente ao acessar membros não declarados. O estado, na época de `Nette\Object`, era o seguinte: - -```php -echo $obj->undeclared; // E_NOTICE, mais tarde E_WARNING -$obj->undeclared = 1; // passa silenciosamente sem informar -$obj->unknownMethod(); // Erro fatal (não detectável por tentativa/captura) -``` - -O erro fatal terminou a aplicação sem qualquer possibilidade de reação. Escrever silenciosamente a membros inexistentes sem aviso prévio poderia levar a erros graves que eram difíceis de detectar. `Nette\Object` Todos estes casos foram pegos e uma exceção `MemberAccessException` foi lançada. - -```php -echo $obj->undeclared; // jogue Nette\MemberAccessException -$obj->undeclared = 1; // jogar Nette\MemberAccessException -$obj->unknownMethod(); // jogar Nette\MemberAccessException +$circle->radius = 10; // na verdade chama setRadius(10) +echo $circle->radius; // chama getRadius() +echo $circle->visible; // chama isVisible() ``` -Desde o PHP 7.0, o PHP não causa mais erros fatais não detectáveis, e acessar membros não declarados tem sido um erro desde o PHP 8.2. - -Você quis dizer? .[#toc-did-you-mean] -------------------------------------- -Se um erro `Nette\MemberAccessException` foi lançado, talvez devido a um erro de digitação ao acessar uma variável de objeto ou ao chamar um método, `Nette\Object` tentou dar uma dica na mensagem de erro sobre como corrigir o erro, na forma do icônico adendo "você quis dizer...". +Desde o PHP 8.4, a mesma funcionalidade pode ser alcançada usando property hooks, que oferecem uma sintaxe muito mais elegante e concisa: ```php -class Foo extends Nette\Object +class Circle { - public static function from($var) - { + public float $radius = 0.0 { + set => max(0.0, $value); } -} -$foo = Foo::form($var); -// throw Nette\MemberAccessException -// "Call to undefined static method Foo::form(), did you mean from()?" + public bool $visible { + get => $this->radius > 0; + } +} ``` -Embora o PHP atual não tenha um recurso "você quis dizer?", essa frase pode ser adicionada aos erros pela [Tracy |tracy:]. Ele pode até mesmo [corrigir automaticamente esses erros |tracy:open-files-in-ide#toc-demos]. - -Métodos de extensão .[#toc-extension-methods] ---------------------------------------------- -Inspirado pelos métodos de extensão da C#. Eles deram a possibilidade de adicionar novos métodos às classes existentes. Por exemplo, você poderia adicionar o método `addDateTime()` a um formulário para adicionar seu próprio DateTimePicker. +Extension Methods +----------------- +O `Nette\Object` trouxe outro conceito interessante ao PHP inspirado em linguagens de programação modernas - extension methods. Essa funcionalidade, emprestada do C#, permitia que os desenvolvedores estendessem elegantemente classes existentes com novos métodos sem modificá-las ou herdar delas. Por exemplo, você poderia adicionar um método `addDateTime()` a um formulário que adiciona um DateTimePicker personalizado: ```php Form::extensionMethod( @@ -131,22 +137,22 @@ $form = new Form; $form->addDateTime('date'); ``` -Os métodos de extensão se mostraram impraticáveis porque seus nomes não foram autocompletados pelos editores, em vez disso, eles relataram que o método não existia. Portanto, seu apoio foi descontinuado. +As extension methods se mostraram impráticas porque os editores não sugeriam seus nomes e, em vez disso, relatavam que o método não existia. Portanto, seu suporte foi descontinuado. Hoje, é mais comum usar composição ou herança para estender a funcionalidade da classe. -Como obter o nome da classe .[#toc-getting-the-class-name] ----------------------------------------------------------- +Obtendo o Nome da Classe +------------------------ +O SmartObject oferecia um método simples para obter o nome da classe: ```php $class = $obj->getClass(); // usando Nette\Object -$class = $obj::class; // desde PHP 8.0 +$class = $obj::class; // desde PHP 8.0 ``` -Acesso à Reflexão e Anotações .[#toc-access-to-reflection-and-annotations] --------------------------------------------------------------------------- - -`Nette\Object` ofereceu acesso à reflexão e à anotação utilizando os métodos `getReflection()` e `getAnnotation()`: +Acesso à Reflexão e Anotações +----------------------------- +O `Nette\Object` fornecia acesso à reflexão e anotações através dos métodos `getReflection()` e `getAnnotation()`. Essa abordagem simplificou significativamente o trabalho com metainformações de classe: ```php /** @@ -158,10 +164,10 @@ class Foo extends Nette\Object $obj = new Foo; $reflection = $obj->getReflection(); -$reflection->getAnnotation('author'); // devolve 'John Doe' +$reflection->getAnnotation('author'); // retorna 'John Doe' ``` -A partir do PHP 8.0, é possível acessar meta-informação sob a forma de atributos: +Desde o PHP 8.0, é possível acessar metainformações através de atributos, que oferecem ainda mais possibilidades e melhor verificação de tipo: ```php #[Author('John Doe')] @@ -175,10 +181,9 @@ $reflection->getAttributes(Author::class)[0]; ``` -Método Getters .[#toc-method-getters] -------------------------------------- - -`Nette\Object` oferecia uma maneira elegante de lidar com métodos como se fossem variáveis: +Method Getters +-------------- +O `Nette\Object` oferecia uma maneira elegante de passar métodos como se fossem variáveis: ```php class Foo extends Nette\Object @@ -194,7 +199,7 @@ $method = $obj->adder; echo $method(2, 3); // 5 ``` -A partir do PHP 8.1, você pode usar a chamada "sintaxe de primeira classe que pode ser chamada":https://www.php.net/manual/en/functions.first_class_callable_syntax: +Desde o PHP 8.1, você pode usar a "first-class callable syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax, que leva esse conceito ainda mais longe: ```php $obj = new Foo; @@ -203,10 +208,9 @@ echo $method(2, 3); // 5 ``` -Eventos .[#toc-events] ----------------------- - -`Nette\Object` ofereceu açúcar sintáctico para acionar o [evento |nette:glossary#events]: +Eventos +------- +O SmartObject oferece uma sintaxe simplificada para trabalhar com [eventos|nette:glossary#events]. Eventos permitem que objetos informem outras partes da aplicação sobre mudanças em seu estado: ```php class Circle extends Nette\Object @@ -221,7 +225,7 @@ class Circle extends Nette\Object } ``` -O código `$this->onChange($this, $radius)` é equivalente ao seguinte: +O código `$this->onChange($this, $radius)` é equivalente ao seguinte loop: ```php foreach ($this->onChange as $callback) { @@ -229,7 +233,7 @@ foreach ($this->onChange as $callback) { } ``` -Por uma questão de clareza, recomendamos evitar o método mágico `$this->onChange()`. Um substituto prático é a [Arrays Nette\Utils::invoke |arrays#invoke] function: +Para maior clareza, recomendamos evitar o método mágico `$this->onChange()`. Uma substituição prática é a função [Nette\Utils\Arrays::invoke|arrays#invoke]: ```php Nette\Utils\Arrays::invoke($this->onChange, $this, $radius); diff --git a/utils/ro/smartobject.texy b/utils/ro/smartobject.texy index 3d1ed9e89f..3f9d6840b4 100644 --- a/utils/ro/smartobject.texy +++ b/utils/ro/smartobject.texy @@ -2,7 +2,7 @@ SmartObject *********** .[perex] -SmartObject obișnuia să corecteze comportamentul obiectelor în mai multe moduri, dar PHP-ul de astăzi include deja majoritatea acestor îmbunătățiri în mod nativ. Cu toate acestea, se adaugă încă suport pentru *proprietate*. +SmartObject a îmbunătățit comportamentul obiectelor în PHP timp de mulți ani. Începând cu PHP 8.4, toate funcționalitățile sale au devenit parte nativă a PHP-ului, completându-și astfel misiunea istorică de a fi pionierul abordării moderne orientate pe obiecte în PHP. Instalare: @@ -11,19 +11,64 @@ Instalare: composer require nette/utils ``` +SmartObject a apărut în 2007 ca o soluție revoluționară pentru deficiențele modelului de obiecte din PHP la acea vreme. Într-o perioadă în care PHP suferea de numeroase probleme legate de design-ul orientat pe obiecte, acesta a adus îmbunătățiri semnificative și a simplificat munca dezvoltatorilor. A devenit o parte legendară a framework-ului Nette. A oferit funcționalități pe care PHP le-a obținut abia mulți ani mai târziu - de la validarea accesului la proprietăți până la gestionarea sofisticată a erorilor. Odată cu apariția PHP 8.4, și-a încheiat misiunea istorică, deoarece toate funcționalitățile sale au devenit părți native ale limbajului. A fost cu 17 ani înaintea dezvoltării PHP-ului. -Proprietăți, Getters și Setters .[#toc-properties-getters-and-setters] -====================================================================== +SmartObject a trecut printr-o evoluție tehnică interesantă. Inițial, a fost implementat ca și clasă `Nette\Object`, de la care alte clase moșteneau funcționalitatea necesară. O schimbare semnificativă a venit cu PHP 5.4, care a introdus suportul pentru trait-uri. Acest lucru a permis transformarea în trait-ul `Nette\SmartObject`, oferind mai multă flexibilitate - dezvoltatorii puteau folosi funcționalitatea chiar și în clasele care moșteneau deja dintr-o altă clasă. În timp ce clasa originală `Nette\Object` a încetat să existe odată cu PHP 7.2 (care a interzis denumirea claselor cu cuvântul 'Object'), trait-ul `Nette\SmartObject` continuă să existe. -În limbajele moderne orientate pe obiecte (de exemplu, C#, Python, Ruby, JavaScript), termenul *proprietate* se referă la [membrii speciali ai claselor |https://en.wikipedia.org/wiki/Property_(programming)] care seamănă cu variabilele, dar care sunt de fapt reprezentate de metode. Atunci când valoarea acestei "variabile" este atribuită sau citită, se apelează metoda corespunzătoare (numită getter sau setter). Acesta este un lucru foarte util, deoarece ne oferă un control total asupra accesului la variabile. Putem valida intrarea sau genera rezultate numai atunci când proprietatea este citită. +Să explorăm funcționalitățile pe care `Nette\Object` și mai târziu `Nette\SmartObject` le-au oferit. Fiecare dintre aceste funcții a reprezentat un pas important înainte în programarea orientată pe obiecte în PHP. -Proprietățile PHP nu sunt acceptate, dar trait `Nette\SmartObject` le poate imita. Cum se utilizează? -- Adăugați o adnotare la clasă sub forma `@property $xyz` +Stări de eroare consistente +--------------------------- +Una dintre cele mai presante probleme ale PHP-ului timpuriu a fost comportamentul inconsistent în lucrul cu obiectele. `Nette\Object` a adus ordine și predictibilitate în acest haos. Să vedem cum se comporta PHP-ul inițial: + +```php +echo $obj->undeclared; // E_NOTICE, mai târziu E_WARNING +$obj->undeclared = 1; // trece silențios fără avertisment +$obj->unknownMethod(); // Fatal error (imposibil de prins cu try/catch) +``` + +Fatal error termina aplicația fără posibilitatea de a reacționa. Scrierea silențioasă în membri inexistenți fără avertisment putea duce la erori grave, greu de detectat. `Nette\Object` prindea toate aceste cazuri și arunca o excepție `MemberAccessException`, permițând programatorilor să reacționeze și să gestioneze aceste erori: + +```php +echo $obj->undeclared; // aruncă Nette\MemberAccessException +$obj->undeclared = 1; // aruncă Nette\MemberAccessException +$obj->unknownMethod(); // aruncă Nette\MemberAccessException +``` + +Din PHP 7.0, limbajul nu mai cauzează fatal error-uri imposibil de prins, iar din PHP 8.2, accesul la membri nedeclarați este considerat o eroare. + + +Ajutorul "Did you mean?" +------------------------ +`Nette\Object` a venit cu o funcționalitate foarte convenabilă: sugestii inteligente pentru greșeli de scriere. Când un dezvoltator făcea o greșeală în numele unei metode sau variabile, nu doar raporta eroarea, ci oferea și ajutor sugerând numele corect. Acest mesaj iconic, cunoscut ca "did you mean?", a economisit programatorilor ore întregi de căutare a greșelilor de scriere: + +```php +class Foo extends Nette\Object +{ + public static function from($var) + { + } +} + +$foo = Foo::form($var); +// aruncă Nette\MemberAccessException +// "Call to undefined static method Foo::form(), did you mean from()?" +``` + +Deși PHP-ul în sine nu are nicio formă de "did you mean?", această funcționalitate este acum oferită de [Tracy|tracy:]. Poate chiar [auto-corecta|tracy:open-files-in-ide#demos] astfel de erori. + + +Properties cu acces controlat +----------------------------- +O inovație semnificativă pe care SmartObject a adus-o în PHP au fost properties cu acces controlat. Acest concept, comun în limbaje precum C# sau Python, a permis dezvoltatorilor să controleze elegant accesul la datele obiectelor și să asigure consistența acestora. Properties sunt un instrument puternic al programării orientate pe obiecte. Funcționează ca variabile, dar sunt de fapt reprezentate prin metode (getteri și setteri). Acest lucru permite validarea intrărilor sau generarea valorilor în momentul citirii. + +Pentru a utiliza properties, trebuie să: +- Adăugați adnotarea `@property $xyz` la clasă - Creați un getter numit `getXyz()` sau `isXyz()`, un setter numit `setXyz()` -- Getterul și setterul trebuie să fie *public* sau *protected* și sunt opționale, astfel încât poate exista o proprietate *read-only* sau *write-only*. +- Să vă asigurați că getter-ul și setter-ul sunt *public* sau *protected*. Sunt opționali - astfel pot exista ca properties *read-only* sau *write-only* -Vom utiliza proprietatea pentru clasa Circle pentru a ne asigura că în variabila `$radius` sunt introduse numai numere non-negative. Înlocuiți `public $radius` cu proprietatea: +Să vedem un exemplu practic folosind clasa Circle, unde vom folosi properties pentru a ne asigura că raza este întotdeauna non-negativă. Vom înlocui `public $radius` cu o property: ```php /** @@ -34,22 +79,22 @@ class Circle { use Nette\SmartObject; - private float $radius = 0.0; // nu sunt publice + private float $radius = 0.0; // nu este public! - // getter pentru proprietatea $radius + // getter pentru property-ul $radius protected function getRadius(): float { return $this->radius; } - // setter pentru proprietatea $radius + // setter pentru property-ul $radius protected function setRadius(float $radius): void { - // curățarea valorii înainte de a o salva + // sanitizăm valoarea înainte de salvare $this->radius = max(0.0, $radius); } - // getter pentru proprietatea $visible + // getter pentru property-ul $visible protected function isVisible(): bool { return $this->radius > 0; @@ -57,69 +102,30 @@ class Circle } $circle = new Circle; -$circle->radius = 10; // apelează de fapt setRadius(10) +$circle->radius = 10; // de fapt apelează setRadius(10) echo $circle->radius; // apelează getRadius() -echo $circle->visible; // solicită isVisible() -``` - -Proprietățile sunt în primul rând "zahăr sintactic"((zahăr sintactic)), care are rolul de a face viața programatorului mai ușoară prin simplificarea codului. Dacă nu le doriți, nu trebuie să le folosiți. - - -O privire în istorie .[#toc-a-glimpse-into-history] -=================================================== - -SmartObject obișnuia să rafineze comportamentul obiectelor în numeroase moduri, dar PHP-ul de astăzi încorporează deja majoritatea acestor îmbunătățiri în mod nativ. Următorul text este o privire nostalgică asupra istoriei, amintindu-ne cum au evoluat lucrurile. - -Încă de la începuturile sale, modelul de obiecte din PHP a suferit de o multitudine de deficiențe și neajunsuri grave. Acest lucru a dus la crearea clasei `Nette\Object` (în 2007), care a avut ca scop rectificarea acestor probleme și îmbunătățirea confortului de utilizare a PHP. Tot ceea ce era necesar era ca alte clase să moștenească din ea și să obțină beneficiile oferite de aceasta. Când PHP 5.4 a introdus suportul pentru trăsături, clasa `Nette\Object` a fost înlocuită cu trăsătura `Nette\SmartObject`. Acest lucru a eliminat necesitatea de a moșteni de la un strămoș comun. În plus, trăsătura putea fi utilizată în clase care moșteneau deja de la o altă clasă. Sfârșitul definitiv al `Nette\Object` a venit odată cu lansarea PHP 7.2, care a interzis ca clasele să fie denumite `Object`. - -Pe măsură ce dezvoltarea PHP a continuat, modelul său de obiecte și capacitățile limbajului s-au îmbunătățit. Diverse funcții ale clasei `SmartObject` au devenit redundante. De la lansarea PHP 8.2, a rămas o singură funcție care nu este direct suportată în PHP: capacitatea de a utiliza așa-numitele [proprietăți |#Properties, getters, and setters]. - -Ce caracteristici au oferit `Nette\Object` și, prin extensie, `Nette\SmartObject`? Iată o prezentare generală. (În exemple, este utilizată clasa `Nette\Object`, dar majoritatea caracteristicilor se aplică și trăsăturii `Nette\SmartObject` ). - - -Erori inconsistente .[#toc-inconsistent-errors] ------------------------------------------------ -PHP avea un comportament inconsecvent la accesarea membrilor nedeclarați. Starea la momentul `Nette\Object` era următoarea: - -```php -echo $obj->undeclared; // E_NOTICE, ulterior E_WARNING -$obj->undeclared = 1; // trece în tăcere fără a raporta -$obj->unknownMethod(); // Eroare fatală (care nu poate fi prinsă prin try/catch) -``` - -O eroare fatală a încheiat aplicația fără nicio posibilitate de reacție. Scrierea silențioasă în membri inexistenți fără avertisment putea duce la erori grave, greu de detectat. `Nette\Object` Toate aceste cazuri au fost detectate și a fost lansată o excepție `MemberAccessException`. - -```php -echo $obj->undeclared; // aruncați Nette\MemberAccessException -$obj->undeclared = 1; // throw Nette\MemberAccessException -$obj->unknownMethod(); // throw Nette\MemberAccessException +echo $circle->visible; // apelează isVisible() ``` -Începând cu PHP 7.0, PHP nu mai provoacă erori fatale care nu pot fi prinse, iar accesarea membrilor nedeclarați este un bug începând cu PHP 8.2. - -Ați vrut să spuneți? .[#toc-did-you-mean] ------------------------------------------ -În cazul în care se producea o eroare `Nette\MemberAccessException`, poate din cauza unei greșeli de scriere la accesarea unei variabile de obiect sau la apelarea unei metode, `Nette\Object` încerca să ofere un indiciu în mesajul de eroare cu privire la modul de corectare a erorii, sub forma unui addendum iconic "did you mean?". +Din PHP 8.4, aceeași funcționalitate poate fi obținută folosind property hooks, care oferă o sintaxă mult mai elegantă și concisă: ```php -class Foo extends Nette\Object +class Circle { - public static function from($var) - { + public float $radius = 0.0 { + set => max(0.0, $value); } -} -$foo = Foo::form($var); -// throw Nette\MemberAccessException -// "Call to undefined static method Foo::form(), did you mean from()?" + public bool $visible { + get => $this->radius > 0; + } +} ``` -În timp ce PHP-ul actual nu are o funcție "ai vrut să spui?", această frază poate fi adăugată la erori de către [Tracy |tracy:]. Acesta poate chiar să [corecteze automat astfel de erori |tracy:open-files-in-ide#toc-demos]. - -Metode de extensie .[#toc-extension-methods] --------------------------------------------- -Inspirat de metodele de extensie din C#. Acestea au oferit posibilitatea de a adăuga noi metode la clasele existente. De exemplu, ați putea adăuga metoda `addDateTime()` la un formular pentru a adăuga propriul DateTimePicker. +Extension methods +----------------- +`Nette\Object` a adus în PHP un alt concept interesant inspirat din limbajele de programare moderne - extension methods. Această funcționalitate, împrumutată din C#, a permis dezvoltatorilor să extindă elegant clasele existente cu metode noi fără a le modifica sau moșteni. De exemplu, puteați adăuga o metodă `addDateTime()` unui formular care adaugă un DateTimePicker personalizat: ```php Form::extensionMethod( @@ -131,11 +137,12 @@ $form = new Form; $form->addDateTime('date'); ``` -Metodele de extensie s-au dovedit a fi nepractice deoarece numele lor nu era completat automat de către editori, în schimb aceștia raportau că metoda nu există. Prin urmare, suportul lor a fost întrerupt. +Extension methods s-au dovedit nepractice deoarece editoarele nu sugerau numele lor și în schimb raportau că metoda nu există. Prin urmare, suportul lor a fost întrerupt. Astăzi, este mai comun să se folosească compoziția sau moștenirea pentru a extinde funcționalitatea clasei. -Obținerea numelui clasei .[#toc-getting-the-class-name] -------------------------------------------------------- +Obținerea numelui clasei +------------------------ +SmartObject oferea o metodă simplă pentru obținerea numelui clasei: ```php $class = $obj->getClass(); // folosind Nette\Object @@ -143,10 +150,9 @@ $class = $obj::class; // din PHP 8.0 ``` -Acces la reflecție și adnotări .[#toc-access-to-reflection-and-annotations] ---------------------------------------------------------------------------- - -`Nette\Object` a oferit acces la reflectare și adnotare prin intermediul metodelor `getReflection()` și `getAnnotation()`: +Acces la Reflexie și Adnotări +----------------------------- +`Nette\Object` oferea acces la reflexie și adnotări prin metodele `getReflection()` și `getAnnotation()`. Această abordare a simplificat semnificativ lucrul cu meta-informațiile claselor: ```php /** @@ -158,10 +164,10 @@ class Foo extends Nette\Object $obj = new Foo; $reflection = $obj->getReflection(); -$reflection->getAnnotation('author'); // returnează "John Doe +$reflection->getAnnotation('author'); // returnează 'John Doe' ``` -Începând cu PHP 8.0, este posibilă accesarea meta-informațiilor sub formă de atribute: +Din PHP 8.0, este posibil să accesați meta-informațiile prin atribute, care oferă chiar mai multe posibilități și o verificare mai bună a tipurilor: ```php #[Author('John Doe')] @@ -175,10 +181,9 @@ $reflection->getAttributes(Author::class)[0]; ``` -Metode Getters .[#toc-method-getters] -------------------------------------- - -`Nette\Object` a oferit o modalitate elegantă de a trata metodele ca și cum ar fi fost variabile: +Method getteri +-------------- +`Nette\Object` oferea o modalitate elegantă de a transmite metode ca și cum ar fi fost variabile: ```php class Foo extends Nette\Object @@ -194,7 +199,7 @@ $method = $obj->adder; echo $method(2, 3); // 5 ``` -Începând cu PHP 8.1, puteți utiliza așa-numita "sintaxă de primă clasă pentru metode apelabile":https://www.php.net/manual/en/functions.first_class_callable_syntax: +Din PHP 8.1, puteți utiliza "first-class callable syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax, care duce acest concept și mai departe: ```php $obj = new Foo; @@ -203,10 +208,9 @@ echo $method(2, 3); // 5 ``` -Evenimente .[#toc-events] -------------------------- - -`Nette\Object` a oferit zahăr sintactic pentru a declanșa [evenimentul |nette:glossary#events]: +Evenimente +---------- +SmartObject oferă o sintaxă simplificată pentru lucrul cu [evenimente|nette:glossary#events]. Evenimentele permit obiectelor să informeze alte părți ale aplicației despre schimbările din starea lor: ```php class Circle extends Nette\Object @@ -221,7 +225,7 @@ class Circle extends Nette\Object } ``` -Codul `$this->onChange($this, $radius)` este echivalent cu următoarele: +Codul `$this->onChange($this, $radius)` este echivalent cu următoarea buclă: ```php foreach ($this->onChange as $callback) { @@ -229,7 +233,7 @@ foreach ($this->onChange as $callback) { } ``` -Din motive de claritate, vă recomandăm să evitați metoda magică `$this->onChange()`. Un substitut practic este funcția [Nette\Utils\Arrays::invoke |arrays#invoke]: +Pentru claritate, recomandăm evitarea metodei magice `$this->onChange()`. O înlocuire practică este funcția [Nette\Utils\Arrays::invoke|arrays#invoke]: ```php Nette\Utils\Arrays::invoke($this->onChange, $this, $radius); diff --git a/utils/ru/smartobject.texy b/utils/ru/smartobject.texy index e0301323fd..cf1c5f6540 100644 --- a/utils/ru/smartobject.texy +++ b/utils/ru/smartobject.texy @@ -2,7 +2,7 @@ SmartObject *********** .[perex] -SmartObject во многом исправлял поведение объектов, но современный PHP уже включает большинство этих улучшений нативно. Тем не менее, в нем все еще добавлена поддержка *property*. +SmartObject на протяжении многих лет улучшал поведение объектов в PHP. Начиная с версии PHP 8.4, все его функции стали встроенной частью самого PHP, тем самым завершив свою историческую миссию первопроходца современного объектно-ориентированного подхода в PHP. Установка: @@ -11,19 +11,64 @@ SmartObject во многом исправлял поведение объект composer require nette/utils ``` +SmartObject появился в 2007 году как революционное решение недостатков объектной модели PHP того времени. В период, когда PHP страдал от множества проблем с объектно-ориентированным дизайном, он принес значительные улучшения и упростил работу разработчиков. Он стал легендарной частью фреймворка Nette. SmartObject предлагал функциональность, которую PHP получил лишь много лет спустя - от валидации доступа к свойствам объектов до сложной обработки ошибок. С выходом PHP 8.4 он завершил свою историческую миссию, так как все его функции стали встроенной частью языка. SmartObject опередил развитие PHP на впечатляющие 17 лет. -Свойства, геттери и сеттери .[#toc-properties-getters-and-setters] -================================================================== +Технически SmartObject прошел интересный путь развития. Изначально он был реализован как класс `Nette\Object`, от которого другие классы наследовали необходимую функциональность. Значительные изменения пришли с PHP 5.4, который ввел поддержку trait-ов. Это позволило трансформировать его в trait `Nette\SmartObject`, что принесло большую гибкость - разработчики могли использовать функциональность даже в классах, которые уже наследовались от другого класса. В то время как оригинальный класс `Nette\Object` прекратил существование с выходом PHP 7.2 (который запретил именование классов словом 'Object'), trait `Nette\SmartObject` продолжает жить. -В современных объектно-ориентированных языках (например, C#, Python, Ruby, JavaScript) термин *свойство* относится к [специальным членам классов |https://en.wikipedia.org/wiki/Property_(programming)], которые выглядят как переменные, но на самом деле представлены методами. Когда значение такой "переменной" присваивается или считывается, вызывается соответствующий метод (называемый getter или setter). Это очень удобная вещь, она дает нам полный контроль над доступом к переменным. Мы можем проверять вводимые данные или генерировать результаты только тогда, когда свойство прочитано. +Давайте рассмотрим возможности, которые предлагали `Nette\Object` и позже `Nette\SmartObject`. Каждая из этих функций в свое время представляла значительный шаг вперед в области объектно-ориентированного программирования в PHP. -Свойства PHP не поддерживаются, но trait `Nette\SmartObject` может их имитировать. Как это использовать? -- Добавьте аннотацию к классу в виде `@property $xyz` -- Создайте геттер с именем `getXyz()` или `isXyz()`, сеттер с именем `setXyz()` -- Геттер и сеттер должны быть *публичными* или *защищенными* и необязательными, поэтому может быть свойство *только для чтения* или *только для записи*. +Последовательная обработка ошибок +--------------------------------- +Одной из самых острых проблем раннего PHP было непоследовательное поведение при работе с объектами. `Nette\Object` внес порядок и предсказуемость в этот хаос. Посмотрим, как вело себя PHP изначально: + +```php +echo $obj->undeclared; // E_NOTICE, позже E_WARNING +$obj->undeclared = 1; // проходит молча без предупреждения +$obj->unknownMethod(); // Fatal error (необрабатываемый try/catch) +``` + +Fatal error завершал приложение без возможности какой-либо реакции. Тихая запись в несуществующие члены без предупреждения могла привести к серьезным ошибкам, которые было трудно обнаружить. `Nette\Object` отлавливал все эти случаи и выбрасывал исключение `MemberAccessException`, что позволяло программистам реагировать на ошибки и обрабатывать их: + +```php +echo $obj->undeclared; // выбрасывает Nette\MemberAccessException +$obj->undeclared = 1; // выбрасывает Nette\MemberAccessException +$obj->unknownMethod(); // выбрасывает Nette\MemberAccessException +``` + +Начиная с PHP 7.0, язык больше не вызывает необрабатываемые fatal error, а с PHP 8.2 доступ к необъявленным членам считается ошибкой. + + +Подсказка "Did you mean?" +------------------------- +`Nette\Object` пришел с очень удобной функцией: интеллектуальными подсказками при опечатках. Когда разработчик делал ошибку в названии метода или переменной, он не только сообщал об ошибке, но и предлагал помощь в виде предложения правильного названия. Это знаковое сообщение, известное как "did you mean?", сэкономило программистам часы поиска опечаток: + +```php +class Foo extends Nette\Object +{ + public static function from($var) + { + } +} + +$foo = Foo::form($var); +// выбрасывает Nette\MemberAccessException +// "Call to undefined static method Foo::form(), did you mean from()?" +``` + +Хотя современный PHP не имеет встроенных подсказок "did you mean?", эту функциональность теперь предоставляет [Tracy|tracy:]. Он даже может [автоматически исправлять|tracy:open-files-in-ide#demos] такие ошибки. -Мы будем использовать свойство для класса Circle, чтобы гарантировать, что в переменную `$radius` будут помещаться только неотрицательные числа. Замените `public $radius` на property: + +Properties с контролируемым доступом +------------------------------------ +Значительным нововведением, которое SmartObject принес в PHP, были properties с контролируемым доступом. Эта концепция, распространенная в таких языках как C# или Python, позволила разработчикам элегантно контролировать доступ к данным объекта и обеспечивать их целостность. Properties являются мощным инструментом объектно-ориентированного программирования. Они работают как переменные, но фактически представлены методами (getters и setters). Это позволяет валидировать входные данные или генерировать значения в момент чтения. + +Для использования properties необходимо: +- Добавить классу аннотацию вида `@property $xyz` +- Создать getter с именем `getXyz()` или `isXyz()`, setter с именем `setXyz()` +- Обеспечить, чтобы getter и setter были *public* или *protected*. Они опциональны - могут существовать как *read-only* или *write-only* properties + +Рассмотрим практический пример на классе Circle, где мы используем properties для обеспечения того, чтобы радиус всегда был неотрицательным числом. Заменим `public $radius` на property: ```php /** @@ -34,22 +79,22 @@ class Circle { use Nette\SmartObject; - private float $radius = 0.0; // not public + private float $radius = 0.0; // не public! - // getter for property $radius + // getter для property $radius protected function getRadius(): float { return $this->radius; } - // setter for property $radius + // setter для property $radius protected function setRadius(float $radius): void { - // sanitizing value before saving it + // санитизируем значение перед сохранением $this->radius = max(0.0, $radius); } - // getter for property $visible + // getter для property $visible protected function isVisible(): bool { return $this->radius > 0; @@ -57,69 +102,30 @@ class Circle } $circle = new Circle; -$circle->radius = 10; // actually calls setRadius(10) -echo $circle->radius; // calls getRadius() -echo $circle->visible; // calls isVisible() +$circle->radius = 10; // фактически вызывает setRadius(10) +echo $circle->radius; // вызывает getRadius() +echo $circle->visible; // вызывает isVisible() ``` -Свойства - это прежде всего "синтаксический сахар"((syntactic sugar)), который призван сделать жизнь программиста слаще за счет упрощения кода. Если они вам не нужны, вы не обязаны их использовать. - - -Взгляд в историю .[#toc-a-glimpse-into-history] -=============================================== - -SmartObject использовался для улучшения поведения объектов различными способами, но современный PHP уже включает в себя большинство из этих улучшений. Следующий текст - это ностальгический взгляд в историю, напоминающий нам о том, как все развивалось. - -С самого начала своего существования объектная модель PHP страдала от множества серьезных недостатков и недоработок. Это привело к созданию класса `Nette\Object` (в 2007 году), который был призван исправить эти недостатки и повысить удобство работы с PHP. Достаточно было наследовать от него другие классы, чтобы они получили те преимущества, которые он дает. Когда в PHP 5.4 появилась поддержка трейтов, класс `Nette\Object` был заменен трейтом `Nette\SmartObject`. Это избавило от необходимости наследоваться от общего предка. Более того, трейты можно было использовать в классах, которые уже наследовались от другого класса. Окончательный конец `Nette\Object` наступил с выходом PHP 7.2, который запретил называть классы `Object`. - -По мере развития PHP его объектная модель и возможности языка совершенствовались. Различные функции класса `SmartObject` стали излишними. После выхода PHP 8.2 в PHP осталась только одна функция, не поддерживаемая напрямую: возможность использования так называемых [свойств |#Properties, getters, and setters]. - -Какие же возможности предоставляли `Nette\Object` и, соответственно, `Nette\SmartObject`? Вот обзор. (В примерах используется класс `Nette\Object`, но большинство возможностей применимо и к свойству `Nette\SmartObject` ). - - -Непоследовательные ошибки .[#toc-inconsistent-errors] ------------------------------------------------------ -PHP имел непоследовательное поведение при обращении к необъявленным членам. Состояние на момент публикации `Nette\Object` было следующим: - -```php -echo $obj->undeclared; // E_NOTICE, later E_WARNING -$obj->undeclared = 1; // passes silently without reporting -$obj->unknownMethod(); // Fatal error (not catchable by try/catch) -``` - -Фатальная ошибка завершала приложение без какой-либо возможности отреагировать. Тихая запись в несуществующие члены без предупреждения могла привести к серьезным ошибкам, которые было трудно обнаружить. `Nette\Object` Все эти случаи были пойманы, и было выброшено исключение `MemberAccessException`. +Начиная с PHP 8.4, той же функциональности можно достичь с помощью property hooks, которые предлагают более элегантный и краткий синтаксис: ```php -echo $obj->undeclared; // throw Nette\MemberAccessException -$obj->undeclared = 1; // throw Nette\MemberAccessException -$obj->unknownMethod(); // throw Nette\MemberAccessException -``` -Начиная с PHP 7.0, PHP больше не вызывает неперехватываемых фатальных ошибок, а доступ к необъявленным членам стал ошибкой начиная с PHP 8.2. - - -Вы имели в виду? .[#toc-did-you-mean] -------------------------------------- -Если возникала ошибка `Nette\MemberAccessException`, возможно, из-за опечатки при обращении к объектной переменной или вызове метода, `Nette\Object` пытался дать подсказку в сообщении об ошибке, как исправить ошибку, в виде знакового дополнения "Вы имели в виду?". - -```php -class Foo extends Nette\Object +class Circle { - public static function from($var) - { + public float $radius = 0.0 { + set => max(0.0, $value); } -} -$foo = Foo::form($var); -// throw Nette\MemberAccessException -// "Call to undefined static method Foo::form(), did you mean from()?" + public bool $visible { + get => $this->radius > 0; + } +} ``` -Хотя современный PHP не имеет функции "Вы имели в виду?", эта фраза может быть добавлена к ошибкам [Tracy |tracy:]. Она даже может [автоматически исправлять такие ошибки |tracy:open-files-in-ide#toc-demos]. - -Методы расширения .[#toc-extension-methods] -------------------------------------------- -Вдохновлен методами расширения из C#. Они дают возможность добавлять новые методы к существующим классам. Например, вы можете добавить метод `addDateTime()` к форме, чтобы добавить свой собственный DateTimePicker. +Extension methods +----------------- +`Nette\Object` принес в PHP еще одну интересную концепцию, вдохновленную современными языками программирования - extension methods. Эта функция, заимствованная из C#, позволяла разработчикам элегантно расширять существующие классы новыми методами без необходимости их модификации или наследования. Например, вы могли добавить в форму метод `addDateTime()`, который добавляет пользовательский DateTimePicker: ```php Form::extensionMethod( @@ -131,22 +137,22 @@ $form = new Form; $form->addDateTime('date'); ``` -Методы расширения оказались непрактичными, поскольку их имена не автозаполнялись редакторами, вместо этого они сообщали, что метод не существует. Поэтому их поддержка была прекращена. +Extension methods оказались непрактичными, потому что редакторы не подсказывали их имена, а наоборот, сообщали, что метод не существует. Поэтому их поддержка была прекращена. Сегодня для расширения функциональности классов чаще используется композиция или наследование. -Получение имени класса .[#toc-getting-the-class-name] ------------------------------------------------------ +Получение имени класса +---------------------- +Для получения имени класса SmartObject предлагал простой метод: ```php -$class = $obj->getClass(); // using Nette\Object -$class = $obj::class; // since PHP 8.0 +$class = $obj->getClass(); // используя Nette\Object +$class = $obj::class; // начиная с PHP 8.0 ``` -Доступ к размышлениям и аннотациям .[#toc-access-to-reflection-and-annotations] -------------------------------------------------------------------------------- - -`Nette\Object` предложен доступ к размышлениям и аннотациям с помощью методов `getReflection()` и `getAnnotation()`: +Доступ к рефлексии и аннотациям +------------------------------- +`Nette\Object` предоставлял доступ к рефлексии и аннотациям через методы `getReflection()` и `getAnnotation()`. Этот подход значительно упростил работу с метаинформацией классов: ```php /** @@ -158,10 +164,10 @@ class Foo extends Nette\Object $obj = new Foo; $reflection = $obj->getReflection(); -$reflection->getAnnotation('author'); // returns 'John Doe' +$reflection->getAnnotation('author'); // возвращает 'John Doe' ``` -Начиная с PHP 8.0, появилась возможность доступа к мета-информации в виде атрибутов: +Начиная с PHP 8.0, можно получать доступ к метаинформации через атрибуты, которые предлагают еще больше возможностей и лучшую проверку типов: ```php #[Author('John Doe')] @@ -175,10 +181,9 @@ $reflection->getAttributes(Author::class)[0]; ``` -Геттеры методов .[#toc-method-getters] --------------------------------------- - -`Nette\Object` предлагают элегантный способ работы с методами, как если бы они были переменными: +Method getters +-------------- +`Nette\Object` предлагал элегантный способ передачи методов, как если бы они были переменными: ```php class Foo extends Nette\Object @@ -194,7 +199,7 @@ $method = $obj->adder; echo $method(2, 3); // 5 ``` -Начиная с PHP 8.1, вы можете использовать так называемый "первоклассный синтаксис вызываемых методов":https://www.php.net/manual/en/functions.first_class_callable_syntax: +Начиная с PHP 8.1, можно использовать так называемый "first-class callable syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax, который развивает эту концепцию еще дальше: ```php $obj = new Foo; @@ -203,10 +208,9 @@ echo $method(2, 3); // 5 ``` -События .[#toc-events] ----------------------- - -`Nette\Object` предлагает синтаксический сахар для запуска [события |nette:glossary#events]: +События +------- +SmartObject предлагает упрощенный синтаксис для работы с [событиями|nette:glossary#events]. События позволяют объектам информировать другие части приложения об изменениях своего состояния: ```php class Circle extends Nette\Object @@ -221,7 +225,7 @@ class Circle extends Nette\Object } ``` -Код `$this->onChange($this, $radius)` эквивалентен следующему: +Код `$this->onChange($this, $radius)` эквивалентен следующему циклу: ```php foreach ($this->onChange as $callback) { @@ -229,8 +233,7 @@ foreach ($this->onChange as $callback) { } ``` -Для ясности мы рекомендуем избегать магического метода `$this->onChange()`. Хорошей заменой будет [Nette\Utils\Arrays::invoke |arrays#invoke]: +Для ясности мы рекомендуем избегать магического метода `$this->onChange()`. Практичной заменой является функция [Nette\Utils\Arrays::invoke|arrays#invoke]: ```php Nette\Utils\Arrays::invoke($this->onChange, $this, $radius); -``` diff --git a/utils/sl/smartobject.texy b/utils/sl/smartobject.texy index 1045e03c54..2aabb5175b 100644 --- a/utils/sl/smartobject.texy +++ b/utils/sl/smartobject.texy @@ -2,7 +2,7 @@ SmartObject *********** .[perex] -SmartObject je v preteklosti na različne načine popravljal obnašanje predmetov, vendar današnji PHP večino teh izboljšav že vključuje. Vendar pa še vedno dodaja podporo za *lastnost*. +SmartObject je leta izboljševal obnašanje objektov v PHP-ju. Od različice PHP 8.4 so vse njegove funkcije del samega PHP-ja, s čimer je zaključil svoje zgodovinsko poslanstvo biti pionir modernega objektno usmerjenega pristopa v PHP-ju. Namestitev: @@ -11,19 +11,64 @@ Namestitev: composer require nette/utils ``` +SmartObject je nastal leta 2007 kot revolucionarna rešitev pomanjkljivosti tedanjega objektnega modela PHP. V času, ko je PHP trpel zaradi številnih težav z objektno usmerjenim načrtovanjem, je prinesel pomembne izboljšave in poenostavil delo razvijalcem. Postal je legendarna komponenta ogrodja Nette. Ponujal je funkcionalnost, ki jo je PHP dobil šele mnogo let pozneje - od validacije dostopa do lastnosti objektov do naprednega ravnanja z napakami. S prihodom PHP 8.4 je zaključil svoje zgodovinsko poslanstvo, saj so vse njegove funkcije postale sestavni del jezika. Prehitel je razvoj PHP za izjemnih 17 let. -Lastnosti, nastavljalci in pridobitelji .[#toc-properties-getters-and-setters] -============================================================================== +SmartObject je doživel zanimiv tehnični razvoj. Prvotno je bil implementiran kot razred `Nette\Object`, od katerega so drugi razredi podedovali potrebno funkcionalnost. Pomembna sprememba je prišla s PHP 5.4, ki je uvedel podporo za trait-e. To je omogočilo preoblikovanje v trait `Nette\SmartObject`, kar je prineslo večjo prilagodljivost - razvijalci so lahko uporabljali funkcionalnost tudi v razredih, ki so že podedovali od drugega razreda. Medtem ko je prvotni razred `Nette\Object` prenehal obstajati s PHP 7.2 (ki je prepovedal poimenovanje razredov z besedo 'Object'), trait `Nette\SmartObject` živi naprej. -V sodobnih objektno usmerjenih jezikih (npr. C#, Python, Ruby, JavaScript) se izraz *lastnost* nanaša na [posebne člane razredov |https://en.wikipedia.org/wiki/Property_(programming)], ki so videti kot spremenljivke, v resnici pa jih predstavljajo metode. Ko se vrednost te "spremenljivke" dodeli ali prebere, se pokliče ustrezna metoda (imenovana getter ali setter). To je zelo priročno, saj nam omogoča popoln nadzor nad dostopom do spremenljivk. Potrdimo lahko vnos ali ustvarimo rezultate samo takrat, ko je lastnost prebrana. +Poglejmo si funkcije, ki sta jih nekoč ponujala `Nette\Object` in kasneje `Nette\SmartObject`. Vsaka od teh funkcij je v svojem času predstavljala pomemben korak naprej na področju objektno usmerjenega programiranja v PHP-ju. -Lastnosti PHP niso podprte, vendar jih lahko posnemamo z lastnostmi `Nette\SmartObject`. Kako jo uporabiti? -- V razred dodajte opombo v obliki `@property $xyz` -- Ustvarite getter z imenom `getXyz()` ali `isXyz()`, setter z imenom `setXyz()` -- Getter in setter morata biti *javna* ali *zaščitena* in sta neobvezna, zato je lahko lastnost *samo za branje* ali *samo za pisanje* +Konsistentna obravnava napak +---------------------------- +Ena najbolj perečih težav zgodnjega PHP-ja je bilo nedosledno obnašanje pri delu z objekti. `Nette\Object` je v ta kaos prinesel red in predvidljivost. Poglejmo si, kako se je PHP prvotno obnašal: -Lastnost za razred Circle bomo uporabili za zagotovitev, da se v spremenljivko `$radius` vnesejo samo nenegativna števila. Zamenjajte `public $radius` z lastnostjo: +```php +echo $obj->undeclared; // E_NOTICE, kasneje E_WARNING +$obj->undeclared = 1; // se izvede tiho brez opozorila +$obj->unknownMethod(); // Fatal error (ni mogoče ujeti s try/catch) +``` + +Fatal error je prekinil aplikacijo brez možnosti odziva. Tiho pisanje v neobstoječe člane brez opozorila je lahko vodilo do resnih napak, ki jih je bilo težko odkriti. `Nette\Object` je vse te primere prestregel in vrgel izjemo `MemberAccessException`, kar je programerjem omogočilo odzivanje na napake in njihovo reševanje: + +```php +echo $obj->undeclared; // vrže Nette\MemberAccessException +$obj->undeclared = 1; // vrže Nette\MemberAccessException +$obj->unknownMethod(); // vrže Nette\MemberAccessException +``` + +Od PHP 7.0 jezik ne povzroča več neulovljivih fatal error-jev, od PHP 8.2 pa se dostop do nedeklariranih članov šteje za napako. + + +Pomoč "Did you mean?" +--------------------- +`Nette\Object` je prišel z zelo priročno funkcijo: inteligentnimi predlogi pri napakah v črkovanju. Ko je razvijalec naredil napako v imenu metode ali spremenljivke, ni le sporočil napake, ampak je tudi ponudil pomoč v obliki predloga pravilnega imena. To ikonično sporočilo, znano kot "did you mean?", je programerjem prihranilo ure iskanja napak v črkovanju: + +```php +class Foo extends Nette\Object +{ + public static function from($var) + { + } +} + +$foo = Foo::form($var); +// vrže Nette\MemberAccessException +// "Call to undefined static method Foo::form(), did you mean from()?" +``` + +Današnji PHP sicer nima nobene oblike "did you mean?", vendar to funkcionalnost v sporočila o napakah dodaja [Tracy|tracy:]. In celo [samodejno popravlja|tracy:open-files-in-ide#demos] take napake. + + +Properties s kontroliranim dostopom +----------------------------------- +Pomembna inovacija, ki jo je SmartObject prinesel v PHP, so bile properties s kontroliranim dostopom. Ta koncept, običajen v jezikih kot sta C# in Python, je razvijalcem omogočil eleganten nadzor nad dostopom do podatkov objekta in zagotavljanje njihove konsistentnosti. Properties so močno orodje objektno usmerjenega programiranja. Delujejo kot spremenljivke, vendar so v resnici predstavljene z metodami (getterji in setterji). To omogoča validacijo vhodnih podatkov ali generiranje vrednosti šele ob branju. + +Za uporabo properties morate: +- Dodati razredu anotacijo v obliki `@property $xyz` +- Ustvariti getter z imenom `getXyz()` ali `isXyz()`, setter z imenom `setXyz()` +- Zagotoviti, da sta getter in setter *public* ali *protected*. Sta opcijska - lahko torej obstajata kot *read-only* ali *write-only* property + +Poglejmo si praktičen primer na razredu Circle, kjer bomo properties uporabili za zagotavljanje, da je polmer vedno nenegativno število. Nadomestili bomo prvotni `public $radius` s property: ```php /** @@ -34,22 +79,22 @@ class Circle { use Nette\SmartObject; - private float $radius = 0.0; // ni javno + private float $radius = 0.0; // ni public! - // getter za lastnost $radius + // getter za property $radius protected function getRadius(): float { return $this->radius; } - // setter za lastnost $radius + // setter za property $radius protected function setRadius(float $radius): void { - // sanitizacija vrednosti pred shranjevanjem + // vrednost pred shranjevanjem preverimo $this->radius = max(0.0, $radius); } - // getter za lastnost $visible + // getter za property $visible protected function isVisible(): bool { return $this->radius > 0; @@ -57,69 +102,30 @@ class Circle } $circle = new Circle; -$circle->radius = 10; // dejansko pokliče setRadius(10) -echo $circle->radius; // pokliče getRadius() -echo $circle->visible; // pokliče isVisible() -``` - -Lastnosti so predvsem "sintaktični sladkor"((sintactic sugar)), ki je namenjen temu, da programerju s poenostavitvijo kode osladi življenje. Če jih ne želite, vam jih ni treba uporabljati. - - -Pogled v zgodovino .[#toc-a-glimpse-into-history] -================================================= - -SmartObject je v preteklosti na številne načine izboljševal obnašanje predmetov, vendar današnji PHP večino teh izboljšav že vključuje. Naslednje besedilo je nostalgičen pogled v zgodovino, ki nas spominja na razvoj stvari. - -Objektni model PHP je že od samega začetka trpel zaradi številnih resnih pomanjkljivosti in pomanjkljivosti. To je privedlo do oblikovanja razreda `Nette\Object` (leta 2007), katerega cilj je bil odpraviti te težave in povečati udobje pri uporabi PHP. Vse, kar je bilo potrebno, je bilo, da so drugi razredi podedovali razred in pridobili prednosti, ki jih je ponujal. Ko je PHP 5.4 uvedel podporo za lastnosti, je bil razred `Nette\Object` nadomeščen z lastnostjo `Nette\SmartObject`. S tem se je odpravila potreba po dedovanju od skupnega prednika. Poleg tega je bilo mogoče lastnost uporabiti v razredih, ki so že dedovali od drugega razreda. Dokončen konec `Nette\Object` se je zgodil z izdajo PHP 7.2, ki je prepovedal, da bi se razredi imenovali `Object`. - -Z nadaljnjim razvojem PHP sta se izboljšala njegov objektni model in jezikovne zmožnosti. Različne funkcije razreda `SmartObject` so postale nepotrebne. Od izdaje PHP 8.2 je ostala le ena funkcija, ki ni neposredno podprta v PHP: možnost uporabe tako imenovanih [lastnosti |#Properties, getters, and setters]. - -Katere funkcije sta ponujala `Nette\Object` in posledično `Nette\SmartObject`? Tukaj je pregled. (V primerih je uporabljen razred `Nette\Object`, vendar večina lastnosti velja tudi za lastnost `Nette\SmartObject` ). - - -Nedosledne napake .[#toc-inconsistent-errors] ---------------------------------------------- -PHP se je nedosledno obnašal pri dostopu do nereklariranih članov. Stanje v času `Nette\Object` je bilo naslednje: - -```php -echo $obj->undeclared; // E_NOTICE, pozneje E_WARNING -$obj->undeclared = 1; // poteka tiho, brez poročanja -$obj->unknownMethod(); // usodna napaka (ki je ni mogoče ujeti s funkcijo try/catch) -``` - -Usodna napaka je prekinila aplikacijo brez možnosti odziva. Tiho pisanje v neobstoječe člene brez opozorila bi lahko privedlo do resnih napak, ki bi jih bilo težko odkriti. `Nette\Object` Vsi ti primeri so bili ujeti in zavržena je bila izjema `MemberAccessException`. - -```php -echo $obj->undeclared; // vrgel Izjemo Nette\MemberAccessException -$obj->undeclared = 1; // throw Nette\MemberAccessException -$obj->unknownMethod(); // throw Nette\MemberAccessException +$circle->radius = 10; // v resnici kliče setRadius(10) +echo $circle->radius; // kliče getRadius() +echo $circle->visible; // kliče isVisible() ``` -Od PHP 7.0 PHP ne povzroča več usodnih napak, ki jih ni mogoče ujeti, dostop do nedeklariranih članov pa je napaka od PHP 8.2. - -Ali ste mislili? .[#toc-did-you-mean] -------------------------------------- -Če se je vrgla napaka `Nette\MemberAccessException`, morda zaradi tiskarske napake pri dostopu do predmetne spremenljivke ali klicu metode, je `Nette\Object` v sporočilu o napaki poskušal podati namig, kako napako odpraviti, in sicer v obliki ikoničnega dodatka "Ali ste mislili?". +Od PHP 8.4 lahko isto funkcionalnost dosežemo s property hooks, ki ponujajo veliko bolj elegantno in jedrnato sintakso: ```php -class Foo extends Nette\Object +class Circle { - public static function from($var) - { + public float $radius = 0.0 { + set => max(0.0, $value); } -} -$foo = Foo::form($var); -// throw Nette\MemberAccessException -// "Call to undefined static method Foo::form(), did you mean from()?" + public bool $visible { + get => $this->radius > 0; + } +} ``` -Čeprav današnji PHP nima funkcije "Ali ste mislili?", lahko [Tracy |tracy:] napakam doda ta stavek. [Takšne napake |tracy:open-files-in-ide#toc-demos] lahko celo [samodejno popravi |tracy:open-files-in-ide#toc-demos]. - -Metode razširitve .[#toc-extension-methods] -------------------------------------------- -Navdih za razširitvene metode iz C#. Omogočale so dodajanje novih metod obstoječim razredom. Na primer, obrazcu lahko dodate metodo `addDateTime()` in tako dodate svoj DateTimePicker. +Extension methods +----------------- +`Nette\Object` je v PHP prinesel še en zanimiv koncept, navdihnjen s sodobnimi programskimi jeziki - extension methods. Ta funkcionalnost, prevzeta iz C#, je razvijalcem omogočila elegantno razširjanje obstoječih razredov z novimi metodami brez potrebe po spreminjanju ali dedovanju. Na primer, obrazcu ste lahko dodali metodo `addDateTime()`, ki doda lasten DateTimePicker: ```php Form::extensionMethod( @@ -131,11 +137,12 @@ $form = new Form; $form->addDateTime('date'); ``` -Razširitvene metode so se izkazale za nepraktične, saj urejevalniki njihovih imen niso samodejno dopolnili, temveč so sporočili, da metoda ne obstaja. Zato je bila njihova podpora ukinjena. +Extension metode so se izkazale za nepraktične, ker njihovih imen urejevalniki niso predlagali, nasprotno, javljali so, da metoda ne obstaja. Zato je bila njihova podpora ukinjena. Danes je običajneje uporabljati kompozicijo ali dedovanje za razširitev funkcionalnosti razredov. -Pridobivanje imena razreda .[#toc-getting-the-class-name] ---------------------------------------------------------- +Pridobivanje imena razreda +-------------------------- +Za pridobivanje imena razreda je SmartObject ponujal preprosto metodo: ```php $class = $obj->getClass(); // z uporabo Nette\Object @@ -143,10 +150,9 @@ $class = $obj::class; // od PHP 8.0 ``` -Dostop do razmisleka in opomb .[#toc-access-to-reflection-and-annotations] --------------------------------------------------------------------------- - -`Nette\Object` ponujen dostop do refleksije in anotacij z metodama `getReflection()` in `getAnnotation()`: +Dostop do refleksije in anotacij +-------------------------------- +`Nette\Object` je ponujal dostop do refleksije in anotacij preko metod `getReflection()` in `getAnnotation()`. Ta pristop je pomembno poenostavil delo z metainformacijami razredov: ```php /** @@ -161,7 +167,7 @@ $reflection = $obj->getReflection(); $reflection->getAnnotation('author'); // vrne 'John Doe' ``` -Od različice PHP 8.0 je mogoče dostopati do metainformacij v obliki atributov: +Od PHP 8.0 je mogoče dostopati do metainformacij v obliki atributov, ki ponujajo še več možnosti in boljšo tipsko preverjanje: ```php #[Author('John Doe')] @@ -175,10 +181,9 @@ $reflection->getAttributes(Author::class)[0]; ``` -Metode, ki pridobivajo .[#toc-method-getters] ---------------------------------------------- - -`Nette\Object` je ponujal eleganten način za ravnanje z metodami, kot da bi bile spremenljivke: +Method getterji +--------------- +`Nette\Object` je ponujal eleganten način za predajanje metod, kot da bi šlo za spremenljivke: ```php class Foo extends Nette\Object @@ -194,7 +199,7 @@ $method = $obj->adder; echo $method(2, 3); // 5 ``` -Od različice PHP 8.1 lahko uporabljate tako imenovano sintakso "first-class callable syntax"::https://www.php.net/manual/en/functions.first_class_callable_syntax +Od PHP 8.1 je mogoče uporabiti t.i. "first-class callable syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax, ki ta koncept pelje še dlje: ```php $obj = new Foo; @@ -203,10 +208,9 @@ echo $method(2, 3); // 5 ``` -Dogodki .[#toc-events] ----------------------- - -`Nette\Object` ponujen sintaktični sladkor za sprožitev [dogodka |nette:glossary#events]: +Dogodki +------- +SmartObject ponuja poenostavljeno sintakso za delo z [dogodki|nette:glossary#events]. Dogodki omogočajo objektom, da obvestijo druge dele aplikacije o spremembah svojega stanja: ```php class Circle extends Nette\Object @@ -221,7 +225,7 @@ class Circle extends Nette\Object } ``` -Koda `$this->onChange($this, $radius)` je enakovredna naslednjemu: +Koda `$this->onChange($this, $radius)` je enakovredna naslednji zanki: ```php foreach ($this->onChange as $callback) { @@ -229,7 +233,7 @@ foreach ($this->onChange as $callback) { } ``` -Zaradi jasnosti priporočamo, da se izognete čarobni metodi `$this->onChange()`. Praktično nadomestilo je funkcija [Nette\Utils\Arrays::invoke |arrays#invoke]: +Zaradi jasnosti priporočamo, da se izognete magični metodi `$this->onChange()`. Praktična zamenjava je funkcija [Nette\Utils\Arrays::invoke|arrays#invoke]: ```php Nette\Utils\Arrays::invoke($this->onChange, $this, $radius); diff --git a/utils/tr/smartobject.texy b/utils/tr/smartobject.texy index b08dcbca57..fc84c3b9b9 100644 --- a/utils/tr/smartobject.texy +++ b/utils/tr/smartobject.texy @@ -2,7 +2,7 @@ SmartObject *********** .[perex] -SmartObject nesnelerin davranışını birçok yönden düzeltirdi, ancak günümüz PHP'si bu iyileştirmelerin çoğunu zaten yerel olarak içermektedir. Bununla birlikte, hala *property* için destek ekler. +SmartObject, yıllarca PHP'deki nesne davranışını geliştirdi. PHP 8.4 sürümünden itibaren tüm özellikleri PHP'nin doğal bir parçası haline geldi ve böylece modern nesne yönelimli yaklaşımın öncüsü olma tarihi misyonunu tamamladı. Kurulum: @@ -11,19 +11,64 @@ Kurulum: composer require nette/utils ``` +SmartObject, 2007 yılında PHP'nin o zamanki nesne modelinin eksikliklerine devrimci bir çözüm olarak ortaya çıktı. PHP'nin nesne yönelimli tasarımda birçok sorunla karşı karşıya olduğu bir dönemde, geliştiriciler için önemli iyileştirmeler ve basitleştirmeler getirdi. Nette framework'ünün efsanevi bir parçası haline geldi. PHP'nin yıllar sonra kazanacağı işlevselliği sundu - nesne özelliklerine erişim doğrulamasından sofistike hata yönetimine kadar. PHP 8.4'ün gelişiyle, tüm özellikleri dilin doğal bir parçası haline geldiğinde tarihi misyonunu tamamladı. PHP'nin gelişimini dikkat çekici bir şekilde 17 yıl önceden gösterdi. -Özellikler, Getiriciler ve Ayarlayıcılar .[#toc-properties-getters-and-setters] -=============================================================================== +SmartObject ilginç bir teknik evrim geçirdi. Başlangıçta, diğer sınıfların gerekli işlevselliği miras aldığı `Nette\Object` sınıfı olarak uygulandı. PHP 5.4 ile trait desteğinin gelmesiyle önemli bir değişiklik yaşandı. Bu, `Nette\SmartObject` trait'ine dönüşümü sağladı ve daha fazla esneklik getirdi - geliştiriciler işlevselliği başka bir sınıftan miras alan sınıflarda bile kullanabilir hale geldi. Orijinal `Nette\Object` sınıfı PHP 7.2 ile (sınıfların 'Object' kelimesiyle adlandırılmasını yasaklayan) sona ererken, `Nette\SmartObject` trait'i yaşamaya devam ediyor. -Modern nesne yönelimli dillerde (örneğin C#, Python, Ruby, JavaScript) *property* terimi, [sınıfların |https://en.wikipedia.org/wiki/Property_(programming)] değişken gibi görünen ancak aslında yöntemlerle temsil edilen [özel üyelerini |https://en.wikipedia.org/wiki/Property_(programming)] ifade eder. Bu "değişkenin" değeri atandığında veya okunduğunda, ilgili yöntem (getter veya setter olarak adlandırılır) çağrılır. Bu çok kullanışlı bir şeydir, bize değişkenlere erişim üzerinde tam kontrol sağlar. Girdiyi doğrulayabilir veya yalnızca özellik okunduğunda sonuç üretebiliriz. +`Nette\Object` ve daha sonra `Nette\SmartObject`'in sunduğu özellikleri inceleyelim. Bu işlevlerin her biri, zamanında PHP nesne yönelimli programlamada önemli bir adımı temsil ediyordu. -PHP özellikleri desteklenmez, ancak trait `Nette\SmartObject` bunları taklit edebilir. Nasıl kullanılır? -- Sınıfa şu biçimde bir ek açıklama ekleyin `@property $xyz` -- `getXyz()` veya `isXyz()` adında bir getter, adında bir setter oluşturun. `setXyz()` -- Getter ve setter *public* veya *protected* olmalıdır ve isteğe bağlıdır, bu nedenle *read-only* veya *write-only* özelliği olabilir +Tutarlı Hata Durumları +---------------------- +Erken dönem PHP'nin en önemli sorunlarından biri, nesnelerle çalışırken tutarsız davranışlardı. `Nette\Object` bu kargaşaya düzen ve öngörülebilirlik getirdi. PHP'nin orijinal davranışına bakalım: -`$radius` değişkenine yalnızca negatif olmayan sayıların girilmesini sağlamak için Circle sınıfının özelliğini kullanacağız. `public $radius` öğesini özellik ile değiştirin: +```php +echo $obj->undeclared; // E_NOTICE, daha sonra E_WARNING +$obj->undeclared = 1; // sessizce uyarısız geçer +$obj->unknownMethod(); // Fatal error (try/catch ile yakalanamaz) +``` + +Fatal error uygulamayı herhangi bir tepki verme olasılığı olmadan sonlandırırdı. Var olmayan üyelere sessizce yazma, tespit edilmesi zor ciddi hatalara yol açabilirdi. `Nette\Object` tüm bu durumları yakalayıp bir `MemberAccessException` fırlatırdı, bu da programcıların hatalara tepki vermesini ve onları ele almasını sağlardı: + +```php +echo $obj->undeclared; // Nette\MemberAccessException fırlatır +$obj->undeclared = 1; // Nette\MemberAccessException fırlatır +$obj->unknownMethod(); // Nette\MemberAccessException fırlatır +``` + +PHP 7.0'dan beri dil artık yakalanamayan fatal error'lar oluşturmuyor ve PHP 8.2'den beri tanımlanmamış üyelere erişim hata olarak kabul ediliyor. + + +"Did you mean?" Yardımcısı +-------------------------- +`Nette\Object` çok kullanışlı bir özellikle geldi: yazım hatalarında akıllı öneriler. Bir geliştirici bir metot veya değişken adında hata yaptığında, sadece hatayı bildirmekle kalmaz, aynı zamanda doğru adı önererek yardım ederdi. "Did you mean?" olarak bilinen bu ikonik mesaj, programcıların yazım hatalarını aramak için harcadıkları saatleri kurtardı: + +```php +class Foo extends Nette\Object +{ + public static function from($var) + { + } +} + +$foo = Foo::form($var); +// Nette\MemberAccessException fırlatır +// "Call to undefined static method Foo::form(), did you mean from()?" +``` + +Günümüzde PHP'nin kendisinde "did you mean?" özelliği yok, ancak bu özellik [Tracy|tracy:] tarafından sağlanıyor. Hatta bu tür hataları [otomatik düzeltebiliyor|tracy:open-files-in-ide#demos]. + + +Kontrollü Erişimli Properties +----------------------------- +SmartObject'in PHP'ye getirdiği önemli yeniliklerden biri kontrollü erişimli property'lerdi. C# veya Python gibi dillerde yaygın olan bu konsept, geliştiricilerin nesne verilerine erişimi zarif bir şekilde kontrol etmelerini ve tutarlılıklarını sağlamalarını sağladı. Property'ler nesne yönelimli programlamanın güçlü bir aracıdır. Değişkenler gibi çalışırlar ancak aslında metodlarla (getter ve setter) temsil edilirler. Bu, girişlerin doğrulanmasını veya okuma anında değerlerin oluşturulmasını sağlar. + +Property'leri kullanmak için şunları yapmalısınız: +- Sınıfa `@property $xyz` şeklinde bir annotation ekleyin +- `getXyz()` veya `isXyz()` adında bir getter, `setXyz()` adında bir setter oluşturun +- Getter ve setter'ın *public* veya *protected* olmasını sağlayın. Bunlar isteğe bağlıdır - yani *read-only* veya *write-only* property'ler olabilir + +Circle sınıfında yarıçapın her zaman negatif olmayan bir sayı olmasını sağlamak için property'leri kullanan pratik bir örneğe bakalım. `public $radius` yerine bir property kullanalım: ```php /** @@ -34,22 +79,22 @@ class Circle { use Nette\SmartObject; - private float $radius = 0.0; // herkese açık değil + private float $radius = 0.0; // public değil! - //radius özelliği için getter + // $radius property'si için getter protected function getRadius(): float { return $this->radius; } - //radius özelliği için setter + // $radius property'si için setter protected function setRadius(float $radius): void { - // kaydetmeden önce değeri sanitize etme + // kaydetmeden önce değeri temizle $this->radius = max(0.0, $radius); } - // özellik için getter $visible + // $visible property'si için getter protected function isVisible(): bool { return $this->radius > 0; @@ -57,69 +102,30 @@ class Circle } $circle = new Circle; -$circle->radius = 10; // aslında setRadius(10) çağırır -echo $circle->radius; // getRadius() işlevini çağırır -echo $circle->visible; // isVisible() işlevini çağırır -``` - -Özellikler öncelikle "sözdizimsel şeker"((syntactic sugar)) olup, kodu basitleştirerek programcının hayatını daha tatlı hale getirmeyi amaçlar. Eğer onları istemiyorsanız, kullanmak zorunda değilsiniz. - - -Tarihe Bir Bakış .[#toc-a-glimpse-into-history] -=============================================== - -SmartObject, nesnelerin davranışlarını çeşitli şekillerde iyileştirmek için kullanılırdı, ancak bugünün PHP'si bu geliştirmelerin çoğunu zaten yerel olarak içeriyor. Aşağıdaki metin geçmişe nostaljik bir bakıştır ve bize işlerin nasıl geliştiğini hatırlatır. - -PHP'nin nesne modeli, başlangıcından itibaren sayısız ciddi eksiklik ve yetersizlikten muzdaripti. Bu durum, bu sorunları gidermeyi ve PHP'nin kullanım rahatlığını artırmayı amaçlayan `Nette\Object` sınıfının (2007'de) oluşturulmasına yol açtı. İhtiyaç duyulan tek şey diğer sınıfların bu sınıftan miras almasıydı ve onlar da bu sınıfın sunduğu avantajlardan yararlanabileceklerdi. PHP 5.4 özellikler için destek sunduğunda, `Nette\Object` sınıfının yerini `Nette\SmartObject` özelliği aldı. Bu, ortak bir atadan miras alma ihtiyacını ortadan kaldırdı. Dahası, özellik zaten başka bir sınıftan miras alan sınıflarda kullanılabiliyordu. `Nette\Object` 'un kesin sonu, sınıfların `Object` olarak adlandırılmasını yasaklayan PHP 7.2'nin yayınlanmasıyla geldi. - -PHP'nin gelişimi devam ettikçe, nesne modeli ve dil yetenekleri de gelişti. `SmartObject` sınıfının çeşitli işlevleri gereksiz hale geldi. PHP 8.2'nin yayınlanmasından bu yana, PHP'de doğrudan desteklenmeyen tek bir özellik kaldı: sözde [özellikleri |#Properties, getters, and setters] kullanma yeteneği. - - `Nette\Object` ve buna bağlı olarak `Nette\SmartObject` hangi özellikleri sunuyordu? İşte genel bir bakış. (Örneklerde `Nette\Object` sınıfı kullanılmıştır, ancak çoğu özellik `Nette\SmartObject` özelliği için de geçerlidir). - - -Tutarsız Hatalar .[#toc-inconsistent-errors] --------------------------------------------- -PHP, bildirilmemiş üyelere erişirken tutarsız davranışlar sergiliyordu. `Nette\Object` adresinin durumu aşağıdaki gibiydi: - -```php -echo $obj->undeclared; // E_NOTICE, daha sonra E_WARNING -$obj->undeclared = 1; // raporlama yapmadan sessizce geçer -$obj->unknownMethod(); // Ölümcül hata (try/catch ile yakalanamaz) +$circle->radius = 10; // aslında setRadius(10)'u çağırır +echo $circle->radius; // getRadius()'u çağırır +echo $circle->visible; // isVisible()'ı çağırır ``` -Ölümcül hata, herhangi bir tepki verme imkanı olmadan uygulamayı sonlandırdı. Var olmayan üyelere uyarı vermeden sessizce yazmak, tespit edilmesi zor ciddi hatalara yol açabilirdi. `Nette\Object` Tüm bu durumlar yakalandı ve bir istisna `MemberAccessException` atıldı. - -```php -echo $obj->undeclared; // throw Nette\MemberAccessException -$obj->undeclared = 1; // throw Nette\MemberAccessException -$obj->unknownMethod(); // throw Nette\MemberAccessException -``` -PHP 7.0'dan beri PHP artık yakalanamayan ölümcül hatalara neden olmamaktadır ve bildirilmemiş üyelere erişim PHP 8.2'den beri bir hatadır. - - -Ne demek istiyorsun? .[#toc-did-you-mean] ------------------------------------------ -Bir nesne değişkenine erişirken veya bir yöntemi çağırırken yapılan yazım hatası nedeniyle `Nette\MemberAccessException` hatası atıldığında, `Nette\Object` hata mesajında hatanın nasıl düzeltileceğine dair ikonik "demek istediniz mi?" eki şeklinde bir ipucu vermeye çalışmıştır. +PHP 8.4'ten beri, aynı işlevselliğe property hooks kullanılarak ulaşılabilir, bu da çok daha zarif ve özlü bir sözdizimi sunar: ```php -class Foo extends Nette\Object +class Circle { - public static function from($var) - { + public float $radius = 0.0 { + set => max(0.0, $value); } -} -$foo = Foo::form($var); -// throw Nette\MemberAccessException -// "Call to undefined static method Foo::form(), did you mean from()?" + public bool $visible { + get => $this->radius > 0; + } +} ``` -Günümüz PHP'sinde "demek istediniz mi?" özelliği olmasa da, bu ifade [Tracy |tracy:] tarafından hatalara eklenebilir. Hatta bu [tür hataları otomatik olarak düzeltebilir |tracy:open-files-in-ide#toc-demos]. - -Uzatma yöntemleri .[#toc-extension-methods] -------------------------------------------- -C#'ın uzantı yöntemlerinden esinlenilmiştir. Mevcut sınıflara yeni yöntemler ekleme imkanı verdiler. Örneğin, kendi DateTimePicker'ınızı eklemek için bir forma `addDateTime()` yöntemini ekleyebilirsiniz. +Extension Methods +----------------- +`Nette\Object`, modern programlama dillerinden esinlenen başka bir ilginç konsepti PHP'ye getirdi - extension methods. C#'tan alınan bu özellik, geliştiricilerin var olan sınıfları değiştirmeden veya onlardan miras almadan yeni metodlarla genişletmelerini sağladı. Örneğin, bir forma özel bir DateTimePicker ekleyen bir `addDateTime()` metodu ekleyebilirdiniz: ```php Form::extensionMethod( @@ -131,22 +137,22 @@ $form = new Form; $form->addDateTime('date'); ``` -Uzatma yöntemlerinin pratik olmadığı kanıtlandı çünkü isimleri editörler tarafından otomatik olarak tamamlanmadı, bunun yerine yöntemin mevcut olmadığını bildirdiler. Bu nedenle destekleri kesilmiştir. +Extension metodları, editörlerin isimlerini önermemesi ve bunun yerine metodun var olmadığını bildirmesi nedeniyle pratik olmadığını kanıtladı. Bu nedenle destekleri sonlandırıldı. Günümüzde sınıf işlevselliğini genişletmek için composition veya inheritance kullanmak daha yaygın. -Sınıf Adını Alma .[#toc-getting-the-class-name] ------------------------------------------------ +Sınıf Adını Alma +---------------- +SmartObject sınıf adını almak için basit bir metod sunuyordu: ```php -$class = $obj->getClass(); // using Nette\Object -$class = $obj::class; // PHP 8.0'dan beri +$class = $obj->getClass(); // Nette\Object kullanarak +$class = $obj::class; // PHP 8.0'dan beri ``` -Yansıma ve Ek Açıklamalara Erişim .[#toc-access-to-reflection-and-annotations] ------------------------------------------------------------------------------- - -`Nette\Object` `getReflection()` ve `getAnnotation()` yöntemlerini kullanarak yansıtma ve ek açıklamaya erişim sundu: +Reflection ve Annotation Erişimi +-------------------------------- +`Nette\Object`, `getReflection()` ve `getAnnotation()` metodları aracılığıyla reflection ve annotation'lara erişim sağlıyordu. Bu yaklaşım sınıf meta-bilgileriyle çalışmayı önemli ölçüde basitleştirdi: ```php /** @@ -161,7 +167,7 @@ $reflection = $obj->getReflection(); $reflection->getAnnotation('author'); // 'John Doe' döndürür ``` -PHP 8.0'dan itibaren meta-bilgilere öznitelikler şeklinde erişmek mümkündür: +PHP 8.0'dan beri, meta-bilgilere özellikler (attributes) aracılığıyla erişmek mümkün, bu da daha fazla olanak ve daha iyi tip kontrolü sunuyor: ```php #[Author('John Doe')] @@ -175,10 +181,9 @@ $reflection->getAttributes(Author::class)[0]; ``` -Yöntem Getiriciler .[#toc-method-getters] ------------------------------------------ - -`Nette\Object` metotları değişkenlermiş gibi ele almak için zarif bir yol sundu: +Method Getters +-------------- +`Nette\Object` metodları değişkenlermiş gibi aktarmanın zarif bir yolunu sunuyordu: ```php class Foo extends Nette\Object @@ -194,7 +199,7 @@ $method = $obj->adder; echo $method(2, 3); // 5 ``` -PHP 8.1'den itibaren, "birinci sınıf çağrılabilir sözdizimi":https://www.php.net/manual/en/functions.first_class_callable_syntax olarak adlandırılan sözdizimini:https://www.php.net/manual/en/functions.first_class_callable_syntax kullanabilirsiniz: +PHP 8.1'den beri "first-class callable syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax kullanabilirsiniz, bu da konsepti daha da ileri taşıyor: ```php $obj = new Foo; @@ -203,10 +208,9 @@ echo $method(2, 3); // 5 ``` -Etkinlikler .[#toc-events] --------------------------- - -`Nette\Object` [olayı |nette:glossary#events] tetiklemek için sözdizimsel şeker sundu: +Olaylar (Events) +---------------- +SmartObject [olaylarla|nette:glossary#events] çalışmak için basitleştirilmiş bir sözdizimi sunar. Olaylar, nesnelerin durumlarındaki değişiklikler hakkında uygulamanın diğer kısımlarını bilgilendirmesini sağlar: ```php class Circle extends Nette\Object @@ -221,7 +225,7 @@ class Circle extends Nette\Object } ``` -`$this->onChange($this, $radius)` kodu aşağıdakine eşdeğerdir: +`$this->onChange($this, $radius)` kodu aşağıdaki döngüye eşdeğerdir: ```php foreach ($this->onChange as $callback) { @@ -229,7 +233,7 @@ foreach ($this->onChange as $callback) { } ``` -Netlik açısından sihirli yöntemden kaçınmanızı öneririz `$this->onChange()`. Pratik bir ikame [Nette\Utils\Arrays::invoke |arrays#invoke] fonksiyonudur: +Netlik için `$this->onChange()` sihirli metodundan kaçınmanızı öneririz. Pratik bir alternatif [Nette\Utils\Arrays::invoke|arrays#invoke] fonksiyonudur: ```php Nette\Utils\Arrays::invoke($this->onChange, $this, $radius); diff --git a/utils/uk/smartobject.texy b/utils/uk/smartobject.texy index 446738b83e..8257edc244 100644 --- a/utils/uk/smartobject.texy +++ b/utils/uk/smartobject.texy @@ -2,7 +2,7 @@ SmartObject *********** .[perex] -Раніше SmartObject виправляв поведінку об'єктів багатьма способами, але сьогоднішній PHP вже містить більшість з цих покращень вбудовано. Проте, він все ще додає підтримку *property*. +SmartObject протягом багатьох років покращував поведінку об'єктів у PHP. Починаючи з версії PHP 8.4, усі його функції стали вбудованими частинами самого PHP, чим завершив свою історичну місію бути піонером сучасного об'єктно-орієнтованого підходу в PHP. Встановлення: @@ -11,19 +11,64 @@ SmartObject composer require nette/utils ``` +SmartObject з'явився у 2007 році як революційне рішення недоліків тодішньої об'єктної моделі PHP. У час, коли PHP страждав від численних проблем з об'єктно-орієнтованим дизайном, він приніс значні покращення та спростив роботу розробників. Він став легендарною частиною фреймворку Nette. Він пропонував функціональність, яку PHP отримав лише через багато років - від валідації доступу до властивостей об'єктів до складної обробки помилок. З появою PHP 8.4 він завершив свою історичну місію, оскільки всі його функції стали вбудованими частинами мови. Він випередив розвиток PHP на вражаючих 17 років. -Властивості, геттери та сеттери .[#toc-properties-getters-and-setters] -====================================================================== +SmartObject пройшов цікавий технічний розвиток. Спочатку він був реалізований як клас `Nette\Object`, від якого інші класи успадковували потрібну функціональність. Значна зміна прийшла з PHP 5.4, який представив підтримку trait. Це дозволило трансформацію у trait `Nette\SmartObject`, що принесло більшу гнучкість - розробники могли використовувати функціональність навіть у класах, які вже успадковувалися від іншого класу. У той час як оригінальний клас `Nette\Object` припинив існування з появою PHP 7.2 (який заборонив називати класи словом 'Object'), trait `Nette\SmartObject` продовжує жити. -У сучасних об'єктно-орієнтованих мовах (наприклад, C#, Python, Ruby, JavaScript) термін *властивість* відноситься до [спеціальних членів класів |https://en.wikipedia.org/wiki/Property_(programming)], що виглядають як змінні, але насправді представлені методами. Коли значення такої "змінної" присвоюється або зчитується, викликається відповідний метод (званий getter або setter). Це дуже зручна річ, вона дає нам повний контроль над доступом до змінних. Ми можемо перевіряти дані, що вводяться, або генерувати результати тільки тоді, коли властивість прочитано. +Розглянемо функції, які колись пропонували `Nette\Object` і пізніше `Nette\SmartObject`. Кожна з цих функцій у свій час представляла значний крок вперед у області об'єктно-орієнтованого програмування в PHP. -Властивості PHP не підтримуються, але trait `Nette\SmartObject` може їх імітувати. Як це використовувати? -- Додайте анотацію до класу у вигляді `@property $xyz` -- Створіть геттер з іменем `getXyz()` або `isXyz()`, сеттер з іменем `setXyz()` -- Геттер і сеттер мають бути *публічними* або *захищеними* і необов'язковими, тому може бути властивість *тільки для читання* або *тільки для запису*. +Послідовна обробка помилок +-------------------------- +Однією з найгостріших проблем раннього PHP була непослідовна поведінка при роботі з об'єктами. `Nette\Object` вніс порядок і передбачуваність у цей хаос. Подивімося, як поводилось PHP спочатку: -Ми будемо використовувати властивість для класу Circle, щоб гарантувати, що в змінну `$radius` будуть поміщатися тільки невід'ємні числа. Замініть `public $radius` на property: +```php +echo $obj->undeclared; // E_NOTICE, пізніше E_WARNING +$obj->undeclared = 1; // проходить тихо без попередження +$obj->unknownMethod(); // Fatal error (неможливо перехопити за допомогою try/catch) +``` + +Fatal error завершував роботу програми без можливості якось відреагувати. Тихий запис у неіснуючі члени без попередження міг призвести до серйозних помилок, які було важко виявити. `Nette\Object` перехоплював усі ці випадки і викидав виняток `MemberAccessException`, що дозволяло програмістам реагувати на помилки та обробляти їх: + +```php +echo $obj->undeclared; // викидає Nette\MemberAccessException +$obj->undeclared = 1; // викидає Nette\MemberAccessException +$obj->unknownMethod(); // викидає Nette\MemberAccessException +``` + +Починаючи з PHP 7.0, мова більше не викликає неперехоплювані fatal error, а з PHP 8.2 доступ до неоголошених членів вважається помилкою. + + +Підказка "Did you mean?" +------------------------ +`Nette\Object` з'явився з дуже зручною функцією: інтелектуальними підказками при опечатках. Коли розробник робив помилку в назві методу чи змінної, він не лише повідомляв про помилку, але й пропонував допомогу у вигляді підказки правильної назви. Це іконічне повідомлення, відоме як "did you mean?", зекономило програмістам години пошуку опечаток: + +```php +class Foo extends Nette\Object +{ + public static function from($var) + { + } +} + +$foo = Foo::form($var); +// викидає Nette\MemberAccessException +// "Call to undefined static method Foo::form(), did you mean from()?" +``` + +Сучасний PHP хоч і не має жодної форми "did you mean?", але цю функцію тепер забезпечує [Tracy|tracy:]. Він навіть може [автоматично виправляти|tracy:open-files-in-ide#demos] такі помилки. + + +Properties з контрольованим доступом +------------------------------------ +Значною інновацією, яку SmartObject приніс у PHP, були properties з контрольованим доступом. Ця концепція, поширена в таких мовах як C# чи Python, дозволила розробникам елегантно контролювати доступ до даних об'єкта та забезпечувати їх консистентність. Properties є потужним інструментом об'єктно-орієнтованого програмування. Вони функціонують як змінні, але насправді представлені методами (getters і setters). Це дозволяє валідувати вхідні дані або генерувати значення в момент читання. + +Для використання properties потрібно: +- Додати анотацію класу у форматі `@property $xyz` +- Створити getter з назвою `getXyz()` або `isXyz()`, setter з назвою `setXyz()` +- Забезпечити, щоб getter і setter були *public* або *protected*. Вони опціональні - тобто можуть існувати як *read-only* або *write-only* properties + +Розглянемо практичний приклад на класі Circle, де properties використовуються для забезпечення того, що радіус завжди буде невід'ємним числом. Замінимо `public $radius` на property: ```php /** @@ -34,22 +79,22 @@ class Circle { use Nette\SmartObject; - private float $radius = 0.0; // not public + private float $radius = 0.0; // не public! - // геттер для властивості $radius + // getter для property $radius protected function getRadius(): float { return $this->radius; } - // задатчик для властивості $radius + // setter для property $radius protected function setRadius(float $radius): void { - // очищення значення перед збереженням + // санітизуємо значення перед збереженням $this->radius = max(0.0, $radius); } - // геттер для властивості $visible + // getter для property $visible protected function isVisible(): bool { return $this->radius > 0; @@ -57,69 +102,30 @@ class Circle } $circle = new Circle; -$circle->radius = 10; // власне викликає setRadius(10) -echo $circle->radius; // викликаємо getRadius() -echo $circle->visible; // викликаємо isVisible() -``` - -Властивості - це насамперед "синтаксичний цукор"((syntactic sugar)), який покликаний зробити життя програміста солодшим за рахунок спрощення коду. Якщо вони вам не потрібні, ви не зобов'язані їх використовувати. - - -Погляд в історію .[#toc-a-glimpse-into-history] -=============================================== - -SmartObject використовувався для покращення поведінки об'єктів багатьма способами, але сьогоднішній PHP вже включає в себе більшість з цих покращень нативно. Наступний текст - це ностальгічний погляд в історію, що нагадує нам про те, як все розвивалося. - -Від самого початку об'єктна модель PHP страждала від безлічі серйозних недоліків і недоробок. Це призвело до створення класу `Nette\Object` (у 2007 році), який мав на меті виправити ці проблеми та підвищити комфорт використання PHP. Все, що було потрібно - це щоб інші класи успадковували його, і вони отримували переваги, які він пропонував. Коли в PHP 5.4 було введено підтримку трейтів, клас `Nette\Object` було замінено на трейт `Nette\SmartObject`. Це усунуло необхідність успадковувати від спільного предка. Крім того, ознаку можна було використовувати в класах, які вже були успадковані від іншого класу. Остаточний кінець `Nette\Object` настав з виходом PHP 7.2, який заборонив класам називатися `Object`. - -З розвитком PHP його об'єктна модель і можливості мови покращувалися. Різні функції класу `SmartObject` стали надлишковими. З виходом PHP 8.2 залишилася лише одна функція, яка не підтримується безпосередньо в PHP: можливість використання так званих [властивостей |#Properties, getters, and setters]. - -Які ж можливості пропонували `Nette\Object` і, відповідно, `Nette\SmartObject`? Ось короткий огляд. (У прикладах використовується клас `Nette\Object`, але більшість можливостей також застосовні до властивості `Nette\SmartObject` ). - - -Непослідовні помилки .[#toc-inconsistent-errors] ------------------------------------------------- -PHP мав непослідовну поведінку при зверненні до неоголошених членів. Стан на момент публікації `Nette\Object` був таким: - -```php -echo $obj->undeclared; // E_NOTICE, пізніше E_WARNING -$obj->undeclared = 1; // проходить мовчки без повідомлення -$obj->unknownMethod(); // Фатальна помилка (не перехоплюється try/catch) -``` - -Фатальна помилка завершувала додаток без будь-якої можливості відреагувати. Тихий запис у неіснуючі члени без попередження міг призвести до серйозних помилок, які було важко виявити. `Nette\Object` Всі ці випадки були спіймані, і було викинуто виняток `MemberAccessException`. - -```php -echo $obj->undeclared; // згенерувати виключення Nette\MemberAccessException -$obj->undeclared = 1; // згенерувати виключення Nette\MemberAccessException -$obj->unknownMethod(); // згенерувати виключення Nette\MemberAccessException +$circle->radius = 10; // насправді викликає setRadius(10) +echo $circle->radius; // викликає getRadius() +echo $circle->visible; // викликає isVisible() ``` -Починаючи з PHP 7.0, PHP більше не спричиняє неперехоплюваних фатальних помилок, а доступ до неоголошених членів став помилкою, починаючи з PHP 8.2. - -Ви мали на увазі? .[#toc-did-you-mean] --------------------------------------- -Якщо виникала помилка `Nette\MemberAccessException`, можливо, через друкарську помилку під час звернення до об'єктної змінної або виклику методу, `Nette\Object` намагався дати підказку в повідомленні про помилку, як виправити помилку, у вигляді знакового доповнення "Ви мали на увазі?". +Починаючи з PHP 8.4, тієї ж функціональності можна досягти за допомогою property hooks, які пропонують набагато елегантніший і коротший синтаксис: ```php -class Foo extends Nette\Object +class Circle { - public static function from($var) - { + public float $radius = 0.0 { + set => max(0.0, $value); } -} -$foo = Foo::form($var); -// throw Nette\MemberAccessException -// "Call to undefined static method Foo::form(), did you mean from()?" + public bool $visible { + get => $this->radius > 0; + } +} ``` -Хоча сучасний PHP не має функції "ви мали на увазі?", цю фразу можна додати до помилок за допомогою [Трейсі |tracy:]. Він навіть може [автоматично виправляти такі помилки |tracy:open-files-in-ide#toc-demos]. - -Методи розширення .[#toc-extension-methods] -------------------------------------------- -Натхненний методами розширення з C#. Вони дають можливість додавати нові методи до наявних класів. Наприклад, ви можете додати метод `addDateTime()` до форми, щоб додати свій власний DateTimePicker. +Extension methods +----------------- +`Nette\Object` приніс у PHP ще одну цікаву концепцію, натхненну сучасними мовами програмування - extension methods. Ця функція, запозичена з C#, дозволила розробникам елегантно розширювати існуючі класи новими методами без необхідності їх модифікації чи успадкування. Наприклад, ви могли додати до форми метод `addDateTime()`, який додає власний DateTimePicker: ```php Form::extensionMethod( @@ -131,22 +137,22 @@ $form = new Form; $form->addDateTime('date'); ``` -Методи розширення виявилися непрактичними, оскільки їхні імена не автозаповнювалися редакторами, натомість вони повідомляли, що метод не існує. Тому їхню підтримку було припинено. +Extension methods виявилися непрактичними, оскільки редактори не підказували їх назви, навпаки, повідомляли, що метод не існує. Тому їх підтримку було припинено. Сьогодні більш поширеним є використання композиції або успадкування для розширення функціональності класів. -Отримання імені класу .[#toc-getting-the-class-name] ----------------------------------------------------- +Отримання назви класу +--------------------- +Для отримання назви класу SmartObject пропонував простий метод: ```php -$class = $obj->getClass(); // використання Nette\Object -$class = $obj::class; // починаючи з PHP 8.0 +$class = $obj->getClass(); // використовуючи Nette\Object +$class = $obj::class; // починаючи з PHP 8.0 ``` -Доступ до роздумів та анотацій .[#toc-access-to-reflection-and-annotations] ---------------------------------------------------------------------------- - -`Nette\Object` запропоновано доступ до роздумів і анотацій за допомогою методів `getReflection()` і `getAnnotation()`: +Доступ до рефлексії та анотацій +------------------------------- +`Nette\Object` надавав доступ до рефлексії та анотацій через методи `getReflection()` та `getAnnotation()`. Цей підхід значно спростив роботу з метаінформацією класів: ```php /** @@ -161,7 +167,7 @@ $reflection = $obj->getReflection(); $reflection->getAnnotation('author'); // повертає 'John Doe' ``` -Починаючи з PHP 8.0, з'явилася можливість доступу до мета-інформації у вигляді атрибутів: +Починаючи з PHP 8.0, можна отримувати доступ до метаінформації через атрибути, які пропонують ще більше можливостей та кращу перевірку типів: ```php #[Author('John Doe')] @@ -175,10 +181,9 @@ $reflection->getAttributes(Author::class)[0]; ``` -Геттери методів .[#toc-method-getters] --------------------------------------- - -`Nette\Object` пропонують елегантний спосіб роботи з методами, наче вони є змінними: +Method getters +-------------- +`Nette\Object` пропонував елегантний спосіб передачі методів, ніби вони були змінними: ```php class Foo extends Nette\Object @@ -194,7 +199,7 @@ $method = $obj->adder; echo $method(2, 3); // 5 ``` -Починаючи з PHP 8.1, ви можете використовувати так званий "першокласний синтаксис методів, що викликаються":https://www.php.net/manual/en/functions.first_class_callable_syntax: +Починаючи з PHP 8.1, можна використовувати так званий "first-class callable syntax":https://www.php.net/manual/en/functions.first_class_callable_syntax, який розвиває цю концепцію ще далі: ```php $obj = new Foo; @@ -203,10 +208,9 @@ echo $method(2, 3); // 5 ``` -Події .[#toc-events] --------------------- - -`Nette\Object` пропонує синтаксичний цукор для запуску [події |nette:glossary#events]: +Події +----- +SmartObject пропонує спрощений синтаксис для роботи з [подіями|nette:glossary#events]. Події дозволяють об'єктам інформувати інші частини програми про зміни свого стану: ```php class Circle extends Nette\Object @@ -221,7 +225,7 @@ class Circle extends Nette\Object } ``` -Код `$this->onChange($this, $radius)` еквівалентний наступному: +Код `$this->onChange($this, $radius)` еквівалентний наступному циклу: ```php foreach ($this->onChange as $callback) { @@ -229,7 +233,7 @@ foreach ($this->onChange as $callback) { } ``` -Для ясності ми рекомендуємо уникати магічного методу `$this->onChange()`. Хорошою заміною буде [Nette\Utils\Arrays::invoke |arrays#invoke]: +Для кращої зрозумілості рекомендуємо уникати магічного методу `$this->onChange()`. Практичною заміною є функція [Nette\Utils\Arrays::invoke|arrays#invoke]: ```php Nette\Utils\Arrays::invoke($this->onChange, $this, $radius); From d280c3e40f4617cde17bf8eb9c9ff71db8c51519 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Thu, 28 Nov 2024 17:05:34 +0100 Subject: [PATCH 3/5] nette/php-generator 4.1.7 --- php-generator/bg/@home.texy | 90 +++++++++++++++++++++++++++++++++++-- php-generator/cs/@home.texy | 90 +++++++++++++++++++++++++++++++++++-- php-generator/de/@home.texy | 90 +++++++++++++++++++++++++++++++++++-- php-generator/el/@home.texy | 90 +++++++++++++++++++++++++++++++++++-- php-generator/en/@home.texy | 90 +++++++++++++++++++++++++++++++++++-- php-generator/es/@home.texy | 90 +++++++++++++++++++++++++++++++++++-- php-generator/fr/@home.texy | 90 +++++++++++++++++++++++++++++++++++-- php-generator/hu/@home.texy | 90 +++++++++++++++++++++++++++++++++++-- php-generator/it/@home.texy | 90 +++++++++++++++++++++++++++++++++++-- php-generator/ja/@home.texy | 90 +++++++++++++++++++++++++++++++++++-- php-generator/pl/@home.texy | 90 +++++++++++++++++++++++++++++++++++-- php-generator/pt/@home.texy | 90 +++++++++++++++++++++++++++++++++++-- php-generator/ro/@home.texy | 90 +++++++++++++++++++++++++++++++++++-- php-generator/ru/@home.texy | 90 +++++++++++++++++++++++++++++++++++-- php-generator/sl/@home.texy | 90 +++++++++++++++++++++++++++++++++++-- php-generator/tr/@home.texy | 90 +++++++++++++++++++++++++++++++++++-- php-generator/uk/@home.texy | 90 +++++++++++++++++++++++++++++++++++-- 17 files changed, 1462 insertions(+), 68 deletions(-) diff --git a/php-generator/bg/@home.texy b/php-generator/bg/@home.texy index 80b6ed7027..081f668ebd 100644 --- a/php-generator/bg/@home.texy +++ b/php-generator/bg/@home.texy @@ -4,7 +4,7 @@
Търсите ли инструмент за генериране на PHP код за класове, функции или цели файлове? -- Поддържа всички най-нови функции на PHP (като enums и др.) +- Поддържа всички най-нови функции на PHP (като кукички за свойства, енуми, атрибути и др.) - Позволява ви лесно да променяте съществуващи класове - Изход, съвместим със стила на кодиране PSR-12 / PER - Зряла, стабилна и широко използвана библиотека @@ -634,6 +634,88 @@ class Demo ``` +Куки за имоти .[#toc-property-hooks] +------------------------------------ + +Можете също така да дефинирате куки за свойства (представени от класа [PropertyHook |api:Nette\PhpGenerator\PropertyHook]) за операции get и set - функция, въведена в PHP 8.4: + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); +$prop = $class->addProperty('firstName') + ->setType('string'); + +$prop->addHook('set', 'strtolower($value)') + ->addParameter('value') + ->setType('string'); + +$prop->addHook('get') + ->setBody('return ucfirst($this->firstName);'); + +echo $class; +``` + +Това генерира: + +```php +class Demo +{ + public string $firstName { + set(string $value) => strtolower($value); + get { + return ucfirst($this->firstName); + } + } +} +``` + +Свойствата и куките за свойства могат да бъдат абстрактни или окончателни: + +```php +$class->addProperty('id') + ->setType('int') + ->addHook('get') + ->setAbstract(); + +$class->addProperty('role') + ->setType('string') + ->addHook('set', 'strtolower($value)') + ->setFinal(); +``` + + +Асиметрична видимост .[#toc-asymmetric-visibility] +-------------------------------------------------- + +В PHP 8.4 е въведена асиметрична видимост за свойствата. Можете да зададете различни нива на достъп за четене и писане. + +Видимостта може да бъде зададена или чрез метода `setVisibility()` с два параметъра, или чрез използване на `setPublic()`, `setProtected()` или `setPrivate()` с параметъра `mode`, който определя дали видимостта се отнася за получаване или задаване на свойството. Режимът по подразбиране е `'get'`. + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); + +$class->addProperty('name') + ->setType('string') + ->setVisibility('public', 'private'); // public for read, private for write + +$class->addProperty('id') + ->setType('int') + ->setProtected('set'); // protected for write + +echo $class; +``` + +По този начин се генерира: + +```php +class Demo +{ + public private(set) string $name; + + protected(set) int $id; +} +``` + + Пространство от имена .[#toc-namespace] --------------------------------------- @@ -867,10 +949,10 @@ $property = $manipulator->inheritProperty('foo'); $property->setValue('new value'); ``` -Методът `implementInterface()` автоматично имплементира всички методи от дадения интерфейс във вашия клас: +Методът `implement()` автоматично имплементира всички методи и свойства от дадения интерфейс или абстрактен клас: ```php -$manipulator->implementInterface(SomeInterface::class); +$manipulator->implement(SomeInterface::class); // Сега вашият клас имплементира SomeInterface и включва всички негови методи ``` @@ -892,6 +974,6 @@ echo $dumper->dump($var); // отпечатва ['a', 'b', 123] Таблица за съвместимост .[#toc-compatibility-table] --------------------------------------------------- -PhpGenerator 4.0 и 4.1 са съвместими с PHP 8.0 до 8.3 +PhpGenerator 4.1 е съвместим с PHP 8.0 до 8.4. {{leftbar: nette:@menu-topics}} diff --git a/php-generator/cs/@home.texy b/php-generator/cs/@home.texy index 241b06e39e..8c98156677 100644 --- a/php-generator/cs/@home.texy +++ b/php-generator/cs/@home.texy @@ -4,7 +4,7 @@ Generátor PHP kódu
Hledáte nástroj pro generování PHP kódu tříd, funkcí či kompletních souborů? -- Umí všechny nejnovější vychytávky v PHP (jako enumy atd.) +- Umí všechny nejnovější vychytávky v PHP (jako property hooks, enumy, atributy atd.) - Umožní vám snadno modifikovat existující třídy - Výstupní kód je v souladu s PSR-12 / PER coding style - Zralá, stabilní a široce používaná knihovna @@ -634,6 +634,88 @@ class Demo ``` +Property Hooks +-------------- + +Pomocí property hooks (reprezentované třídou [PropertyHook|api:Nette\PhpGenerator\PropertyHook]) můžete definovat operace get a set pro vlastnosti, což je funkce zavedená v PHP 8.4: + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); +$prop = $class->addProperty('firstName') + ->setType('string'); + +$prop->addHook('set', 'strtolower($value)') + ->addParameter('value') + ->setType('string'); + +$prop->addHook('get') + ->setBody('return ucfirst($this->firstName);'); + +echo $class; +``` + +Vygeneruje: + +```php +class Demo +{ + public string $firstName { + set(string $value) => strtolower($value); + get { + return ucfirst($this->firstName); + } + } +} +``` + +Property a property hooks mohou být abstraktní nebo finální: + +```php +$class->addProperty('id') + ->setType('int') + ->addHook('get') + ->setAbstract(); + +$class->addProperty('role') + ->setType('string') + ->addHook('set', 'strtolower($value)') + ->setFinal(); +``` + + +Asymetrická viditelnost +----------------------- + +PHP 8.4 zavádí asymetrickou viditelnost pro vlastnosti. Můžete nastavit různé úrovně přístupu pro čtení a zápis. + +Viditelnost lze nastavit buď pomocí metody `setVisibility()` se dvěma parametry, nebo pomocí `setPublic()`, `setProtected()` nebo `setPrivate()` s parametrem `mode`, který určuje, zda se viditelnost vztahuje ke čtení nebo zápisu vlastnosti. Výchozí režim je `'get'`. + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); + +$class->addProperty('name') + ->setType('string') + ->setVisibility('public', 'private'); // public pro čtení, private pro zápis + +$class->addProperty('id') + ->setType('int') + ->setProtected('set'); // protected pro zápis + +echo $class; +``` + +Vygeneruje: + +```php +class Demo +{ + public private(set) string $name; + + protected(set) int $id; +} +``` + + Jmenný prostor -------------- @@ -867,10 +949,10 @@ $property = $manipulator->inheritProperty('foo'); $property->setValue('new value'); ``` -Metoda `implementInterface()` automaticky implementuje všechny metody z daného rozhraní ve vaší třídě: +Metoda `implement()` automaticky implementuje všechny metody a vlastnosti z daného rozhraní nebo abstraktní třídy ve vaší třídě: ```php -$manipulator->implementInterface(SomeInterface::class); +$manipulator->implement(SomeInterface::class); // Nyní vaše třída implementuje SomeInterface a obsahuje všechny jeho metody ``` @@ -892,6 +974,6 @@ echo $dumper->dump($var); // vypíše ['a', 'b', 123] Tabulka kompatibility --------------------- -PhpGenerator 4.0 a 4.1 jsou kompatibilní s PHP 8.0 až 8.3. +PhpGenerator 4.1 je kompatibilní s PHP 8.0 až 8.4. {{leftbar: nette:@menu-topics}} diff --git a/php-generator/de/@home.texy b/php-generator/de/@home.texy index de0662647b..2af051777d 100644 --- a/php-generator/de/@home.texy +++ b/php-generator/de/@home.texy @@ -4,7 +4,7 @@ PHP-Code-Generator
Suchen Sie ein Tool, um PHP-Code für Klassen, Funktionen oder komplette Dateien zu generieren? -- Unterstützt alle aktuellen PHP-Funktionen (wie Enums, etc.) +- Unterstützt alle aktuellen PHP-Funktionen (wie Property Hooks, Enums, Attribute usw.) - Ermöglicht die einfache Änderung bestehender Klassen - Ausgabe in Übereinstimmung mit PSR-12 / PER-Kodierung - Ausgereifte, stabile und weit verbreitete Bibliothek @@ -634,6 +634,88 @@ class Demo ``` +Eigentumshaken .[#toc-property-hooks] +------------------------------------- + +Sie können auch Property Hooks (repräsentiert durch die Klasse [PropertyHook |api:Nette\PhpGenerator\PropertyHook]) für Get- und Set-Operationen definieren, eine Funktion, die in PHP 8.4 eingeführt wurde: + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); +$prop = $class->addProperty('firstName') + ->setType('string'); + +$prop->addHook('set', 'strtolower($value)') + ->addParameter('value') + ->setType('string'); + +$prop->addHook('get') + ->setBody('return ucfirst($this->firstName);'); + +echo $class; +``` + +Dies erzeugt: + +```php +class Demo +{ + public string $firstName { + set(string $value) => strtolower($value); + get { + return ucfirst($this->firstName); + } + } +} +``` + +Eigenschaften und Eigenschaftshaken können abstrakt oder endgültig sein: + +```php +$class->addProperty('id') + ->setType('int') + ->addHook('get') + ->setAbstract(); + +$class->addProperty('role') + ->setType('string') + ->addHook('set', 'strtolower($value)') + ->setFinal(); +``` + + +Asymmetrische Sichtbarkeit .[#toc-asymmetric-visibility] +-------------------------------------------------------- + +PHP 8.4 führt eine asymmetrische Sichtbarkeit für Eigenschaften ein. Sie können unterschiedliche Zugriffsebenen für das Lesen und Schreiben festlegen. + +Die Sichtbarkeit kann entweder mit der Methode `setVisibility()` mit zwei Parametern oder mit `setPublic()`, `setProtected()` oder `setPrivate()` mit dem Parameter `mode` eingestellt werden, der angibt, ob die Sichtbarkeit für das Abrufen oder Setzen der Eigenschaft gilt. Der Standardmodus ist `'get'`. + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); + +$class->addProperty('name') + ->setType('string') + ->setVisibility('public', 'private'); // public for read, private for write + +$class->addProperty('id') + ->setType('int') + ->setProtected('set'); // protected for write + +echo $class; +``` + +Dies erzeugt: + +```php +class Demo +{ + public private(set) string $name; + + protected(set) int $id; +} +``` + + Namensraum .[#toc-namespace] ---------------------------- @@ -867,10 +949,10 @@ $property = $manipulator->inheritProperty('foo'); $property->setValue('new value'); ``` -Die Methode `implementInterface()` implementiert automatisch alle Methoden der angegebenen Schnittstelle in Ihrer Klasse: +Die Methode `implement()` implementiert automatisch alle Methoden und Eigenschaften der angegebenen Schnittstelle oder abstrakten Klasse: ```php -$manipulator->implementInterface(SomeInterface::class); +$manipulator->implement(SomeInterface::class); // Ihre Klasse implementiert nun SomeInterface und enthält alle seine Methoden ``` @@ -892,6 +974,6 @@ echo $dumper->dump($var); // druckt ['a', 'b', 123] Kompatibilitätstabelle .[#toc-compatibility-table] -------------------------------------------------- -PhpGenerator 4.0 und 4.1 sind kompatibel mit PHP 8.0 bis 8.3 +PhpGenerator 4.1 ist kompatibel mit PHP 8.0 bis 8.4. {{leftbar: nette:@menu-topics}} diff --git a/php-generator/el/@home.texy b/php-generator/el/@home.texy index ca87244ab6..f20c5f2feb 100644 --- a/php-generator/el/@home.texy +++ b/php-generator/el/@home.texy @@ -4,7 +4,7 @@
Ψάχνετε ένα εργαλείο για τη δημιουργία κώδικα PHP για κλάσεις, συναρτήσεις ή πλήρη αρχεία; -- Υποστηρίζει όλα τα τελευταία χαρακτηριστικά της PHP (όπως enums κ.λπ.) +- Υποστηρίζει όλα τα τελευταία χαρακτηριστικά της PHP (όπως αγκίστρια ιδιοτήτων, enums, attributes, κ.λπ.) - Σας επιτρέπει να τροποποιείτε εύκολα τις υπάρχουσες κλάσεις - Έξοδος συμβατή με το στυλ κωδικοποίησης PSR-12 / PER - Ώριμη, σταθερή και ευρέως χρησιμοποιούμενη βιβλιοθήκη @@ -634,6 +634,88 @@ class Demo ``` +Άγκιστρα ιδιοκτησίας .[#toc-property-hooks] +------------------------------------------- + +Μπορείτε επίσης να ορίσετε άγκιστρα ιδιοτήτων (που αντιπροσωπεύονται από την κλάση [PropertyHook |api:Nette\PhpGenerator\PropertyHook]) για λειτουργίες get και set, ένα χαρακτηριστικό που εισήχθη στην PHP 8.4: + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); +$prop = $class->addProperty('firstName') + ->setType('string'); + +$prop->addHook('set', 'strtolower($value)') + ->addParameter('value') + ->setType('string'); + +$prop->addHook('get') + ->setBody('return ucfirst($this->firstName);'); + +echo $class; +``` + +Αυτό παράγει: + +```php +class Demo +{ + public string $firstName { + set(string $value) => strtolower($value); + get { + return ucfirst($this->firstName); + } + } +} +``` + +Ιδιότητες και άγκιστρα ιδιοτήτων μπορούν να είναι αφηρημένες ή τελικές: + +```php +$class->addProperty('id') + ->setType('int') + ->addHook('get') + ->setAbstract(); + +$class->addProperty('role') + ->setType('string') + ->addHook('set', 'strtolower($value)') + ->setFinal(); +``` + + +Ασύμμετρη ορατότητα .[#toc-asymmetric-visibility] +------------------------------------------------- + +Η PHP 8.4 εισάγει την ασύμμετρη ορατότητα για τις ιδιότητες. Μπορείτε να ορίσετε διαφορετικά επίπεδα πρόσβασης για ανάγνωση και εγγραφή. + +Η ορατότητα μπορεί να οριστεί είτε χρησιμοποιώντας τη μέθοδο `setVisibility()` με δύο παραμέτρους, είτε χρησιμοποιώντας τις μεθόδους `setPublic()`, `setProtected()` ή `setPrivate()` με την παράμετρο `mode` που καθορίζει αν η ορατότητα ισχύει για τη λήψη ή τη ρύθμιση της ιδιότητας. Η προεπιλεγμένη λειτουργία είναι η `'get'`. + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); + +$class->addProperty('name') + ->setType('string') + ->setVisibility('public', 'private'); // public for read, private for write + +$class->addProperty('id') + ->setType('int') + ->setProtected('set'); // protected for write + +echo $class; +``` + +Αυτό δημιουργεί: + +```php +class Demo +{ + public private(set) string $name; + + protected(set) int $id; +} +``` + + Χώρος ονομάτων .[#toc-namespace] -------------------------------- @@ -867,10 +949,10 @@ $property = $manipulator->inheritProperty('foo'); $property->setValue('new value'); ``` -Η μέθοδος `implementInterface()` υλοποιεί αυτόματα όλες τις μεθόδους της δεδομένης διεπαφής στην κλάση σας: +Η μέθοδος `implement()` υλοποιεί αυτόματα όλες τις μεθόδους και τις ιδιότητες της δεδομένης διεπαφής ή αφηρημένης κλάσης: ```php -$manipulator->implementInterface(SomeInterface::class); +$manipulator->implement(SomeInterface::class), // Τώρα η κλάση σας υλοποιεί το SomeInterface και περιλαμβάνει όλες τις μεθόδους του ``` @@ -892,6 +974,6 @@ echo $dumper->dump($var); // εκτυπώνει ['a', 'b', 123] Πίνακας συμβατότητας .[#toc-compatibility-table] ------------------------------------------------ -Οι εκδόσεις PhpGenerator 4.0 και 4.1 είναι συμβατές με την PHP 8.0 έως 8.3. +Το PhpGenerator 4.1 είναι συμβατό με την PHP 8.0 έως 8.4. {{leftbar: nette:@menu-topics}} diff --git a/php-generator/en/@home.texy b/php-generator/en/@home.texy index ccd879bf4a..31c48659c2 100644 --- a/php-generator/en/@home.texy +++ b/php-generator/en/@home.texy @@ -4,7 +4,7 @@ PHP Code Generator
Are you looking for a tool to generate PHP code for classes, functions, or complete files? -- Supports all the latest PHP features (like enums, etc.) +- Supports all the latest PHP features (like property hooks, enums, attributes, etc.) - Allows you to easily modify existing classes - Output compliant with PSR-12 / PER coding style - Mature, stable, and widely used library @@ -634,6 +634,88 @@ class Demo ``` +Property Hooks +-------------- + +You can also define property hooks (represented by the class [PropertyHook|api:Nette\PhpGenerator\PropertyHook]) for get and set operations, a feature introduced in PHP 8.4: + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); +$prop = $class->addProperty('firstName') + ->setType('string'); + +$prop->addHook('set', 'strtolower($value)') + ->addParameter('value') + ->setType('string'); + +$prop->addHook('get') + ->setBody('return ucfirst($this->firstName);'); + +echo $class; +``` + +This generates: + +```php +class Demo +{ + public string $firstName { + set(string $value) => strtolower($value); + get { + return ucfirst($this->firstName); + } + } +} +``` + +Properties and property hooks can be abstract or final: + +```php +$class->addProperty('id') + ->setType('int') + ->addHook('get') + ->setAbstract(); + +$class->addProperty('role') + ->setType('string') + ->addHook('set', 'strtolower($value)') + ->setFinal(); +``` + + +Asymmetric Visibility +--------------------- + +PHP 8.4 introduces asymmetric visibility for properties. You can set different access levels for reading and writing. + +The visibility can be set using either the `setVisibility()` method with two parameters, or by using `setPublic()`, `setProtected()`, or `setPrivate()` with the `mode` parameter that specifies whether the visibility applies to getting or setting the property. The default mode is `'get'`. + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); + +$class->addProperty('name') + ->setType('string') + ->setVisibility('public', 'private'); // public for read, private for write + +$class->addProperty('id') + ->setType('int') + ->setProtected('set'); // protected for write + +echo $class; +``` + +This generates: + +```php +class Demo +{ + public private(set) string $name; + + protected(set) int $id; +} +``` + + Namespace --------- @@ -867,10 +949,10 @@ $property = $manipulator->inheritProperty('foo'); $property->setValue('new value'); ``` -The `implementInterface()` method automatically implements all methods from the given interface in your class: +The `implement()` method automatically implements all methods and properties from the given interface or abstract class: ```php -$manipulator->implementInterface(SomeInterface::class); +$manipulator->implement(SomeInterface::class); // Now your class implements SomeInterface and includes all its methods ``` @@ -892,6 +974,6 @@ echo $dumper->dump($var); // outputs ['a', 'b', 123] Compatibility Table ------------------- -PhpGenerator 4.0 and 4.1 are compatible with PHP 8.0 to 8.3. +PhpGenerator 4.1 is compatible with PHP 8.0 to 8.4. {{leftbar: nette:@menu-topics}} diff --git a/php-generator/es/@home.texy b/php-generator/es/@home.texy index 0ee0eb3d70..9a9e8cc1cd 100644 --- a/php-generator/es/@home.texy +++ b/php-generator/es/@home.texy @@ -4,7 +4,7 @@ Generador de código PHP
¿Está buscando una herramienta para generar código PHP para clases, funciones o archivos completos? -- Soporta todas las últimas características de PHP (como enums, etc.) +- Soporta todas las últimas características de PHP (como ganchos de propiedades, enums, atributos, etc.) - Le permite modificar fácilmente las clases existentes - Salida conforme con el estilo de codificación PSR-12 / PER - Biblioteca madura, estable y ampliamente utilizada @@ -634,6 +634,88 @@ class Demo ``` +Ganchos para propiedades .[#toc-property-hooks] +----------------------------------------------- + +También puede definir ganchos de propiedad (representados por la clase [PropertyHook |api:Nette\PhpGenerator\PropertyHook]) para operaciones get y set, una característica introducida en PHP 8.4: + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); +$prop = $class->addProperty('firstName') + ->setType('string'); + +$prop->addHook('set', 'strtolower($value)') + ->addParameter('value') + ->setType('string'); + +$prop->addHook('get') + ->setBody('return ucfirst($this->firstName);'); + +echo $class; +``` + +Esto genera: + +```php +class Demo +{ + public string $firstName { + set(string $value) => strtolower($value); + get { + return ucfirst($this->firstName); + } + } +} +``` + +Las propiedades y los ganchos de propiedades pueden ser abstractos o finales: + +```php +$class->addProperty('id') + ->setType('int') + ->addHook('get') + ->setAbstract(); + +$class->addProperty('role') + ->setType('string') + ->addHook('set', 'strtolower($value)') + ->setFinal(); +``` + + +Visibilidad asimétrica .[#toc-asymmetric-visibility] +---------------------------------------------------- + +PHP 8.4 introduce visibilidad asimétrica para las propiedades. Puede establecer diferentes niveles de acceso para lectura y escritura. + +La visibilidad puede establecerse usando el método `setVisibility()` con dos parámetros, o usando `setPublic()`, `setProtected()`, o `setPrivate()` con el parámetro `mode` que especifica si la visibilidad se aplica a obtener o establecer la propiedad. El modo por defecto es `'get'`. + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); + +$class->addProperty('name') + ->setType('string') + ->setVisibility('public', 'private'); // public for read, private for write + +$class->addProperty('id') + ->setType('int') + ->setProtected('set'); // protected for write + +echo $class; +``` + +Esto genera: + +```php +class Demo +{ + public private(set) string $name; + + protected(set) int $id; +} +``` + + Espacio de nombres .[#toc-namespace] ------------------------------------ @@ -867,10 +949,10 @@ $property = $manipulator->inheritProperty('foo'); $property->setValue('new value'); ``` -El método `implementInterface()` implementa automáticamente todos los métodos de la interfaz dada en su clase: +El método `implement()` implementa automáticamente todos los métodos y propiedades de la interfaz o clase abstracta dada: ```php -$manipulator->implementInterface(SomeInterface::class); +$manipulador->implementar(CiertaInterfaz::clase); // Ahora tu clase implementa CiertaInterfaz e incluye todos sus métodos ``` @@ -892,6 +974,6 @@ echo $dumper->dump($var); // imprime ['a', 'b', 123] Tabla de compatibilidad .[#toc-compatibility-table] --------------------------------------------------- -PhpGenerator 4.0 y 4.1 son compatibles con PHP 8.0 a 8.3 +PhpGenerator 4.1 es compatible con PHP 8.0 a 8.4. {{leftbar: nette:@menu-topics}} diff --git a/php-generator/fr/@home.texy b/php-generator/fr/@home.texy index d0279a6c3a..9dc8e9c59e 100644 --- a/php-generator/fr/@home.texy +++ b/php-generator/fr/@home.texy @@ -4,7 +4,7 @@ Générateur de code PHP
Vous cherchez un outil pour générer du code PHP pour des classes, des fonctions ou des fichiers complets ? -- Supporte toutes les dernières fonctionnalités de PHP (comme les enums, etc.) +- Prend en charge toutes les dernières fonctionnalités de PHP (comme les crochets de propriété, les enums, les attributs, etc.) - Vous permet de modifier facilement les classes existantes - Sortie conforme au style de codage PSR-12 / PER - Bibliothèque mature, stable et largement utilisée @@ -634,6 +634,88 @@ class Demo ``` +Crochets de propriété .[#toc-property-hooks] +-------------------------------------------- + +Vous pouvez également définir des crochets de propriété (représentés par la classe [PropertyHook |api:Nette\PhpGenerator\PropertyHook]) pour les opérations get et set, une fonctionnalité introduite en PHP 8.4 : + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); +$prop = $class->addProperty('firstName') + ->setType('string'); + +$prop->addHook('set', 'strtolower($value)') + ->addParameter('value') + ->setType('string'); + +$prop->addHook('get') + ->setBody('return ucfirst($this->firstName);'); + +echo $class; +``` + +Ceci génère : + +```php +class Demo +{ + public string $firstName { + set(string $value) => strtolower($value); + get { + return ucfirst($this->firstName); + } + } +} +``` + +Les propriétés et les crochets de propriété peuvent être abstraits ou finaux : + +```php +$class->addProperty('id') + ->setType('int') + ->addHook('get') + ->setAbstract(); + +$class->addProperty('role') + ->setType('string') + ->addHook('set', 'strtolower($value)') + ->setFinal(); +``` + + +Visibilité asymétrique .[#toc-asymmetric-visibility] +---------------------------------------------------- + +PHP 8.4 introduit la visibilité asymétrique pour les propriétés. Vous pouvez définir des niveaux d'accès différents pour la lecture et l'écriture. + +La visibilité peut être définie en utilisant la méthode `setVisibility()` avec deux paramètres, ou en utilisant `setPublic()`, `setProtected()`, ou `setPrivate()` avec le paramètre `mode` qui spécifie si la visibilité s'applique à l'obtention ou à la définition de la propriété. Le mode par défaut est `'get'`. + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); + +$class->addProperty('name') + ->setType('string') + ->setVisibility('public', 'private'); // public for read, private for write + +$class->addProperty('id') + ->setType('int') + ->setProtected('set'); // protected for write + +echo $class; +``` + +Ceci génère : + +```php +class Demo +{ + public private(set) string $name; + + protected(set) int $id; +} +``` + + Espace de nommage .[#toc-namespace] ----------------------------------- @@ -867,10 +949,10 @@ $property = $manipulator->inheritProperty('foo'); $property->setValue('new value'); ``` -La méthode `implementInterface()` implémente automatiquement toutes les méthodes de l'interface donnée dans votre classe : +La méthode `implement()` implémente automatiquement toutes les méthodes et propriétés de l'interface ou de la classe abstraite donnée : ```php -$manipulator->implementInterface(SomeInterface::class); +$manipulator->implement(SomeInterface::class) ; // Maintenant, votre classe implémente SomeInterface et inclut toutes ses méthodes ``` @@ -892,6 +974,6 @@ echo $dumper->dump($var); // imprime ['a', 'b', 123] Tableau de compatibilité .[#toc-compatibility-table] ---------------------------------------------------- -PhpGenerator 4.0 et 4.1 sont compatibles avec PHP 8.0 à 8.3 +PhpGenerator 4.1 est compatible avec PHP 8.0 à 8.4. {{leftbar: nette:@menu-topics}} diff --git a/php-generator/hu/@home.texy b/php-generator/hu/@home.texy index cd1cc89d34..3d9430d344 100644 --- a/php-generator/hu/@home.texy +++ b/php-generator/hu/@home.texy @@ -4,7 +4,7 @@ PHP kód generátor
Olyan eszközt keres, amellyel PHP kódot generálhat osztályokhoz, függvényekhez vagy teljes fájlokhoz? -- Támogatja az összes legújabb PHP-funkciót (például enums stb.) +- Támogatja az összes legújabb PHP funkciót (mint például a property hooks, enums, attribútumok, stb.) - Lehetővé teszi a meglévő osztályok egyszerű módosítását - PSR-12 / PER kódolási stílusnak megfelelő kimenet - Kiforrott, stabil és széles körben használt könyvtár @@ -634,6 +634,88 @@ class Demo ``` +Ingatlan horgok .[#toc-property-hooks] +-------------------------------------- + +A PHP 8.4-ben bevezetett funkció, a [PropertyHook |api:Nette\PhpGenerator\PropertyHook] osztály által képviselt PropertyHook horgok is definiálhatók a get és set műveletekhez: + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); +$prop = $class->addProperty('firstName') + ->setType('string'); + +$prop->addHook('set', 'strtolower($value)') + ->addParameter('value') + ->setType('string'); + +$prop->addHook('get') + ->setBody('return ucfirst($this->firstName);'); + +echo $class; +``` + +Ez generálja: + +```php +class Demo +{ + public string $firstName { + set(string $value) => strtolower($value); + get { + return ucfirst($this->firstName); + } + } +} +``` + +Tulajdonságok és tulajdonsághorgok lehetnek absztraktak vagy véglegesek: + +```php +$class->addProperty('id') + ->setType('int') + ->addHook('get') + ->setAbstract(); + +$class->addProperty('role') + ->setType('string') + ->addHook('set', 'strtolower($value)') + ->setFinal(); +``` + + +Aszimmetrikus láthatóság .[#toc-asymmetric-visibility] +------------------------------------------------------ + +A PHP 8.4 bevezeti a tulajdonságok aszimmetrikus láthatóságát. Különböző hozzáférési szinteket állíthat be az olvasáshoz és az íráshoz. + +A láthatóságot vagy a `setVisibility()` metódussal lehet beállítani két paraméterrel, vagy a `setPublic()`, `setProtected()` vagy `setPrivate()` metódussal a `mode` paraméterrel, amely megadja, hogy a láthatóság a tulajdonság megszerzésére vagy beállítására vonatkozik-e a tulajdonság. Az alapértelmezett mód a `'get'`. + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); + +$class->addProperty('name') + ->setType('string') + ->setVisibility('public', 'private'); // public for read, private for write + +$class->addProperty('id') + ->setType('int') + ->setProtected('set'); // protected for write + +echo $class; +``` + +Ez generálja: + +```php +class Demo +{ + public private(set) string $name; + + protected(set) int $id; +} +``` + + Namespace .[#toc-namespace] --------------------------- @@ -867,10 +949,10 @@ $property = $manipulator->inheritProperty('foo'); $property->setValue('new value'); ``` -A `implementInterface()` metódus automatikusan megvalósítja az adott interfész összes metódusát az osztályodban: +A `implement()` módszer automatikusan megvalósítja az adott interfész vagy absztrakt osztály összes metódusát és tulajdonságát: ```php -$manipulator->implementInterface(SomeInterface::class); +$manipulator->implement(SomeInterface::class); // Most az osztályod megvalósítja a SomeInterface-t és tartalmazza annak összes metódusát. ``` @@ -892,6 +974,6 @@ echo $dumper->dump($var); // prints ['a', 'b', 123] Kompatibilitási táblázat .[#toc-compatibility-table] ---------------------------------------------------- -A PhpGenerator 4.0 és 4.1 kompatibilis a PHP 8.0 és 8.3 közötti változatokkal. +A PhpGenerator 4.1 kompatibilis a PHP 8.0 és 8.4 között. {{leftbar: nette:@menu-topics}} diff --git a/php-generator/it/@home.texy b/php-generator/it/@home.texy index 5d3c701cc1..3bc908b6d6 100644 --- a/php-generator/it/@home.texy +++ b/php-generator/it/@home.texy @@ -4,7 +4,7 @@ Generatore di codice PHP
State cercando uno strumento per generare codice PHP per classi, funzioni o file completi? -- Supporta tutte le più recenti caratteristiche di PHP (come gli enum, ecc.) +- Supporta tutte le più recenti caratteristiche di PHP (come gli agganci per le proprietà, gli enum, gli attributi e così via). - Permette di modificare facilmente le classi esistenti - Uscita conforme allo stile di codifica PSR-12 / PER - Libreria matura, stabile e ampiamente utilizzata @@ -634,6 +634,88 @@ class Demo ``` +Ganci di proprietà .[#toc-property-hooks] +----------------------------------------- + +È possibile definire anche degli hook di proprietà (rappresentati dalla classe [PropertyHook |api:Nette\PhpGenerator\PropertyHook]) per le operazioni di get e set, una caratteristica introdotta in PHP 8.4: + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); +$prop = $class->addProperty('firstName') + ->setType('string'); + +$prop->addHook('set', 'strtolower($value)') + ->addParameter('value') + ->setType('string'); + +$prop->addHook('get') + ->setBody('return ucfirst($this->firstName);'); + +echo $class; +``` + +Questo genera: + +```php +class Demo +{ + public string $firstName { + set(string $value) => strtolower($value); + get { + return ucfirst($this->firstName); + } + } +} +``` + +Le proprietà e i ganci di proprietà possono essere astratti o finali: + +```php +$class->addProperty('id') + ->setType('int') + ->addHook('get') + ->setAbstract(); + +$class->addProperty('role') + ->setType('string') + ->addHook('set', 'strtolower($value)') + ->setFinal(); +``` + + +Visibilità asimmetrica .[#toc-asymmetric-visibility] +---------------------------------------------------- + +PHP 8.4 introduce la visibilità asimmetrica per le proprietà. È possibile impostare diversi livelli di accesso per la lettura e la scrittura. + +La visibilità può essere impostata utilizzando il metodo `setVisibility()` con due parametri, oppure utilizzando `setPublic()`, `setProtected()`, o `setPrivate()` con il parametro `mode` che specifica se la visibilità si applica a ottenere o impostare la proprietà. La modalità predefinita è `'get'`. + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); + +$class->addProperty('name') + ->setType('string') + ->setVisibility('public', 'private'); // public for read, private for write + +$class->addProperty('id') + ->setType('int') + ->setProtected('set'); // protected for write + +echo $class; +``` + +Questo genera: + +```php +class Demo +{ + public private(set) string $name; + + protected(set) int $id; +} +``` + + Spazio dei nomi .[#toc-namespace] --------------------------------- @@ -867,10 +949,10 @@ $property = $manipulator->inheritProperty('foo'); $property->setValue('new value'); ``` -Il metodo `implementInterface()` implementa automaticamente tutti i metodi dell'interfaccia data nella vostra classe: +Il metodo `implement()` implementa automaticamente tutti i metodi e le proprietà dell'interfaccia o della classe astratta indicata: ```php -$manipulator->implementInterface(SomeInterface::class); +$manipolatore->implementa(SomeInterface::class); // Ora la classe implementa SomeInterface e include tutti i suoi metodi ``` @@ -892,6 +974,6 @@ echo $dumper->dump($var); // stampa ['a', 'b', 123]. Tabella di compatibilità .[#toc-compatibility-table] ---------------------------------------------------- -PhpGenerator 4.0 e 4.1 sono compatibili con PHP 8.0-8.3. +PhpGenerator 4.1 è compatibile con PHP 8.0 - 8.4. {{leftbar: nette:@menu-topics}} diff --git a/php-generator/ja/@home.texy b/php-generator/ja/@home.texy index 8468614408..e0d7043629 100644 --- a/php-generator/ja/@home.texy +++ b/php-generator/ja/@home.texy @@ -4,7 +4,7 @@ PHP コードジェネレータ
クラスや関数、ファイル全体のPHPコードを生成するツールをお探しですか? -- 最新の PHP 機能 (enum など) をすべてサポートしています。 +- PHPの最新機能(プロパティ・フック、列挙型、属性など)をすべてサポート。 - 既存のクラスを簡単に修正することが可能 - PSR-12 / PERコーディングスタイルに準拠した出力 - 成熟し、安定し、広く使用されているライブラリ @@ -634,6 +634,88 @@ class Demo ``` +プロパティ・フック.[#toc-property-hooks] +------------------------------- + +これは PHP 8.4 で導入された機能です: + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); +$prop = $class->addProperty('firstName') + ->setType('string'); + +$prop->addHook('set', 'strtolower($value)') + ->addParameter('value') + ->setType('string'); + +$prop->addHook('get') + ->setBody('return ucfirst($this->firstName);'); + +echo $class; +``` + +これは PHP 8.4 で導入された機能です: + +```php +class Demo +{ + public string $firstName { + set(string $value) => strtolower($value); + get { + return ucfirst($this->firstName); + } + } +} +``` + +プロパティとプロパティ・フックは、抽象でも最終でもかまいません: + +```php +$class->addProperty('id') + ->setType('int') + ->addHook('get') + ->setAbstract(); + +$class->addProperty('role') + ->setType('string') + ->addHook('set', 'strtolower($value)') + ->setFinal(); +``` + + +非対称の可視性.[#toc-asymmetric-visibility] +------------------------------------ + +PHP 8.4 では、プロパティに非対称な可視性が導入されました。読み書きで異なるアクセスレベルを設定することができます。 + +可視性を設定するには、`setVisibility()` メソッドに2つのパラメータを指定するか、`setPublic()`,`setProtected()`,`setPrivate()` のいずれかに`mode` パラメータを指定します。デフォルトのモードは`'get'` です。 + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); + +$class->addProperty('name') + ->setType('string') + ->setVisibility('public', 'private'); // public for read, private for write + +$class->addProperty('id') + ->setType('int') + ->setProtected('set'); // protected for write + +echo $class; +``` + +これは生成されます: + +```php +class Demo +{ + public private(set) string $name; + + protected(set) int $id; +} +``` + + 名前空間 .[#toc-namespace] ---------------------- @@ -867,10 +949,10 @@ $property = $manipulator->inheritProperty('foo'); $property->setValue('new value'); ``` -`implementInterface()` メソッドは、指定されたインターフェイスのすべてのメソッドを自動的にクラスに実装します: +`implement()` メソッドは、指定されたインターフェイスまたは抽象クラスのすべてのメソッドとプロパティを自動的に実装する: ```php -$manipulator->implementInterface(SomeInterface::class); +manipulator->implement(SomeInterface::class); // これで、あなたのクラスは SomeInterface を実装し、そのすべてのメソッドを含むようになった。 ``` @@ -892,6 +974,6 @@ echo $dumper->dump($var); // prints ['a', 'b', 123] 互換性テーブル .[#toc-compatibility-table] ----------------------------------- -PhpGenerator 4.0と4.1はPHP 8.0から8.3と互換性があります。 +PhpGenerator 4.1はPHP 8.0から8.4と互換性があります。 {{leftbar: nette:en:@menu-topics}} diff --git a/php-generator/pl/@home.texy b/php-generator/pl/@home.texy index 3f68976960..2ecf613c33 100644 --- a/php-generator/pl/@home.texy +++ b/php-generator/pl/@home.texy @@ -4,7 +4,7 @@ Generator kodu PHP
Szukasz narzędzia do generowania kodu PHP dla klas, funkcji lub całych plików? -- Obsługuje wszystkie najnowsze funkcje PHP (takie jak wyliczenia itp.) +- Obsługuje wszystkie najnowsze funkcje PHP (takie jak haki właściwości, enumy, atrybuty itp.). - Pozwala na łatwą modyfikację istniejących klas - Wyjście zgodne ze stylem kodowania PSR-12 / PER - Dojrzała, stabilna i szeroko stosowana biblioteka @@ -634,6 +634,88 @@ class Demo ``` +Haki nieruchomości .[#toc-property-hooks] +----------------------------------------- + +Można również definiować haki właściwości (reprezentowane przez klasę [PropertyHook |api:Nette\PhpGenerator\PropertyHook]) dla operacji pobierania i ustawiania, funkcja wprowadzona w PHP 8.4: + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); +$prop = $class->addProperty('firstName') + ->setType('string'); + +$prop->addHook('set', 'strtolower($value)') + ->addParameter('value') + ->setType('string'); + +$prop->addHook('get') + ->setBody('return ucfirst($this->firstName);'); + +echo $class; +``` + +To generuje: + +```php +class Demo +{ + public string $firstName { + set(string $value) => strtolower($value); + get { + return ucfirst($this->firstName); + } + } +} +``` + +Właściwości i haki właściwości mogą być abstrakcyjne lub końcowe: + +```php +$class->addProperty('id') + ->setType('int') + ->addHook('get') + ->setAbstract(); + +$class->addProperty('role') + ->setType('string') + ->addHook('set', 'strtolower($value)') + ->setFinal(); +``` + + +Asymetryczna widoczność .[#toc-asymmetric-visibility] +----------------------------------------------------- + +PHP 8.4 wprowadza asymetryczną widoczność właściwości. Można ustawić różne poziomy dostępu dla odczytu i zapisu. + +Widoczność można ustawić za pomocą metody `setVisibility()` z dwoma parametrami lub za pomocą `setPublic()`, `setProtected()`, lub `setPrivate()` z parametrem `mode`, który określa, czy widoczność dotyczy pobierania czy ustawiania właściwości. Domyślnym trybem jest `'get'`. + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); + +$class->addProperty('name') + ->setType('string') + ->setVisibility('public', 'private'); // public for read, private for write + +$class->addProperty('id') + ->setType('int') + ->setProtected('set'); // protected for write + +echo $class; +``` + +To generuje: + +```php +class Demo +{ + public private(set) string $name; + + protected(set) int $id; +} +``` + + Przestrzeń nazw .[#toc-namespace] --------------------------------- @@ -867,10 +949,10 @@ $property = $manipulator->inheritProperty('foo'); $property->setValue('new value'); ``` -Metoda `implementInterface()` automatycznie implementuje wszystkie metody z danego interfejsu w klasie: +Metoda `implement()` automatycznie implementuje wszystkie metody i właściwości z danego interfejsu lub klasy abstrakcyjnej: ```php -$manipulator->implementInterface(SomeInterface::class); +$manipulator->implement(SomeInterface::class); // Teraz twoja klasa implementuje interfejs SomeInterface i zawiera wszystkie jego metody ``` @@ -892,6 +974,6 @@ echo $dumper->dump($var); // drukuje ['a', 'b', 123] Tabela kompatybilności .[#toc-compatibility-table] -------------------------------------------------- -PhpGenerator 4.0 i 4.1 są kompatybilne z PHP 8.0 do 8.3. +PhpGenerator 4.1 jest kompatybilny z PHP 8.0 do 8.4. {{leftbar: nette:@menu-topics}} diff --git a/php-generator/pt/@home.texy b/php-generator/pt/@home.texy index 3e797093a6..e0816507de 100644 --- a/php-generator/pt/@home.texy +++ b/php-generator/pt/@home.texy @@ -4,7 +4,7 @@ Gerador de código PHP
Você está procurando uma ferramenta para gerar código PHP para classes, funções ou arquivos completos? -- Oferece suporte a todos os recursos mais recentes do PHP (como enums, etc.) +- Oferece suporte a todos os recursos mais recentes do PHP (como ganchos de propriedade, enums, atributos, etc.) - Permite modificar facilmente as classes existentes - Saída compatível com o estilo de codificação PSR-12 / PER - Biblioteca madura, estável e amplamente utilizada @@ -634,6 +634,88 @@ class Demo ``` +Ganchos de propriedade .[#toc-property-hooks] +--------------------------------------------- + +Você também pode definir ganchos de propriedade (representados pela classe [PropertyHook |api:Nette\PhpGenerator\PropertyHook]) para operações get e set, um recurso introduzido no PHP 8.4: + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); +$prop = $class->addProperty('firstName') + ->setType('string'); + +$prop->addHook('set', 'strtolower($value)') + ->addParameter('value') + ->setType('string'); + +$prop->addHook('get') + ->setBody('return ucfirst($this->firstName);'); + +echo $class; +``` + +Isso gera: + +```php +class Demo +{ + public string $firstName { + set(string $value) => strtolower($value); + get { + return ucfirst($this->firstName); + } + } +} +``` + +As propriedades e os ganchos de propriedade podem ser abstratos ou finais: + +```php +$class->addProperty('id') + ->setType('int') + ->addHook('get') + ->setAbstract(); + +$class->addProperty('role') + ->setType('string') + ->addHook('set', 'strtolower($value)') + ->setFinal(); +``` + + +Visibilidade assimétrica .[#toc-asymmetric-visibility] +------------------------------------------------------ + +O PHP 8.4 introduz a visibilidade assimétrica para propriedades. Você pode definir diferentes níveis de acesso para leitura e gravação. + +A visibilidade pode ser definida usando o método `setVisibility()` com dois parâmetros ou usando `setPublic()`, `setProtected()`, ou `setPrivate()` com o parâmetro `mode` que especifica se a visibilidade se aplica à obtenção ou à definição da propriedade. O modo padrão é `'get'`. + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); + +$class->addProperty('name') + ->setType('string') + ->setVisibility('public', 'private'); // public for read, private for write + +$class->addProperty('id') + ->setType('int') + ->setProtected('set'); // protected for write + +echo $class; +``` + +Isso gera: + +```php +class Demo +{ + public private(set) string $name; + + protected(set) int $id; +} +``` + + Namespace .[#toc-namespace] --------------------------- @@ -867,10 +949,10 @@ $property = $manipulator->inheritProperty('foo'); $property->setValue('new value'); ``` -O método `implementInterface()` implementa automaticamente todos os métodos da interface fornecida em sua classe: +O método `implement()` implementa automaticamente todos os métodos e propriedades da interface ou classe abstrata fornecida: ```php -$manipulator->implementInterface(SomeInterface::class); +$manipulator->implement(SomeInterface::class); // Agora sua classe implementa SomeInterface e inclui todos os seus métodos ``` @@ -892,6 +974,6 @@ echo $dumper->dump($var); // gravuras ['a', 'b', 123] Tabela de Compatibilidade .[#toc-compatibility-table] ----------------------------------------------------- -O PhpGenerator 4.0 e 4.1 são compatíveis com o PHP 8.0 a 8.3 +O PhpGenerator 4.1 é compatível com o PHP 8.0 a 8.4. {{leftbar: nette:@menu-topics}} diff --git a/php-generator/ro/@home.texy b/php-generator/ro/@home.texy index edc02152f3..a5f9a64564 100644 --- a/php-generator/ro/@home.texy +++ b/php-generator/ro/@home.texy @@ -4,7 +4,7 @@ Generator de coduri PHP
Sunteți în căutarea unui instrument pentru a genera cod PHP pentru clase, funcții sau fișiere complete? -- Suportă toate cele mai recente caracteristici PHP (cum ar fi enums etc.) +- Suportă toate cele mai recente caracteristici PHP (cum ar fi cârligele de proprietate, enumurile, atributele etc.) - Vă permite să modificați cu ușurință clasele existente - Ieșire conformă cu stilul de codare PSR-12 / PER - Bibliotecă matură, stabilă și utilizată pe scară largă @@ -634,6 +634,88 @@ class Demo ``` +Cârlige de proprietate .[#toc-property-hooks] +--------------------------------------------- + +De asemenea, puteți defini cârlige de proprietate (reprezentate de clasa [PropertyHook |api:Nette\PhpGenerator\PropertyHook]) pentru operațiile get și set, o caracteristică introdusă în PHP 8.4: + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); +$prop = $class->addProperty('firstName') + ->setType('string'); + +$prop->addHook('set', 'strtolower($value)') + ->addParameter('value') + ->setType('string'); + +$prop->addHook('get') + ->setBody('return ucfirst($this->firstName);'); + +echo $class; +``` + +Aceasta generează: + +```php +class Demo +{ + public string $firstName { + set(string $value) => strtolower($value); + get { + return ucfirst($this->firstName); + } + } +} +``` + +Proprietățile și cârligele de proprietate pot fi abstracte sau finale: + +```php +$class->addProperty('id') + ->setType('int') + ->addHook('get') + ->setAbstract(); + +$class->addProperty('role') + ->setType('string') + ->addHook('set', 'strtolower($value)') + ->setFinal(); +``` + + +Vizibilitate asimetrică .[#toc-asymmetric-visibility] +----------------------------------------------------- + +PHP 8.4 introduce vizibilitatea asimetrică pentru proprietăți. Puteți seta niveluri de acces diferite pentru citire și scriere. + +Vizibilitatea poate fi setată folosind fie metoda `setVisibility()` cu doi parametri, fie folosind `setPublic()`, `setProtected()`, sau `setPrivate()` cu parametrul `mode` care specifică dacă vizibilitatea se aplică la obținerea sau setarea proprietății. Modul implicit este `'get'`. + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); + +$class->addProperty('name') + ->setType('string') + ->setVisibility('public', 'private'); // public for read, private for write + +$class->addProperty('id') + ->setType('int') + ->setProtected('set'); // protected for write + +echo $class; +``` + +Acest lucru generează: + +```php +class Demo +{ + public private(set) string $name; + + protected(set) int $id; +} +``` + + Spațiul de nume .[#toc-namespace] --------------------------------- @@ -867,10 +949,10 @@ $property = $manipulator->inheritProperty('foo'); $property->setValue('new value'); ``` -Metoda `implementInterface()` implementează automat toate metodele interfeței date în clasa dumneavoastră: +Metoda `implement()` implementează automat toate metodele și proprietățile din interfața sau clasa abstractă dată: ```php -$manipulator->implementInterface(SomeInterface::class); +$manipulator->implement(SomeInterface::class); // Acum clasa dvs. implementează SomeInterface și include toate metodele acesteia ``` @@ -892,6 +974,6 @@ echo $dumper->dump($var); // prints ['a', 'b', 123] Tabel de compatibilitate .[#toc-compatibility-table] ---------------------------------------------------- -PhpGenerator 4.0 și 4.1 sunt compatibile cu PHP 8.0 până la 8.3 +PhpGenerator 4.1 este compatibil cu PHP 8.0 până la 8.4. {{leftbar: nette:@menu-topics}} diff --git a/php-generator/ru/@home.texy b/php-generator/ru/@home.texy index dc328ce15a..19633d8644 100644 --- a/php-generator/ru/@home.texy +++ b/php-generator/ru/@home.texy @@ -4,7 +4,7 @@
Вы ищете инструмент для генерации PHP-кода для классов, функций или целых файлов? -- Поддерживает все новейшие возможности PHP (такие как перечисления и т.д.) +- Поддерживает все новейшие возможности PHP (такие как крючки свойств, перечисления, атрибуты и т.д.). - Позволяет легко модифицировать существующие классы - Выходные данные соответствуют стилю кодирования PSR-12 / PER - Зрелая, стабильная и широко используемая библиотека @@ -634,6 +634,88 @@ class Demo ``` +Крючки для недвижимости .[#toc-property-hooks] +---------------------------------------------- + +Вы также можете определить крючки свойств (представленные классом [PropertyHook |api:Nette\PhpGenerator\PropertyHook]) для операций get и set. Эта возможность появилась в PHP 8.4: + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); +$prop = $class->addProperty('firstName') + ->setType('string'); + +$prop->addHook('set', 'strtolower($value)') + ->addParameter('value') + ->setType('string'); + +$prop->addHook('get') + ->setBody('return ucfirst($this->firstName);'); + +echo $class; +``` + +Это генерирует: + +```php +class Demo +{ + public string $firstName { + set(string $value) => strtolower($value); + get { + return ucfirst($this->firstName); + } + } +} +``` + +Свойства и крючки свойств могут быть абстрактными или конечными: + +```php +$class->addProperty('id') + ->setType('int') + ->addHook('get') + ->setAbstract(); + +$class->addProperty('role') + ->setType('string') + ->addHook('set', 'strtolower($value)') + ->setFinal(); +``` + + +Асимметричная видимость .[#toc-asymmetric-visibility] +----------------------------------------------------- + +В PHP 8.4 появилась асимметричная видимость свойств. Вы можете установить разные уровни доступа для чтения и записи. + +Видимость можно установить либо с помощью метода `setVisibility()` с двумя параметрами, либо с помощью `setPublic()`, `setProtected()`, или `setPrivate()` с параметром `mode`, который указывает, применяется ли видимость к получению или установке свойства. По умолчанию используется метод `'get'`. + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); + +$class->addProperty('name') + ->setType('string') + ->setVisibility('public', 'private'); // public for read, private for write + +$class->addProperty('id') + ->setType('int') + ->setProtected('set'); // protected for write + +echo $class; +``` + +При этом генерируются: + +```php +class Demo +{ + public private(set) string $name; + + protected(set) int $id; +} +``` + + Пространство имен .[#toc-namespace] ----------------------------------- @@ -867,10 +949,10 @@ $property = $manipulator->inheritProperty('foo'); $property->setValue('new value'); ``` -Метод `implementInterface()` автоматически реализует в вашем классе все методы из заданного интерфейса: +Метод `implement()` автоматически реализует все методы и свойства заданного интерфейса или абстрактного класса: ```php -$manipulator->implementInterface(SomeInterface::class); +$manipulator->implement(SomeInterface::class); // Теперь ваш класс реализует SomeInterface и включает все его методы ``` @@ -892,6 +974,6 @@ echo $dumper->dump($var); // печатает ['a', 'b', 123] Таблица совместимости .[#toc-compatibility-table] ------------------------------------------------- -PhpGenerator 4.0 и 4.1 совместим с PHP 8.0 - 8.3 +PhpGenerator 4.1 совместим с PHP 8.0 - 8.4. {{leftbar: nette:@menu-topics}} diff --git a/php-generator/sl/@home.texy b/php-generator/sl/@home.texy index 015e74f7bd..18c6871ec5 100644 --- a/php-generator/sl/@home.texy +++ b/php-generator/sl/@home.texy @@ -4,7 +4,7 @@ Generator kode PHP
Iščete orodje za ustvarjanje kode PHP za razrede, funkcije ali celotne datoteke? -- Podpira vse najnovejše funkcije PHP (kot so enumi itd.) +- Podpira vse najnovejše funkcije PHP (kot so kavlji za lastnosti, enumi, atributi itd.) - Omogoča enostavno spreminjanje obstoječih razredov - Izhod je skladen s slogom kodiranja PSR-12 / PER - Zrela, stabilna in široko uporabljena knjižnica @@ -634,6 +634,88 @@ class Demo ``` +Kljuke za lastnino .[#toc-property-hooks] +----------------------------------------- + +Opredelite lahko tudi lastnostne kljuke (ki jih predstavlja razred [PropertyHook |api:Nette\PhpGenerator\PropertyHook]) za operacije get in set, kar je funkcija, uvedena v PHP 8.4: + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); +$prop = $class->addProperty('firstName') + ->setType('string'); + +$prop->addHook('set', 'strtolower($value)') + ->addParameter('value') + ->setType('string'); + +$prop->addHook('get') + ->setBody('return ucfirst($this->firstName);'); + +echo $class; +``` + +To generira: + +```php +class Demo +{ + public string $firstName { + set(string $value) => strtolower($value); + get { + return ucfirst($this->firstName); + } + } +} +``` + +Lastnosti in kavlji so lahko abstraktni ali končni: + +```php +$class->addProperty('id') + ->setType('int') + ->addHook('get') + ->setAbstract(); + +$class->addProperty('role') + ->setType('string') + ->addHook('set', 'strtolower($value)') + ->setFinal(); +``` + + +Asimetrična vidljivost .[#toc-asymmetric-visibility] +---------------------------------------------------- + +PHP 8.4 uvaja asimetrično vidnost lastnosti. Nastavite lahko različne ravni dostopa za branje in pisanje. + +Vidnost lahko nastavite z metodo `setVisibility()` z dvema parametroma ali z uporabo metod `setPublic()`, `setProtected()` ali `setPrivate()` s parametrom `mode`, ki določa, ali vidnost velja za pridobivanje ali nastavljanje lastnosti. Privzet način je `'get'`. + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); + +$class->addProperty('name') + ->setType('string') + ->setVisibility('public', 'private'); // public for read, private for write + +$class->addProperty('id') + ->setType('int') + ->setProtected('set'); // protected for write + +echo $class; +``` + +Pri tem se ustvari: + +```php +class Demo +{ + public private(set) string $name; + + protected(set) int $id; +} +``` + + Imenski prostor .[#toc-namespace] --------------------------------- @@ -867,10 +949,10 @@ $property = $manipulator->inheritProperty('foo'); $property->setValue('new value'); ``` -Metoda `implementInterface()` samodejno implementira vse metode iz danega vmesnika v vaš razred: +Metoda `implement()` samodejno implementira vse metode in lastnosti danega vmesnika ali abstraktnega razreda: ```php -$manipulator->implementInterface(SomeInterface::class); +$manipulator->implement(SomeInterface::class); // Zdaj vaš razred implementira SomeInterface in vključuje vse njegove metode ``` @@ -892,6 +974,6 @@ echo $dumper->dump($var); // natisne ['a', 'b', 123] Preglednica združljivosti .[#toc-compatibility-table] ----------------------------------------------------- -PhpGenerator 4.0 in 4.1 sta združljiva s PHP 8.0 do 8.3 +PhpGenerator 4.1 je združljiv s PHP 8.0 do 8.4. {{leftbar: nette:@menu-topics}} diff --git a/php-generator/tr/@home.texy b/php-generator/tr/@home.texy index 6d27983caf..de83484c59 100644 --- a/php-generator/tr/@home.texy +++ b/php-generator/tr/@home.texy @@ -4,7 +4,7 @@ PHP Kod Oluşturucu
Sınıflar, fonksiyonlar veya tüm dosyalar için PHP kodu üretecek bir araç mı arıyorsunuz? -- En son PHP özelliklerini destekler (enumlar vb. gibi) +- En yeni PHP özelliklerini destekler (özellik kancaları, enumlar, nitelikler vb. gibi) - Mevcut sınıfları kolayca değiştirmenizi sağlar - PSR-12 / PER kodlama stili ile uyumlu çıkış - Olgun, kararlı ve yaygın olarak kullanılan kütüphane @@ -634,6 +634,88 @@ class Demo ``` +Mülkiyet Kancaları .[#toc-property-hooks] +----------------------------------------- + +Ayrıca, PHP 8.4'te tanıtılan bir özellik olan get ve set işlemleri için özellik kancaları ( [PropertyHook |api:Nette\PhpGenerator\PropertyHook] sınıfı ile temsil edilir) tanımlayabilirsiniz: + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); +$prop = $class->addProperty('firstName') + ->setType('string'); + +$prop->addHook('set', 'strtolower($value)') + ->addParameter('value') + ->setType('string'); + +$prop->addHook('get') + ->setBody('return ucfirst($this->firstName);'); + +echo $class; +``` + +Bu üretir: + +```php +class Demo +{ + public string $firstName { + set(string $value) => strtolower($value); + get { + return ucfirst($this->firstName); + } + } +} +``` + +Özellikler ve özellik kancaları soyut veya nihai olabilir: + +```php +$class->addProperty('id') + ->setType('int') + ->addHook('get') + ->setAbstract(); + +$class->addProperty('role') + ->setType('string') + ->addHook('set', 'strtolower($value)') + ->setFinal(); +``` + + +Asimetrik Görünürlük .[#toc-asymmetric-visibility] +-------------------------------------------------- + +PHP 8.4 özellikler için asimetrik görünürlük sunar. Okuma ve yazma için farklı erişim seviyeleri ayarlayabilirsiniz. + +Görünürlük, iki parametreli `setVisibility()` yöntemi kullanılarak veya görünürlüğün özelliği almak veya ayarlamak için geçerli olup olmadığını belirten `mode` parametresiyle birlikte `setPublic()`, `setProtected()` veya `setPrivate()` kullanılarak ayarlanabilir. Varsayılan mod `'get'` şeklindedir. + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); + +$class->addProperty('name') + ->setType('string') + ->setVisibility('public', 'private'); // public for read, private for write + +$class->addProperty('id') + ->setType('int') + ->setProtected('set'); // protected for write + +echo $class; +``` + +Bu üretir: + +```php +class Demo +{ + public private(set) string $name; + + protected(set) int $id; +} +``` + + İsim Alanı .[#toc-namespace] ---------------------------- @@ -867,10 +949,10 @@ $property = $manipulator->inheritProperty('foo'); $property->setValue('new value'); ``` - `implementInterface()` yöntemi, sınıfınızda verilen arayüzdeki tüm yöntemleri otomatik olarak uygular: +`implement()` yöntemi, verilen arayüz veya soyut sınıftaki tüm yöntem ve özellikleri otomatik olarak uygular: ```php -$manipulator->implementInterface(SomeInterface::class); +$manipulator->implement(SomeInterface::class); // Şimdi sınıfınız SomeInterface'i uyguluyor ve tüm yöntemlerini içeriyor ``` @@ -892,6 +974,6 @@ echo $dumper->dump($var); // prints ['a', 'b', 123] Uyumluluk Tablosu .[#toc-compatibility-table] --------------------------------------------- -PhpGenerator 4.0 ve 4.1 PHP 8.0 ila 8.3 ile uyumludur +PhpGenerator 4.1 PHP 8.0 ila 8.4 ile uyumludur. {{leftbar: nette:@menu-topics}} diff --git a/php-generator/uk/@home.texy b/php-generator/uk/@home.texy index 3a6c88f616..345772c711 100644 --- a/php-generator/uk/@home.texy +++ b/php-generator/uk/@home.texy @@ -4,7 +4,7 @@
Ви шукаєте інструмент для генерації PHP-коду для класів, функцій або цілих файлів? -- Підтримує всі найновіші можливості PHP (наприклад, перерахування тощо). +- Підтримує всі найновіші можливості PHP (наприклад, хуки властивостей, зчислення, атрибути тощо). - Дозволяє легко модифікувати існуючі класи - Вихід, сумісний зі стилем кодування PSR-12 / PER - Зріла, стабільна та широко використовувана бібліотека @@ -634,6 +634,88 @@ class Demo ``` +Хуки властивостей .[#toc-property-hooks] +---------------------------------------- + +Ви також можете визначати хуки властивостей (представлені класом [PropertyHook |api:Nette\PhpGenerator\PropertyHook]) для операцій get і set - ця функція з'явилася в PHP 8.4: + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); +$prop = $class->addProperty('firstName') + ->setType('string'); + +$prop->addHook('set', 'strtolower($value)') + ->addParameter('value') + ->setType('string'); + +$prop->addHook('get') + ->setBody('return ucfirst($this->firstName);'); + +echo $class; +``` + +Це генерує: + +```php +class Demo +{ + public string $firstName { + set(string $value) => strtolower($value); + get { + return ucfirst($this->firstName); + } + } +} +``` + +Властивості та хуки властивостей можуть бути абстрактними або кінцевими: + +```php +$class->addProperty('id') + ->setType('int') + ->addHook('get') + ->setAbstract(); + +$class->addProperty('role') + ->setType('string') + ->addHook('set', 'strtolower($value)') + ->setFinal(); +``` + + +Асиметрична видимість .[#toc-asymmetric-visibility] +--------------------------------------------------- + +У PHP 8.4 введено асиметричну видимість властивостей. Ви можете встановити різні рівні доступу для читання і запису. + +Видимість можна встановити або за допомогою методу `setVisibility()` з двома параметрами, або за допомогою `setPublic()`, `setProtected()`, або `setPrivate()` з параметром `mode`, який вказує, чи застосовується видимість до отримання або встановлення властивості. За замовчуванням використовується режим `'get'`. + +```php +$class = new Nette\PhpGenerator\ClassType('Demo'); + +$class->addProperty('name') + ->setType('string') + ->setVisibility('public', 'private'); // public for read, private for write + +$class->addProperty('id') + ->setType('int') + ->setProtected('set'); // protected for write + +echo $class; +``` + +Це генерує + +```php +class Demo +{ + public private(set) string $name; + + protected(set) int $id; +} +``` + + Простір імен .[#toc-namespace] ------------------------------ @@ -867,10 +949,10 @@ $property = $manipulator->inheritProperty('foo'); $property->setValue('new value'); ``` -Метод `implementInterface()` автоматично реалізує всі методи з даного інтерфейсу у вашому класі: +Метод `implement()` автоматично реалізує всі методи і властивості з даного інтерфейсу або абстрактного класу: ```php -$manipulator->implementInterface(SomeInterface::class); +$manipulator->implement(SomeInterface::class); // Тепер ваш клас реалізує SomeInterface і включає всі його методи ``` @@ -892,6 +974,6 @@ echo $dumper->dump($var); // prints ['a', 'b', 123] Таблиця сумісності .[#toc-compatibility-table] ---------------------------------------------- -PhpGenerator 4.0 і 4.1 сумісні з PHP 8.0 до 8.3 +PhpGenerator 4.1 сумісний з версіями PHP від 8.0 до 8.4. {{leftbar: nette:@menu-topics}} From d3c86fba77e44def5ac3e5c6fbf8cacf6d77a812 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Sat, 30 Nov 2024 00:57:01 +0100 Subject: [PATCH 4/5] improved info about production/development mode --- application/bg/bootstrap.texy | 20 ++++++++++++++++++-- application/cs/bootstrap.texy | 20 ++++++++++++++++++-- application/de/bootstrap.texy | 20 ++++++++++++++++++-- application/el/bootstrap.texy | 20 ++++++++++++++++++-- application/en/bootstrap.texy | 20 ++++++++++++++++++-- application/es/bootstrap.texy | 20 ++++++++++++++++++-- application/fr/bootstrap.texy | 20 ++++++++++++++++++-- application/hu/bootstrap.texy | 20 ++++++++++++++++++-- application/it/bootstrap.texy | 20 ++++++++++++++++++-- application/pl/bootstrap.texy | 20 ++++++++++++++++++-- application/pt/bootstrap.texy | 20 ++++++++++++++++++-- application/ro/bootstrap.texy | 20 ++++++++++++++++++-- application/ru/bootstrap.texy | 20 ++++++++++++++++++-- application/sl/bootstrap.texy | 20 ++++++++++++++++++-- application/tr/bootstrap.texy | 20 ++++++++++++++++++-- application/uk/bootstrap.texy | 20 ++++++++++++++++++-- nette/bg/troubleshooting.texy | 11 +++++++++++ nette/cs/troubleshooting.texy | 11 +++++++++++ nette/de/troubleshooting.texy | 11 +++++++++++ nette/el/troubleshooting.texy | 11 +++++++++++ nette/en/troubleshooting.texy | 11 +++++++++++ nette/es/troubleshooting.texy | 11 +++++++++++ nette/fr/troubleshooting.texy | 11 +++++++++++ nette/hu/troubleshooting.texy | 11 +++++++++++ nette/it/troubleshooting.texy | 11 +++++++++++ nette/pl/troubleshooting.texy | 11 +++++++++++ nette/pt/troubleshooting.texy | 11 +++++++++++ nette/ro/troubleshooting.texy | 11 +++++++++++ nette/ru/troubleshooting.texy | 11 +++++++++++ nette/sl/troubleshooting.texy | 11 +++++++++++ nette/tr/troubleshooting.texy | 11 +++++++++++ nette/uk/troubleshooting.texy | 11 +++++++++++ 32 files changed, 464 insertions(+), 32 deletions(-) diff --git a/application/bg/bootstrap.texy b/application/bg/bootstrap.texy index 2ac3dc2e99..8766be6fd7 100644 --- a/application/bg/bootstrap.texy +++ b/application/bg/bootstrap.texy @@ -84,9 +84,25 @@ $application->run(); Режим на разработка и производствен режим .[#toc-development-vs-production-mode] ================================================================================ -Nette прави разграничение между два основни режима, в които се изпълнява заявката: разработка и производство. Режимът за разработка е насочен към максимално удобство за програмиста, показва се Tracy, кешът се обновява автоматично при промяна на шаблоните или конфигурацията на DI контейнера и т.н. Производственият режим е ориентиран към производителността, Tracy регистрира само грешки, а промените в шаблоните и другите файлове не се проверяват. +Nette се държи по различен начин в зависимост от това дали работи на сървър за разработка или на производствен сървър: -Режимът се избира чрез автоматично разпознаване, така че обикновено не е необходимо да конфигурирате или превключвате нещо ръчно. Режимът за разработка се използва, ако приложението се изпълнява на локален хост (т.е. IP адресът е `127.0.0.1` или `::1`) и няма прокси сървър (т.е. HTTP заглавието му). В противен случай приложението работи в производствен режим. +🛠️ Режим на разработка: + - Показва лентата за отстраняване на грешки на Tracy с полезна информация (напр. SQL заявки, време за изпълнение, използване на памет). + - Показва подробна страница за грешки с проследяване на извикването на функциите и съдържанието на променливите, когато възникне грешка. + - Автоматично опреснява кеша, когато се променят шаблони на Latte, конфигурационни файлове и др. + + +🚀 Производствен режим: + - Не показва никаква информация за отстраняване на грешки; всички грешки се записват в дневника. + - Показва `ErrorPresenter` или обща страница "Server Error" (Грешка на сървъра), когато възникне грешка. + - Кешът никога не се опреснява автоматично! + - Оптимизиран за скорост и сигурност. + + +Режимът се определя автоматично, така че в повечето случаи не е необходимо да го конфигурирате или превключвате ръчно: + +- Режим на разработка: (IP адрес `127.0.0.1` или `::1`), освен ако не се използва прокси сървър (т.е. въз основа на неговите HTTP заглавия). +- Производствен режим: Активен навсякъде другаде. Ако искате да активирате режима за разработка в други случаи, например за програмисти, които имат достъп от определен IP адрес, можете да използвате `setDebugMode()`: diff --git a/application/cs/bootstrap.texy b/application/cs/bootstrap.texy index 6357fe0d4d..19369531d6 100644 --- a/application/cs/bootstrap.texy +++ b/application/cs/bootstrap.texy @@ -84,9 +84,25 @@ Jak vidno, s nastavením prostředí a vytvořením dependency injection (DI) ko Vývojářský vs produkční režim ============================= -Nette rozlišuje dva základní režimy, ve kterých se požadavek vykoná: vývojářský a produkční. Vývojářský je zaměřen na maximální pohodlí programátora, zobrazuje se Tracy, automaticky se aktualizuje cache při změně šablon nebo konfigurace DI kontejneru, atd. Produkční je zaměřený na výkon a ostré nasazení, Tracy chyby pouze loguje a změny šablon a dalších souborů se netestují. +Nette se chová různě podle toho, zda běží na vývojářském nebo produkčním serveru: -Volba režimu se provádí autodetekcí, takže obvykle není potřeba nic konfigurovat nebo ručně přepínat. Režim je vývojářský tehdy, pokud je aplikace spuštěna na localhostu (tj. IP adresa `127.0.0.1` nebo `::1`) a není přitomna proxy (tj. její HTTP hlavička). Jinak běží v produkčním režimu. +🛠️ Vývojářský režim (Development): + - Zobrazuje Tracy debugbar s užitečnými informacemi (SQL dotazy, čas vykonání, použitá paměť) + - Při chybě zobrazí detailní chybovou stránku s voláním funkcí a obsahem proměnných + - Automaticky obnovuje cache při změně Latte šablon, úpravě konfiguračních souborů atd. + + +🚀 Produkční režim (Production): + - Nezobrazuje žádné ladící informace, všechny chyby zapisuje do logu + - Při chybě zobrazí ErrorPresenter nebo obecnou stránku "Server Error" + - Cache se nikdy automaticky neobnovuje! + - Optimalizovaný pro rychlost a bezpečnost + + +Volba režimu se provádí autodetekcí, takže obvykle není potřeba nic konfigurovat nebo ručně přepínat: + +- vývojářský režim: na localhostu (IP adresa `127.0.0.1` nebo `::1`) pokud není přítomná proxy (tj. její HTTP hlavička) +- produkční režim: všude jinde Pokud chceme vývojářský režim povolit i v dalších případech, například programátorům přistupujícím z konkrétní IP adresy, použijeme `setDebugMode()`: diff --git a/application/de/bootstrap.texy b/application/de/bootstrap.texy index 6c441bfcf9..fc61ea86e2 100644 --- a/application/de/bootstrap.texy +++ b/application/de/bootstrap.texy @@ -84,9 +84,25 @@ Wie Sie sehen, hilft die Klasse [api:Nette\Bootstrap\Configurator], die wir nun Entwicklungs- vs. Produktionsmodus .[#toc-development-vs-production-mode] ========================================================================= -Nette unterscheidet zwischen zwei grundlegenden Modi, in denen eine Anfrage ausgeführt wird: Entwicklungs- und Produktionsmodus. Der Entwicklungsmodus ist auf maximalen Komfort für den Programmierer ausgerichtet, Tracy wird angezeigt, der Cache wird automatisch aktualisiert, wenn Vorlagen oder die DI-Containerkonfiguration geändert werden, usw. Im Produktionsmodus liegt der Schwerpunkt auf der Leistung, Tracy protokolliert nur Fehler und Änderungen an Vorlagen und anderen Dateien werden nicht überprüft. +Nette verhält sich unterschiedlich, je nachdem, ob es auf einem Entwicklungs- oder Produktionsserver ausgeführt wird: -Die Auswahl des Modus erfolgt durch automatische Erkennung, so dass in der Regel keine Notwendigkeit besteht, etwas manuell zu konfigurieren oder umzuschalten. Der Modus ist Entwicklung, wenn die Anwendung auf localhost läuft (d.h. IP-Adresse `127.0.0.1` oder `::1`) und kein Proxy vorhanden ist (d.h. sein HTTP-Header). Ansonsten läuft sie im Produktionsmodus. +🛠️ Entwicklungsmodus: + - Zeigt die Tracy-Debug-Leiste mit nützlichen Informationen an (z. B. SQL-Abfragen, Ausführungszeit, Speicherverbrauch). + - Zeigt eine detaillierte Fehlerseite mit Funktionsaufrufspuren und Variableninhalten, wenn ein Fehler auftritt. + - Aktualisiert automatisch den Cache, wenn Latte-Vorlagen, Konfigurationsdateien usw. geändert werden. + + +🚀 Produktionsmodus: + - Es werden keine Debugging-Informationen angezeigt; alle Fehler werden protokolliert. + - Zeigt eine `ErrorPresenter` oder eine allgemeine "Server Error"-Seite an, wenn ein Fehler auftritt. + - Der Cache wird nie automatisch aktualisiert! + - Optimiert für Geschwindigkeit und Sicherheit. + + +Der Modus wird automatisch bestimmt, so dass es in den meisten Fällen nicht notwendig ist, ihn manuell zu konfigurieren oder zu wechseln: + +- Entwicklungsmodus: Aktiv auf localhost (IP-Adresse `127.0.0.1` oder `::1`), es sei denn, es wird ein Proxy verwendet (d. h. basierend auf den HTTP-Headern). +- Produktionsmodus: Überall sonst aktiv. Wenn Sie den Entwicklungsmodus in anderen Fällen aktivieren möchten, z. B. für Programmierer, die von einer bestimmten IP-Adresse aus zugreifen, können Sie `setDebugMode()` verwenden: diff --git a/application/el/bootstrap.texy b/application/el/bootstrap.texy index f71018bac5..6031aacd33 100644 --- a/application/el/bootstrap.texy +++ b/application/el/bootstrap.texy @@ -84,9 +84,25 @@ $application->run(); Λειτουργία ανάπτυξης έναντι λειτουργίας παραγωγής .[#toc-development-vs-production-mode] ======================================================================================== -Η Nette διακρίνει μεταξύ δύο βασικών τρόπων εκτέλεσης μιας αίτησης: ανάπτυξη και παραγωγή. Η λειτουργία ανάπτυξης επικεντρώνεται στη μέγιστη άνεση του προγραμματιστή, εμφανίζεται το Tracy, η προσωρινή μνήμη ενημερώνεται αυτόματα όταν αλλάζουν τα πρότυπα ή η διαμόρφωση του DI container, κ.λπ. Η λειτουργία παραγωγής επικεντρώνεται στην απόδοση, το Tracy καταγράφει μόνο τα σφάλματα και δεν ελέγχονται οι αλλαγές των προτύπων και άλλων αρχείων. +Η Nette συμπεριφέρεται διαφορετικά ανάλογα με το αν εκτελείται σε διακομιστή ανάπτυξης ή παραγωγής: -Η επιλογή της λειτουργίας γίνεται με αυτόματη ανίχνευση, οπότε συνήθως δεν χρειάζεται να ρυθμίσετε ή να αλλάξετε κάτι χειροκίνητα. Η κατάσταση λειτουργίας είναι development εάν η εφαρμογή εκτελείται στο localhost (δηλαδή στη διεύθυνση IP `127.0.0.1` ή `::1`) και δεν υπάρχει proxy (δηλαδή η επικεφαλίδα HTTP του). Διαφορετικά, εκτελείται σε κατάσταση παραγωγής. +🛠️ Λειτουργία ανάπτυξης: + - Εμφανίζει τη γραμμή εντοπισμού σφαλμάτων του Tracy με χρήσιμες πληροφορίες (π.χ. ερωτήματα SQL, χρόνος εκτέλεσης, χρήση μνήμης). + - Εμφανίζει μια λεπτομερή σελίδα σφαλμάτων με ίχνη κλήσεων συναρτήσεων και περιεχόμενα μεταβλητών όταν εμφανίζεται σφάλμα. + - Ανανεώνει αυτόματα την προσωρινή μνήμη όταν τροποποιούνται πρότυπα Latte, αρχεία ρυθμίσεων κ.λπ. + + +🚀 Λειτουργία παραγωγής: + - Δεν εμφανίζει καμία πληροφορία εντοπισμού σφαλμάτων- όλα τα σφάλματα καταγράφονται. + - Εμφανίζει μια σελίδα `ErrorPresenter` ή μια γενική σελίδα "Σφάλμα διακομιστή" όταν προκύψει σφάλμα. + - Η προσωρινή μνήμη δεν ανανεώνεται ποτέ αυτόματα! + - Βελτιστοποιημένη για ταχύτητα και ασφάλεια. + + +Η λειτουργία καθορίζεται αυτόματα, οπότε στις περισσότερες περιπτώσεις δεν χρειάζεται να τη ρυθμίσετε ή να την αλλάξετε χειροκίνητα: + +- Λειτουργία ανάπτυξης: `127.0.0.1` ή `::1`), εκτός εάν χρησιμοποιείται ένας διακομιστής μεσολάβησης (δηλ. με βάση τις επικεφαλίδες HTTP). +- Λειτουργία παραγωγής: Ενεργός παντού αλλού. Αν θέλετε να ενεργοποιήσετε τη λειτουργία ανάπτυξης σε άλλες περιπτώσεις, για παράδειγμα, για προγραμματιστές που έχουν πρόσβαση από μια συγκεκριμένη διεύθυνση IP, μπορείτε να χρησιμοποιήσετε τη διεύθυνση `setDebugMode()`: diff --git a/application/en/bootstrap.texy b/application/en/bootstrap.texy index a950df1e88..191f250735 100644 --- a/application/en/bootstrap.texy +++ b/application/en/bootstrap.texy @@ -84,9 +84,25 @@ As you can see, the [api:Nette\Bootstrap\Configurator] class, which we will now Development vs Production Mode ============================== -Nette distinguishes between two basic modes in which a request is executed: development and production. The development mode is focused on the maximum comfort of the programmer, Tracy is displayed, the cache is automatically updated when changing templates or DI container configuration, etc. Production mode is focused on performance, Tracy only logs errors and changes of templates and other files are not checked. +Nette behaves differently depending on whether it is running on a development or production server: -Mode selection is done by autodetection, so there is usually no need to configure or switch anything manually. The mode is development if the application is running on localhost (ie IP address `127.0.0.1` or `::1`) and no proxy is present (ie its HTTP header). Otherwise, it runs in production mode. +🛠️ Development Mode: + - Displays the Tracy debug bar with useful information (e.g., SQL queries, execution time, memory usage). + - Shows a detailed error page with function call traces and variable contents when an error occurs. + - Automatically refreshes the cache when Latte templates, configuration files, etc., are modified. + + +🚀 Production Mode: + - Does not display any debugging information; all errors are logged. + - Shows an `ErrorPresenter` or a generic "Server Error" page when an error occurs. + - Cache is never automatically refreshed! + - Optimized for speed and security. + + +The mode is determined automatically, so in most cases, there’s no need to configure or switch it manually: + +- Development mode: Active on localhost (IP address `127.0.0.1` or `::1`) unless a proxy is in use (i.e., based on its HTTP headers). +- Production mode: Active everywhere else. If you want to enable development mode in other cases, for example, for programmers accessing from a specific IP address, you can use `setDebugMode()`: diff --git a/application/es/bootstrap.texy b/application/es/bootstrap.texy index 19bb56c0ba..43f1cd3683 100644 --- a/application/es/bootstrap.texy +++ b/application/es/bootstrap.texy @@ -84,9 +84,25 @@ Como puedes ver, la clase [api:Nette\Bootstrap\Configurator], que ahora presenta Modo Desarrollo vs Producción .[#toc-development-vs-production-mode] ==================================================================== -Nette distingue entre dos modos básicos en los que se ejecuta una petición: desarrollo y producción. El modo de desarrollo está enfocado a la máxima comodidad del programador, se visualiza Tracy, la caché se actualiza automáticamente al cambiar las plantillas o la configuración del contenedor DI, etc. El modo de producción está enfocado al rendimiento, Tracy sólo registra los errores y no se comprueban los cambios de plantillas y otros ficheros. +Nette se comporta de forma diferente dependiendo de si se está ejecutando en un servidor de desarrollo o de producción: -La selección del modo se hace por autodetección, por lo que normalmente no hay necesidad de configurar o cambiar nada manualmente. El modo es desarrollo si la aplicación se ejecuta en localhost (es decir, la dirección IP `127.0.0.1` o `::1`) y no hay proxy presente (es decir, su cabecera HTTP). De lo contrario, se ejecuta en modo de producción. +🛠️ Modo Desarrollo: + - Muestra la barra de depuración de Tracy con información útil (por ejemplo, consultas SQL, tiempo de ejecución, uso de memoria). + - Muestra una página de error detallada con trazas de llamadas a funciones y contenidos de variables cuando se produce un error. + - Actualiza automáticamente la caché cuando se modifican las plantillas Latte, los archivos de configuración, etc. + + +Modo de producción: + - No muestra ninguna información de depuración; se registran todos los errores. + - Muestra un `ErrorPresenter` o una página genérica de "Error de servidor" cuando se produce un error. + - ¡La caché nunca se actualiza automáticamente! + - Optimizado para velocidad y seguridad. + + +El modo se determina automáticamente, por lo que en la mayoría de los casos no es necesario configurarlo o cambiarlo manualmente: + +- Modo de desarrollo: Activo en localhost (dirección IP `127.0.0.1` o `::1`) a menos que se esté utilizando un proxy (es decir, basándose en sus cabeceras HTTP). +- Modo de producción: Activo en cualquier otro lugar. Si desea habilitar el modo de desarrollo en otros casos, por ejemplo, para los programadores que acceden desde una dirección IP específica, puede utilizar `setDebugMode()`: diff --git a/application/fr/bootstrap.texy b/application/fr/bootstrap.texy index 32c12e829b..883c45c085 100644 --- a/application/fr/bootstrap.texy +++ b/application/fr/bootstrap.texy @@ -84,9 +84,25 @@ Comme vous pouvez le constater, la classe [api:Nette\Bootstrap\Configurator], qu Mode développement et mode production .[#toc-development-vs-production-mode] ============================================================================ -Nette distingue deux modes de base dans lesquels une requête est exécutée : développement et production. Le mode développement est axé sur le confort maximal du programmeur, Tracy est affiché, le cache est automatiquement mis à jour lors de la modification des modèles ou de la configuration du conteneur DI, etc. Le mode production est axé sur les performances, Tracy ne consigne que les erreurs et les modifications des templates et autres fichiers ne sont pas vérifiées. +Nette se comporte différemment selon qu'il fonctionne sur un serveur de développement ou de production : -La sélection du mode se fait par autodétection, il n'est donc généralement pas nécessaire de configurer ou de changer quoi que ce soit manuellement. Le mode est développement si l'application est exécutée sur l'hôte local (c'est-à-dire l'adresse IP `127.0.0.1` ou `::1`) et qu'aucun proxy n'est présent (c'est-à-dire son en-tête HTTP). Sinon, elle s'exécute en mode production. +🛠️ Mode de développement: + - Affiche la barre de débogage de Tracy avec des informations utiles (par exemple, les requêtes SQL, le temps d'exécution, l'utilisation de la mémoire). + - Affiche une page d'erreur détaillée avec les traces des appels de fonction et le contenu des variables lorsqu'une erreur se produit. + - Actualise automatiquement le cache lorsque les modèles Latte, les fichiers de configuration, etc. sont modifiés. + + +Mode production: + - N'affiche aucune information de débogage ; toutes les erreurs sont enregistrées. + - Affiche une page `ErrorPresenter` ou une page générique "Server Error" lorsqu'une erreur se produit. + - Le cache n'est jamais actualisé automatiquement ! + - Optimisé pour la vitesse et la sécurité. + + +Le mode est déterminé automatiquement, de sorte que dans la plupart des cas, il n'est pas nécessaire de le configurer ou de le changer manuellement : + +- Mode développement : Actif sur l'hôte local (adresse IP `127.0.0.1` ou `::1`) à moins qu'un proxy ne soit utilisé (d'après ses en-têtes HTTP). +- Mode production : Actif partout ailleurs. Si vous souhaitez activer le mode développement dans d'autres cas, par exemple pour les programmeurs accédant depuis une adresse IP spécifique, vous pouvez utiliser `setDebugMode()`: diff --git a/application/hu/bootstrap.texy b/application/hu/bootstrap.texy index a05ab01083..5d5c77f9cb 100644 --- a/application/hu/bootstrap.texy +++ b/application/hu/bootstrap.texy @@ -84,9 +84,25 @@ Mint látható, a [api:Nette\Bootstrap\Configurator] osztály, amelyet most rés Fejlesztői vs. termelési üzemmód .[#toc-development-vs-production-mode] ======================================================================= -A Nette két alapvető módot különböztet meg, amelyben egy kérés végrehajtásra kerül: fejlesztési és termelési mód. A fejlesztési mód a programozó maximális kényelmére összpontosít, a Tracy megjelenik, a gyorsítótár automatikusan frissül, ha a sablonok vagy a DI konténer konfigurációja változik, stb. A termelési mód a teljesítményre összpontosít, a Tracy csak a hibákat naplózza, a sablonok és egyéb fájlok módosításait nem ellenőrzi. +A Nette másképp viselkedik attól függően, hogy fejlesztési vagy termelési szerveren fut: -A mód kiválasztása automatikus felismeréssel történik, így általában nem szükséges kézzel konfigurálni vagy váltani semmit. A mód fejlesztési, ha az alkalmazás localhoston fut (azaz a `127.0.0.1` vagy a `::1` IP-címen ) és nincs proxy (azaz a HTTP fejléce). Ellenkező esetben termelési üzemmódban fut. +🛠️ Fejlesztési mód: + - Megjeleníti a Tracy hibakereső sávot hasznos információkkal (pl. SQL-lekérdezések, végrehajtási idő, memóriahasználat). + - Hiba esetén részletes hibalevelet jelenít meg függvényhívás nyomvonalakkal és változótartalommal. + - Automatikusan frissíti a gyorsítótárat, amikor a Latte sablonok, konfigurációs fájlok stb. módosulnak. + + +🚀 Termelési mód: + - Nem jelenít meg semmilyen hibakeresési információt; minden hiba naplózásra kerül. + - Hiba esetén megjelenít egy `ErrorPresenter` vagy egy általános "Szerverhiba" oldalt. + - A gyorsítótár soha nem frissül automatikusan! + - A sebességre és a biztonságra optimalizált. + + +Az üzemmódot automatikusan határozza meg, így a legtöbb esetben nincs szükség a manuális beállításra vagy váltásra: + +- Fejlesztési üzemmód: `127.0.0.1` vagy `::1`), kivéve, ha proxy van használatban (azaz a HTTP fejlécek alapján). +- Gyártási üzemmód: Mindenhol máshol aktív. Ha más esetekben, például egy adott IP-címről hozzáférő programozók számára szeretné engedélyezni a fejlesztési üzemmódot, akkor a `setDebugMode()` címet használhatja: diff --git a/application/it/bootstrap.texy b/application/it/bootstrap.texy index b338b46064..0751e88b31 100644 --- a/application/it/bootstrap.texy +++ b/application/it/bootstrap.texy @@ -84,9 +84,25 @@ Come si può notare, la classe [api:Nette\Bootstrap\Configurator], che ora prese Modalità di sviluppo e modalità di produzione .[#toc-development-vs-production-mode] ==================================================================================== -Nette distingue due modalità di base per l'esecuzione di una richiesta: sviluppo e produzione. La modalità di sviluppo è incentrata sul massimo comfort del programmatore, Tracy viene visualizzato, la cache viene aggiornata automaticamente quando si modificano i template o la configurazione del contenitore DI, ecc. La modalità di produzione è incentrata sulle prestazioni, Tracy registra solo gli errori e le modifiche dei modelli e di altri file non vengono controllate. +Nette si comporta in modo diverso a seconda che venga eseguito su un server di sviluppo o di produzione: -La selezione della modalità avviene tramite il rilevamento automatico, quindi di solito non è necessario configurare o cambiare qualcosa manualmente. La modalità è di sviluppo se l'applicazione è in esecuzione su localhost (cioè l'indirizzo IP `127.0.0.1` o `::1`) e non è presente alcun proxy (cioè la sua intestazione HTTP). Altrimenti, viene eseguita in modalità di produzione. +🛠️ Modalità di sviluppo: + - Visualizza la barra di debug Tracy con informazioni utili (ad esempio, query SQL, tempo di esecuzione, utilizzo della memoria). + - Mostra una pagina di errore dettagliata con le tracce delle chiamate di funzione e il contenuto delle variabili quando si verifica un errore. + - Aggiorna automaticamente la cache quando vengono modificati i modelli di Latte, i file di configurazione, ecc. + + +🚀 Modalità di produzione: + - Non visualizza alcuna informazione di debug; tutti gli errori vengono registrati. + - Mostra un `ErrorPresenter` o una pagina generica "Server Error" quando si verifica un errore. + - La cache non viene mai aggiornata automaticamente! + - Ottimizzato per la velocità e la sicurezza. + + +La modalità è determinata automaticamente, quindi nella maggior parte dei casi non è necessario configurarla o cambiarla manualmente: + +- Modalità di sviluppo: Attivo su localhost (indirizzo IP `127.0.0.1` o `::1`) a meno che non sia in uso un proxy (ad esempio, in base alle intestazioni HTTP). +- Modalità di produzione: Attivo ovunque. Se si vuole abilitare la modalità di sviluppo in altri casi, ad esempio per i programmatori che accedono da un indirizzo IP specifico, si può usare `setDebugMode()`: diff --git a/application/pl/bootstrap.texy b/application/pl/bootstrap.texy index 084d93b416..c1934bff3a 100644 --- a/application/pl/bootstrap.texy +++ b/application/pl/bootstrap.texy @@ -84,9 +84,25 @@ Jak widać, klasa [api:Nette\Bootstrap\Configurator] pomaga w konfiguracji środ Tryb deweloperski a produkcyjny .[#toc-development-vs-production-mode] ====================================================================== -Nette rozróżnia dwa podstawowe tryby, w których realizowane jest żądanie: deweloperski i produkcyjny. Tryb deweloperski ma na celu maksymalną wygodę dla programisty, wyświetlana jest Tracy, pamięć podręczna jest automatycznie aktualizowana, gdy zmieniają się szablony lub konfiguracje kontenerów DI itp. Produkcja skupia się na wydajności i rześkim wdrożeniu, Tracy tylko loguje błędy, a zmiany w szablonach i innych plikach nie są testowane. +Nette zachowuje się różnie w zależności od tego, czy działa na serwerze deweloperskim czy produkcyjnym: -Wybór trybu odbywa się poprzez autodetekcję, więc zazwyczaj nie ma potrzeby konfigurowania czy ręcznego przełączania czegokolwiek. Trybem deweloperskim jest sytuacja, kiedy aplikacja jest uruchomiona na localhoście (czyli na adresie IP `127.0.0.1` lub `::1`) i nie ma proxy (czyli jego nagłówka HTTP). W przeciwnym razie działa w trybie produkcyjnym. +🛠️ Tryb deweloperski: + - Wyświetla pasek debugowania Tracy z przydatnymi informacjami (np. zapytania SQL, czas wykonania, użycie pamięci). + - Wyświetla szczegółową stronę błędu ze śladami wywołań funkcji i zawartością zmiennych w przypadku wystąpienia błędu. + - Automatycznie odświeża pamięć podręczną, gdy modyfikowane są szablony Latte, pliki konfiguracyjne itp. + + +Tryb produkcyjny: + - Nie wyświetla żadnych informacji debugowania; wszystkie błędy są rejestrowane. + - Wyświetla stronę `ErrorPresenter` lub ogólną stronę "Błąd serwera", gdy wystąpi błąd. + - Pamięć podręczna nigdy nie jest automatycznie odświeżana! + - Zoptymalizowany pod kątem szybkości i bezpieczeństwa. + + +Tryb jest określany automatycznie, więc w większości przypadków nie ma potrzeby konfigurowania lub przełączania go ręcznie: + +- Tryb deweloperski: Aktywny na localhost (adres IP `127.0.0.1` lub `::1`), chyba że używany jest serwer proxy (tj. na podstawie jego nagłówków HTTP). +- Tryb produkcyjny: Aktywny wszędzie indziej. Jeśli chcemy włączyć tryb deweloperski w innych przypadkach, takich jak programiści uzyskujący dostęp z określonego adresu IP, używamy `setDebugMode()`: diff --git a/application/pt/bootstrap.texy b/application/pt/bootstrap.texy index 1428498866..e3b4a1166e 100644 --- a/application/pt/bootstrap.texy +++ b/application/pt/bootstrap.texy @@ -84,9 +84,25 @@ Como você pode ver, a classe [api:Nette\Bootstrap\Configurator], que agora vamo Desenvolvimento vs Modo de Produção .[#toc-development-vs-production-mode] ========================================================================== -Nette distingue dois modos básicos nos quais uma solicitação é executada: desenvolvimento e produção. O modo de desenvolvimento é focado no máximo conforto do programador, Tracy é exibido, o cache é atualizado automaticamente ao alterar os modelos ou a configuração do container DI, etc. O modo de produção é focado no desempenho, Tracy apenas registra erros e mudanças de gabaritos e outros arquivos não são verificados. +O Nette se comporta de forma diferente, dependendo se está sendo executado em um servidor de desenvolvimento ou de produção: -A seleção do modo é feita por autodetecção, de modo que normalmente não há necessidade de configurar ou trocar nada manualmente. O modo é desenvolvimento se a aplicação estiver rodando no localhost (ou seja, endereço IP `127.0.0.1` ou `::1`) e nenhum proxy estiver presente (ou seja, seu cabeçalho HTTP). Caso contrário, ele é executado em modo de produção. +🛠️ Development Mode (Modo de desenvolvimento): + - Exibe a barra de depuração Tracy com informações úteis (por exemplo, consultas SQL, tempo de execução, uso de memória). + - Mostra uma página de erro detalhada com rastros de chamadas de função e conteúdo de variáveis quando ocorre um erro. + - Atualiza automaticamente o cache quando modelos Latte, arquivos de configuração etc. são modificados. + + +Modo de produção: + - Não exibe nenhuma informação de depuração; todos os erros são registrados. + - Mostra um `ErrorPresenter` ou uma página genérica de "Erro do servidor" quando ocorre um erro. + - O cache nunca é atualizado automaticamente! + - Otimizado para velocidade e segurança. + + +O modo é determinado automaticamente, portanto, na maioria dos casos, não há necessidade de configurá-lo ou alterná-lo manualmente: + +- Modo de desenvolvimento: Ativo no localhost (endereço IP `127.0.0.1` ou `::1`), a menos que um proxy esteja em uso (ou seja, com base em seus cabeçalhos HTTP). +- Modo de produção: Ativo em todos os outros lugares. Se você quiser ativar o modo de desenvolvimento em outros casos, por exemplo, para programadores que acessam de um endereço IP específico, você pode usar `setDebugMode()`: diff --git a/application/ro/bootstrap.texy b/application/ro/bootstrap.texy index 97b1a1fe30..988324e93c 100644 --- a/application/ro/bootstrap.texy +++ b/application/ro/bootstrap.texy @@ -84,9 +84,25 @@ După cum puteți vedea, clasa [api:Nette\Bootstrap\Configurator], pe care o vom Modul de dezvoltare vs. modul de producție .[#toc-development-vs-production-mode] ================================================================================= -Nette face distincție între două moduri de bază în care este executată o cerere: dezvoltare și producție. Modul de dezvoltare este axat pe confortul maxim al programatorului, Tracy este afișat, memoria cache este actualizată automat atunci când se schimbă șabloanele sau configurația containerului DI etc. Modul de producție este axat pe performanță, Tracy înregistrează doar erorile, iar modificările șabloanelor și ale altor fișiere nu sunt verificate. +Nette se comportă diferit în funcție de faptul dacă rulează pe un server de dezvoltare sau de producție: -Selectarea modului se face prin autodetecție, astfel încât, de obicei, nu este nevoie să configurați sau să comutați nimic manual. Modul este dezvoltare dacă aplicația rulează pe localhost (adică adresa IP `127.0.0.1` sau `::1`) și nu este prezent niciun proxy (adică antetul său HTTP). În caz contrar, se execută în modul de producție. +🛠️ Modul de dezvoltare: + - Afișează bara de depanare Tracy cu informații utile (de exemplu, interogări SQL, timp de execuție, utilizarea memoriei). + - Afișează o pagină de erori detaliată cu urmele apelurilor funcțiilor și conținutul variabilelor atunci când apare o eroare. + - Actualizează automat memoria cache atunci când sunt modificate șabloanele Latte, fișierele de configurare etc. + + +🚀 Modul de producție: + - Nu afișează nicio informație de depanare; toate erorile sunt înregistrate. + - Afișează o pagină `ErrorPresenter` sau o pagină generică "Server Error" atunci când apare o eroare. + - Cache-ul nu este niciodată reîmprospătat automat! + - Optimizat pentru viteză și securitate. + + +Modul este determinat automat, astfel încât, în majoritatea cazurilor, nu este nevoie să îl configurați sau să îl comutați manual: + +- Modul de dezvoltare: Activ pe localhost (adresa IP `127.0.0.1` sau `::1`), cu excepția cazului în care se utilizează un proxy (adică, pe baza antetelor sale HTTP). +- Modul de producție: Activ peste tot. Dacă doriți să activați modul de dezvoltare în alte cazuri, de exemplu, pentru programatorii care accesează de la o anumită adresă IP, puteți utiliza `setDebugMode()`: diff --git a/application/ru/bootstrap.texy b/application/ru/bootstrap.texy index 82e18f8d6b..04c5a0257b 100644 --- a/application/ru/bootstrap.texy +++ b/application/ru/bootstrap.texy @@ -84,9 +84,25 @@ $application->run(); Режим разработки и режим производства .[#toc-development-vs-production-mode] ============================================================================ -Nette различает два основных режима, в которых выполняется запрос: разработка и производство. Режим разработки ориентирован на максимальное удобство программиста, отображается Tracy, кэш автоматически обновляется при изменении шаблонов или конфигурации DI контейнера и т. д. Режим производства ориентирован на производительность, Tracy только регистрирует ошибки, а изменения шаблонов и других файлов не проверяются. +Nette ведет себя по-разному в зависимости от того, работает ли он на сервере разработки или на рабочем сервере: -Выбор режима осуществляется путем автоопределения, поэтому обычно нет необходимости настраивать или переключать что-либо вручную. Режим разработки используется, если приложение запущено на localhost (т. е. IP-адрес `127.0.0.1` или `::1`) и отсутствует прокси-сервер (т. е. его HTTP-заголовок). В противном случае приложение работает в производственном режиме. +🛠️ Режим разработки: + - Отображает панель отладки Tracy с полезной информацией (например, SQL-запросы, время выполнения, использование памяти). + - При возникновении ошибки показывает подробную страницу ошибки с трассировкой вызовов функций и содержимым переменных. + - Автоматически обновляет кэш при изменении шаблонов Latte, файлов конфигурации и т. д. + + +🚀 Производственный режим: + - Не отображает никакой отладочной информации; все ошибки записываются в журнал. + - При возникновении ошибки показывает `ErrorPresenter` или общую страницу "Ошибка сервера". + - Кэш никогда не обновляется автоматически! + - Оптимизирован для скорости и безопасности. + + +Режим определяется автоматически, поэтому в большинстве случаев нет необходимости настраивать или переключать его вручную: + +- Режим разработки: Активен на localhost (IP-адрес `127.0.0.1` или `::1`), если не используется прокси (т.е. на основании HTTP-заголовков). +- Производственный режим: Активен везде. Если вы хотите включить режим разработки в других случаях, например, для программистов, получающих доступ с определенного IP-адреса, вы можете использовать `setDebugMode()`: diff --git a/application/sl/bootstrap.texy b/application/sl/bootstrap.texy index 33f36e50e8..4f5ca2a413 100644 --- a/application/sl/bootstrap.texy +++ b/application/sl/bootstrap.texy @@ -84,9 +84,25 @@ Kot vidite, razred [api:Nette\Bootstrap\Configurator], ki ga bomo zdaj podrobnej Razvojni in produkcijski način .[#toc-development-vs-production-mode] ===================================================================== -Nette razlikuje med dvema osnovnima načinoma izvajanja zahtevka: razvojnim in produkcijskim. Razvojni način je osredotočen na čim večje udobje programerja, prikazan je Tracy, predpomnilnik se samodejno posodablja ob spreminjanju predlog ali konfiguracije vsebnika DI itd. Produkcijski način je osredotočen na zmogljivost, Tracy beleži le napake, spremembe predlog in drugih datotek pa se ne preverjajo. +Nette se obnaša različno, odvisno od tega, ali deluje v razvojnem ali produkcijskem strežniku: -Izbira načina poteka s samodejnim zaznavanjem, zato običajno ni treba ničesar ročno konfigurirati ali preklapljati. Način je razvojni, če aplikacija teče na lokalnem gostitelju (tj. naslov IP `127.0.0.1` ali `::1`) in ni prisoten posrednik (tj. njegova glavička HTTP). V nasprotnem primeru deluje v produkcijskem načinu. +🛠️ Razvojni način: + - Prikaže Tracyjev razhroščevalni niz z uporabnimi informacijami (npr. poizvedbe SQL, čas izvajanja, poraba pomnilnika). + - Prikaže podrobno stran z napakami s sledmi klicev funkcij in vsebino spremenljivk, ko pride do napake. + - Samodejno osveži predpomnilnik, ko se spremenijo predloge Latte, konfiguracijske datoteke itd. + + +🚀 Produkcijski način: + - Ne prikaže nobenih informacij o odpravljanju napak; vse napake se zabeležijo. + - Prikaže stran `ErrorPresenter` ali splošno stran "Server Error" (Napaka strežnika), ko pride do napake. + - Predpomnilnik se nikoli samodejno ne osveži! + - Optimizirano za hitrost in varnost. + + +Način se določi samodejno, zato ga v večini primerov ni treba ročno konfigurirati ali preklapljati: + +- Razvojni način: (IP naslov `127.0.0.1` ali `::1`), razen če je v uporabi posrednik (tj. na podlagi glave HTTP). +- Produkcijski način: Aktivno povsod drugje. Če želite omogočiti razvojni način v drugih primerih, na primer za programerje, ki dostopajo z določenega naslova IP, lahko uporabite `setDebugMode()`: diff --git a/application/tr/bootstrap.texy b/application/tr/bootstrap.texy index 1513e7fe3a..4fc005fa8f 100644 --- a/application/tr/bootstrap.texy +++ b/application/tr/bootstrap.texy @@ -84,9 +84,25 @@ Gördüğünüz gibi, şimdi daha ayrıntılı olarak tanıtacağımız [api:Net Geliştirme ve Üretim Modu .[#toc-development-vs-production-mode] ================================================================ -Nette, bir talebin yürütüldüğü iki temel mod arasında ayrım yapar: geliştirme ve üretim. Geliştirme modu programcının maksimum konforuna odaklanır, Tracy görüntülenir, şablonlar veya DI konteyner yapılandırması değiştirilirken önbellek otomatik olarak güncellenir, vb. Üretim modu performansa odaklanır, Tracy yalnızca hataları günlüğe kaydeder ve şablonların ve diğer dosyaların değişiklikleri kontrol edilmez. +Nette, bir geliştirme veya üretim sunucusunda çalışmasına bağlı olarak farklı davranır: -Mod seçimi otomatik algılama ile yapılır, bu nedenle genellikle herhangi bir şeyi manuel olarak yapılandırmaya veya değiştirmeye gerek yoktur. Uygulama localhost üzerinde çalışıyorsa (yani IP adresi `127.0.0.1` veya `::1`) ve proxy yoksa (yani HTTP başlığı) mod geliştirmedir. Aksi takdirde, üretim modunda çalışır. +🛠️ Geliştirme Modu: + - Tracy hata ayıklama çubuğunu yararlı bilgilerle birlikte görüntüler (örn. SQL sorguları, yürütme süresi, bellek kullanımı). + - Bir hata oluştuğunda işlev çağrısı izlerini ve değişken içeriklerini içeren ayrıntılı bir hata sayfası gösterir. + - Latte şablonları, yapılandırma dosyaları vb. değiştirildiğinde önbelleği otomatik olarak yeniler. + + +🚀 Üretim Modu: + - Herhangi bir hata ayıklama bilgisi göstermez; tüm hatalar günlüğe kaydedilir. + - Bir hata oluştuğunda `ErrorPresenter` veya genel bir "Sunucu Hatası" sayfası gösterir. + - Önbellek asla otomatik olarak yenilenmez! + - Hız ve güvenlik için optimize edilmiştir. + + +Mod otomatik olarak belirlenir, bu nedenle çoğu durumda manuel olarak yapılandırmaya veya değiştirmeye gerek yoktur: + +- Geliştirme modu: Bir proxy kullanılmadığı sürece (yani HTTP üstbilgilerine göre) localhost'ta (IP adresi `127.0.0.1` veya `::1`) etkin. +- Üretim modu: Diğer her yerde aktif. Geliştirme modunu diğer durumlarda, örneğin belirli bir IP adresinden erişen programcılar için etkinleştirmek istiyorsanız, `setDebugMode()` adresini kullanabilirsiniz: diff --git a/application/uk/bootstrap.texy b/application/uk/bootstrap.texy index aef63e390f..86dd1b6204 100644 --- a/application/uk/bootstrap.texy +++ b/application/uk/bootstrap.texy @@ -84,9 +84,25 @@ $application->run(); Режим розробки та режим виробництва .[#toc-development-vs-production-mode] ========================================================================== -Nette розрізняє два основні режими, в яких виконується запит: розробка і виробництво. Режим розробки орієнтований на максимальну зручність програміста, відображається Tracy, кеш автоматично оновлюється у разі зміни шаблонів або конфігурації DI контейнера тощо. Режим виробництва орієнтований на продуктивність, Tracy тільки реєструє помилки, а зміни шаблонів та інших файлів не перевіряються. +Nette поводиться по-різному залежно від того, чи запущено його на сервері розробки, чи на робочому сервері: -Вибір режиму здійснюється шляхом автовизначення, тому зазвичай немає необхідності налаштовувати або перемикати що-небудь вручну. Режим розробки використовується, якщо застосунок запущено на localhost (тобто IP-адресу `127.0.0.1` або `::1`) і відсутній проксі-сервер (тобто його HTTP-заголовок). В іншому разі застосунок працює у виробничому режимі. +🛠️ Режим розробки: + - Відображає панель налагодження Tracy з корисною інформацією (наприклад, SQL-запити, час виконання, використання пам'яті). + - Показує детальну сторінку помилок з трасуванням викликів функцій та вмістом змінних при виникненні помилки. + - Автоматично оновлює кеш при зміні шаблонів Latte, конфігураційних файлів тощо. + + +🚀 Виробничий режим: + - Не відображає ніякої налагоджувальної інформації; всі помилки реєструються. + - Показує `ErrorPresenter` або загальну сторінку "Помилка сервера", коли виникає помилка. + - Кеш ніколи не оновлюється автоматично! + - Оптимізовано для швидкості та безпеки. + + +Режим визначається автоматично, тому в більшості випадків немає необхідності налаштовувати або перемикати його вручну: + +- Режим розробки: Активний на localhost (IP-адреса `127.0.0.1` або `::1`), якщо не використовується проксі (тобто на основі його HTTP-заголовків). +- Виробничий режим: Активний скрізь. Якщо ви хочете ввімкнути режим розробки в інших випадках, наприклад, для програмістів, які отримують доступ з певної IP-адреси, ви можете використовувати `setDebugMode()`: diff --git a/nette/bg/troubleshooting.texy b/nette/bg/troubleshooting.texy index b21f1f4d64..e4dd3e012e 100644 --- a/nette/bg/troubleshooting.texy +++ b/nette/bg/troubleshooting.texy @@ -32,6 +32,17 @@ Tracy ще ви информира защо не може да регистри Когато всички страници (с изключение на началната страница) връщат грешка 404, това изглежда като проблем с конфигурацията на сървъра за [красиви URL адреси |#How to Configure a Server for Nice URLs?]. +Промените в шаблоните или конфигурацията не се отразяват .[#toc-changes-in-templates-or-configuration-are-not-reflected] +------------------------------------------------------------------------------------------------------------------------ +"Промених шаблона или конфигурацията, но уебсайтът все още показва старата версия." Това поведение се проявява в [производствен режим, |application:bootstrap#Development vs Production Mode] който по причини, свързани с производителността, не проверява за промени във файловете и поддържа предварително генериран кеш. + +За да избегнете ръчното изчистване на кеша на производствения сървър след всяка модификация, разрешете режима за разработка за вашия IP адрес във файла `Bootstrap.php`: + +```php +$this->configurator->setDebugMode('your.ip.address'); +``` + + Как да деактивирам кеша по време на разработка? .[#toc-how-to-disable-cache-during-development] ----------------------------------------------------------------------------------------------- Nette е умен и не е необходимо да деактивирате кеширането в него. По време на разработката той автоматично актуализира кеша, когато има промяна в шаблона или конфигурацията на DI контейнера. Освен това режимът за разработка се активира чрез автоматично откриване, така че обикновено не е необходимо да конфигурирате нищо [или само IP адреса |application:bootstrap#development-vs-production-mode]. diff --git a/nette/cs/troubleshooting.texy b/nette/cs/troubleshooting.texy index 5e4973f910..af3cb4858e 100644 --- a/nette/cs/troubleshooting.texy +++ b/nette/cs/troubleshooting.texy @@ -32,6 +32,17 @@ Chyba 404, nefunguje routování Když všechny stránky (kromě homepage) vrací chybu 404, vypadá to na problém s konfigurací serveru pro [hezká URL |#Jak nastavit server pro hezká URL?]. +Změny v šablonách nebo konfiguraci se neprojevují +------------------------------------------------- +"Upravil jsem šablonu nebo konfiguraci, ale web stále zobrazuje starou verzi." Toto chování nastává v [produkčním režimu |application:bootstrap#Vývojářský vs produkční režim], který z důvodu výkonu nekontroluje změny v souborech a udržuje jednou vygenerovanou cache. + +Abyste nemuseli na produkčním serveru po každé úpravě ručně mazat cache, povolte si vývojářský režim pro vaši IP adresu v souboru `Bootstrap.php`: + +```php +$this->configurator->setDebugMode('vase.ip.adresa'); +``` + + Jak vypnout cache během vývoje? ------------------------------- Nette je chytré a nemusíte v něm vypínat kešování. Při vývoji totiž automaticky aktualizuje cache při každé změně šablony nebo konfigurace DI kontejneru. Vývojový režimu se navíc zapíná autodetekcí, takže obvykle není potřeba konfigurovat nic, [nebo jen IP adresu |application:bootstrap#vyvojarsky-vs-produkcni-rezim]. diff --git a/nette/de/troubleshooting.texy b/nette/de/troubleshooting.texy index c969b14507..ec2aa37dde 100644 --- a/nette/de/troubleshooting.texy +++ b/nette/de/troubleshooting.texy @@ -32,6 +32,17 @@ Fehler 404, Routing funktioniert nicht .[#toc-error-404-routing-not-working] Wenn alle Seiten (außer der Homepage) einen 404-Fehler zurückgeben, sieht es nach einem Serverkonfigurationsproblem für [hübsche URLs |#How to Configure a Server for Nice URLs?] aus. +Änderungen an Vorlagen oder der Konfiguration werden nicht berücksichtigt .[#toc-changes-in-templates-or-configuration-are-not-reflected] +----------------------------------------------------------------------------------------------------------------------------------------- +"Ich habe die Vorlage oder die Konfiguration geändert, aber die Website zeigt immer noch die alte Version an. Dieses Verhalten tritt im [Produktionsmodus |application:bootstrap#Development vs Production Mode] auf, der aus Leistungsgründen nicht auf Datei-Änderungen prüft und einen zuvor erstellten Cache beibehält. + +Um zu vermeiden, dass der Cache auf dem Produktionsserver nach jeder Änderung manuell geleert wird, aktivieren Sie den Entwicklungsmodus für Ihre IP-Adresse in der Datei `Bootstrap.php`: + +```php +$this->configurator->setDebugMode('your.ip.address'); +``` + + Wie kann man den Cache während der Entwicklung deaktivieren? .[#toc-how-to-disable-cache-during-development] ------------------------------------------------------------------------------------------------------------ Nette ist intelligent, und Sie müssen das Caching nicht deaktivieren. Während der Entwicklung wird der Cache automatisch aktualisiert, sobald eine Änderung in der Vorlage oder der DI-Container-Konfiguration vorgenommen wird. Außerdem wird der Entwicklungsmodus durch automatische Erkennung aktiviert, so dass normalerweise nichts konfiguriert werden muss, [auch nicht die IP-Adresse |application:bootstrap#development-vs-production-mode]. diff --git a/nette/el/troubleshooting.texy b/nette/el/troubleshooting.texy index ffdd42680e..7988a565e8 100644 --- a/nette/el/troubleshooting.texy +++ b/nette/el/troubleshooting.texy @@ -32,6 +32,17 @@ $configurator->enableTracy($rootDir . '/log'); Όταν όλες οι σελίδες (εκτός από την αρχική σελίδα) επιστρέφουν ένα σφάλμα 404, φαίνεται ότι υπάρχει πρόβλημα διαμόρφωσης του διακομιστή για τις [όμορφες διευθύνσεις URL |#How to Configure a Server for Nice URLs?]. +Οι αλλαγές σε πρότυπα ή ρυθμίσεις δεν αντικατοπτρίζονται .[#toc-changes-in-templates-or-configuration-are-not-reflected] +------------------------------------------------------------------------------------------------------------------------ +"Τροποποίησα το πρότυπο ή τη διαμόρφωση, αλλά ο ιστότοπος εξακολουθεί να εμφανίζει την παλιά έκδοση." Αυτή η συμπεριφορά εμφανίζεται στη [λειτουργία παραγωγής |application:bootstrap#Development vs Production Mode], η οποία, για λόγους απόδοσης, δεν ελέγχει για αλλαγές αρχείων και διατηρεί μια προηγουμένως δημιουργημένη προσωρινή μνήμη. + +Για να αποφύγετε τη χειροκίνητη εκκαθάριση της προσωρινής μνήμης στον διακομιστή παραγωγής μετά από κάθε τροποποίηση, ενεργοποιήστε τη λειτουργία ανάπτυξης για τη διεύθυνση IP σας στο αρχείο `Bootstrap.php`: + +```php +$this->configurator->setDebugMode('your.ip.address'); +``` + + Πώς να απενεργοποιήσετε την προσωρινή μνήμη cache κατά τη διάρκεια της ανάπτυξης; .[#toc-how-to-disable-cache-during-development] --------------------------------------------------------------------------------------------------------------------------------- Το Nette είναι έξυπνο και δεν χρειάζεται να απενεργοποιήσετε την προσωρινή αποθήκευση σε αυτό. Κατά τη διάρκεια της ανάπτυξης, ενημερώνει αυτόματα την κρυφή μνήμη κάθε φορά που υπάρχει μια αλλαγή στο πρότυπο ή στη διαμόρφωση του DI container. Επιπλέον, η λειτουργία ανάπτυξης ενεργοποιείται με αυτόματη ανίχνευση, οπότε συνήθως δεν χρειάζεται να ρυθμίσετε τίποτα [ή μόνο τη διεύθυνση IP |application:bootstrap#development-vs-production-mode]. diff --git a/nette/en/troubleshooting.texy b/nette/en/troubleshooting.texy index 70b0b650bd..979d53be16 100644 --- a/nette/en/troubleshooting.texy +++ b/nette/en/troubleshooting.texy @@ -32,6 +32,17 @@ Error 404, Routing Not Working When all pages (except the homepage) return a 404 error, it looks like a server configuration problem for [pretty URLs |#How to Configure a Server for Nice URLs?]. +Changes in templates or configuration are not reflected +------------------------------------------------------- +"I modified the template or configuration, but the website still displays the old version." This behavior occurs in [production mode |application:bootstrap#Development vs Production Mode], which, for performance reasons, does not check for file changes and maintains a previously generated cache. + +To avoid manually clearing the cache on the production server after every modification, enable development mode for your IP address in the `Bootstrap.php` file: + +```php +$this->configurator->setDebugMode('your.ip.address'); +``` + + How to Disable Cache During Development? ---------------------------------------- Nette is smart, and you don't need to disable caching in it. During development, it automatically updates the cache whenever there's a change in the template or the DI container configuration. Moreover, the development mode is activated by auto-detection, so there's usually no need to configure anything, [or just the IP address |application:bootstrap#development-vs-production-mode]. diff --git a/nette/es/troubleshooting.texy b/nette/es/troubleshooting.texy index 963876307f..6d617c2351 100644 --- a/nette/es/troubleshooting.texy +++ b/nette/es/troubleshooting.texy @@ -32,6 +32,17 @@ Error 404, enrutamiento no funciona .[#toc-error-404-routing-not-working] Cuando todas las páginas (excepto la página de inicio) devuelven un error 404, parece un problema de configuración del servidor para [URLs bonitas |#How to Configure a Server for Nice URLs?]. +Los cambios en las plantillas o en la configuración no se reflejan .[#toc-changes-in-templates-or-configuration-are-not-reflected] +---------------------------------------------------------------------------------------------------------------------------------- +"He modificado la plantilla o la configuración, pero la web sigue mostrando la versión antigua". Este comportamiento se produce en el [modo de producción |application:bootstrap#Development vs Production Mode], que, por razones de rendimiento, no comprueba los cambios en los archivos y mantiene una caché generada previamente. + +Para evitar borrar manualmente la caché en el servidor de producción después de cada modificación, habilite el modo de desarrollo para su dirección IP en el archivo `Bootstrap.php`: + +```php +$this->configurator->setDebugMode('your.ip.address'); +``` + + ¿Cómo desactivar la caché durante el desarrollo? .[#toc-how-to-disable-cache-during-development] ------------------------------------------------------------------------------------------------ Nette es inteligente, y no necesitas desactivar la caché en él. Durante el desarrollo, actualiza automáticamente la caché cada vez que hay un cambio en la plantilla o en la configuración del contenedor DI. Además, el modo de desarrollo se activa por auto-detección, por lo que normalmente no hay necesidad de configurar nada, [o sólo la dirección IP |application:bootstrap#development-vs-production-mode]. diff --git a/nette/fr/troubleshooting.texy b/nette/fr/troubleshooting.texy index a1b8cfcf69..104eb0f530 100644 --- a/nette/fr/troubleshooting.texy +++ b/nette/fr/troubleshooting.texy @@ -32,6 +32,17 @@ Erreur 404, le routage ne fonctionne pas .[#toc-error-404-routing-not-working] Lorsque toutes les pages (sauf la page d'accueil) renvoient une erreur 404, il semble qu'il y ait un problème de configuration du serveur pour les [jolies URL |#How to Configure a Server for Nice URLs?]. +Les modifications apportées aux modèles ou à la configuration ne sont pas prises en compte .[#toc-changes-in-templates-or-configuration-are-not-reflected] +---------------------------------------------------------------------------------------------------------------------------------------------------------- +"J'ai modifié le modèle ou la configuration, mais le site web affiche toujours l'ancienne version. Ce comportement se produit en [mode production |application:bootstrap#Development vs Production Mode] qui, pour des raisons de performance, ne vérifie pas les modifications de fichiers et maintient un cache généré précédemment. + +Pour éviter de vider manuellement le cache sur le serveur de production après chaque modification, activez le mode développement pour votre adresse IP dans le fichier `Bootstrap.php`: + +```php +$this->configurator->setDebugMode('your.ip.address'); +``` + + Comment désactiver le cache pendant le développement ? .[#toc-how-to-disable-cache-during-development] ------------------------------------------------------------------------------------------------------ Nette est intelligent et il n'est pas nécessaire de désactiver la mise en cache. Pendant le développement, il met automatiquement à jour le cache chaque fois qu'il y a un changement dans le modèle ou la configuration du conteneur DI. De plus, le mode développement est activé par auto-détection, il n'y a donc généralement pas besoin de configurer quoi que ce soit, [ou juste l'adresse IP |application:bootstrap#development-vs-production-mode]. diff --git a/nette/hu/troubleshooting.texy b/nette/hu/troubleshooting.texy index 765855a096..4c09cdfdb6 100644 --- a/nette/hu/troubleshooting.texy +++ b/nette/hu/troubleshooting.texy @@ -32,6 +32,17 @@ Az 500-as hiba egyik leggyakoribb oka az elavult gyorsítótár. Míg a Nette ok Amikor minden oldal (a kezdőlap kivételével) 404-es hibát ad vissza, úgy tűnik, hogy a szerver konfigurációs problémája van a [szép URL-eknél |#How to Configure a Server for Nice URLs?]. +A sablonok vagy a konfiguráció változásai nem tükröződnek .[#toc-changes-in-templates-or-configuration-are-not-reflected] +------------------------------------------------------------------------------------------------------------------------- +"Módosítottam a sablont vagy a konfigurációt, de a weboldal még mindig a régi verziót jeleníti meg." Ez a viselkedés a [termelési üzemmódban |application:bootstrap#Development vs Production Mode] fordul elő, amely a teljesítmény miatt nem ellenőrzi a fájlváltozásokat, és fenntartja a korábban létrehozott gyorsítótárat. + +Annak érdekében, hogy elkerülje a gyorsítótár manuális törlését a termelő szerveren minden módosítás után, engedélyezze a `Bootstrap.php` fájlban a fejlesztési üzemmódot az IP-címe számára: + +```php +$this->configurator->setDebugMode('your.ip.address'); +``` + + Hogyan lehet letiltani a gyorsítótárat a fejlesztés során? .[#toc-how-to-disable-cache-during-development] ---------------------------------------------------------------------------------------------------------- A Nette okos, és nem kell kikapcsolni benne a gyorsítótárazást. A fejlesztés során automatikusan frissíti a gyorsítótárat, ha változás történik a sablonban vagy a DI konténer konfigurációjában. Ráadásul a fejlesztési mód automatikus felismeréssel aktiválódik, így általában nem kell semmit, [vagy csak az IP-címet |application:bootstrap#development-vs-production-mode] konfigurálni. diff --git a/nette/it/troubleshooting.texy b/nette/it/troubleshooting.texy index cbf29ca1f3..461fd7eba0 100644 --- a/nette/it/troubleshooting.texy +++ b/nette/it/troubleshooting.texy @@ -32,6 +32,17 @@ Errore 404, il routing non funziona .[#toc-error-404-routing-not-working] Quando tutte le pagine (tranne la homepage) restituiscono un errore 404, sembra che ci sia un problema di configurazione del server per gli [URL più belli |#How to Configure a Server for Nice URLs?]. +Le modifiche apportate ai modelli o alla configurazione non vengono riflesse .[#toc-changes-in-templates-or-configuration-are-not-reflected] +-------------------------------------------------------------------------------------------------------------------------------------------- +"Ho modificato il modello o la configurazione, ma il sito web visualizza ancora la vecchia versione". Questo comportamento si verifica nella [modalità di produzione |application:bootstrap#Development vs Production Mode] che, per motivi di prestazioni, non controlla le modifiche ai file e mantiene una cache generata in precedenza. + +Per evitare di cancellare manualmente la cache sul server di produzione dopo ogni modifica, abilitare la modalità di sviluppo per il proprio indirizzo IP nel file `Bootstrap.php`: + +```php +$this->configurator->setDebugMode('your.ip.address'); +``` + + Come disattivare la cache durante lo sviluppo? .[#toc-how-to-disable-cache-during-development] ---------------------------------------------------------------------------------------------- Nette è intelligente e non è necessario disabilitare la cache. Durante lo sviluppo, aggiorna automaticamente la cache ogni volta che c'è un cambiamento nel template o nella configurazione del contenitore DI. Inoltre, la modalità di sviluppo è attivata dal rilevamento automatico, quindi di solito non è necessario configurare nulla, [o solo l'indirizzo IP |application:bootstrap#development-vs-production-mode]. diff --git a/nette/pl/troubleshooting.texy b/nette/pl/troubleshooting.texy index b2af3ea4db..a6ba6ea967 100644 --- a/nette/pl/troubleshooting.texy +++ b/nette/pl/troubleshooting.texy @@ -32,6 +32,17 @@ Błąd 404, routing nie działa .[#toc-error-404-routing-not-working] Kiedy wszystkie strony (oprócz strony głównej) zwracają błąd 404, wygląda to na problem z konfiguracją serwera dla [ładnych adresów URL |#How to Configure a Server for Nice URLs?]. +Zmiany w szablonach lub konfiguracji nie są odzwierciedlane .[#toc-changes-in-templates-or-configuration-are-not-reflected] +--------------------------------------------------------------------------------------------------------------------------- +"Zmodyfikowałem szablon lub konfigurację, ale witryna nadal wyświetla starą wersję". Takie zachowanie występuje w [trybie produkcyjnym |application:bootstrap#Development vs Production Mode], który ze względów wydajnościowych nie sprawdza zmian w plikach i utrzymuje wcześniej wygenerowaną pamięć podręczną. + +Aby uniknąć ręcznego czyszczenia pamięci podręcznej na serwerze produkcyjnym po każdej modyfikacji, włącz tryb deweloperski dla swojego adresu IP w pliku `Bootstrap.php`: + +```php +$this->configurator->setDebugMode('your.ip.address'); +``` + + Jak wyłączyć pamięć podręczną podczas programowania? .[#toc-how-to-disable-cache-during-development] ---------------------------------------------------------------------------------------------------- Nette jest inteligentny i nie trzeba w nim wyłączać buforowania. Podczas programowania automatycznie aktualizuje pamięć podręczną za każdym razem, gdy nastąpi zmiana w szablonie lub konfiguracji kontenera DI. Co więcej, tryb deweloperski jest aktywowany przez automatyczne wykrywanie, więc zwykle nie ma potrzeby konfigurowania czegokolwiek [lub tylko adresu IP |application:bootstrap#development-vs-production-mode]. diff --git a/nette/pt/troubleshooting.texy b/nette/pt/troubleshooting.texy index 9614da9a54..683b090b61 100644 --- a/nette/pt/troubleshooting.texy +++ b/nette/pt/troubleshooting.texy @@ -32,6 +32,17 @@ Erro 404, roteamento não funciona .[#toc-error-404-routing-not-working] Quando todas as páginas (exceto a página inicial) retornam um erro 404, parece um problema de configuração do servidor para [URLs bonitas |#How to Configure a Server for Nice URLs?]. +As alterações nos modelos ou na configuração não são refletidas .[#toc-changes-in-templates-or-configuration-are-not-reflected] +------------------------------------------------------------------------------------------------------------------------------- +"Modifiquei o modelo ou a configuração, mas o site ainda exibe a versão antiga." Esse comportamento ocorre no [modo de produção |application:bootstrap#Development vs Production Mode], que, por motivos de desempenho, não verifica as alterações nos arquivos e mantém um cache gerado anteriormente. + +Para evitar a limpeza manual do cache no servidor de produção após cada modificação, ative o modo de desenvolvimento para seu endereço IP no arquivo `Bootstrap.php`: + +```php +$this->configurator->setDebugMode('your.ip.address'); +``` + + Como desativar o cache durante o desenvolvimento? .[#toc-how-to-disable-cache-during-development] ------------------------------------------------------------------------------------------------- O Nette é inteligente, e você não precisa desativar o cache nele. Durante o desenvolvimento, ele atualiza automaticamente o cache sempre que há uma alteração no modelo ou na configuração do contêiner DI. Além disso, o modo de desenvolvimento é ativado por detecção automática, portanto, normalmente não há necessidade de configurar nada, [ou apenas o endereço IP |application:bootstrap#development-vs-production-mode]. diff --git a/nette/ro/troubleshooting.texy b/nette/ro/troubleshooting.texy index 2435740c53..7cadf25f60 100644 --- a/nette/ro/troubleshooting.texy +++ b/nette/ro/troubleshooting.texy @@ -32,6 +32,17 @@ Eroare 404, rutarea nu funcționează .[#toc-error-404-routing-not-working] Atunci când toate paginile (cu excepția paginii de start) returnează o eroare 404, se pare că este vorba de o problemă de configurare a serverului pentru [URL-urile frumoase |#How to Configure a Server for Nice URLs?]. +Modificările aduse șabloanelor sau configurației nu sunt reflectate .[#toc-changes-in-templates-or-configuration-are-not-reflected] +----------------------------------------------------------------------------------------------------------------------------------- +"Am modificat șablonul sau configurația, dar site-ul afișează în continuare versiunea veche." Acest comportament apare în [modul de producție |application:bootstrap#Development vs Production Mode], care, din motive de performanță, nu verifică modificările fișierelor și menține un cache generat anterior. + +Pentru a evita ștergerea manuală a cache-ului pe serverul de producție după fiecare modificare, activați modul de dezvoltare pentru adresa dvs. de IP în fișierul `Bootstrap.php`: + +```php +$this->configurator->setDebugMode('your.ip.address'); +``` + + Cum se dezactivează memoria cache în timpul dezvoltării? .[#toc-how-to-disable-cache-during-development] -------------------------------------------------------------------------------------------------------- Nette este inteligent și nu este nevoie să dezactivați memoria cache în el. În timpul dezvoltării, acesta actualizează automat memoria cache ori de câte ori există o modificare în șablon sau în configurația containerului DI. Mai mult, modul de dezvoltare este activat prin autodetecție, așa că, de obicei, nu este nevoie să configurați nimic, [sau doar adresa IP |application:bootstrap#development-vs-production-mode]. diff --git a/nette/ru/troubleshooting.texy b/nette/ru/troubleshooting.texy index 4db89b8096..e51812b0ac 100644 --- a/nette/ru/troubleshooting.texy +++ b/nette/ru/troubleshooting.texy @@ -32,6 +32,17 @@ Tracy сообщит, почему он не может вести журнал. Когда все страницы (кроме домашней) выдают ошибку 404, это похоже на проблему конфигурации сервера для [красивых URL |#How to Configure a Server for Nice URLs?]. +Изменения в шаблонах или конфигурации не отражаются .[#toc-changes-in-templates-or-configuration-are-not-reflected] +------------------------------------------------------------------------------------------------------------------- +"Я изменил шаблон или конфигурацию, но на сайте по-прежнему отображается старая версия". Такое поведение наблюдается в [производственном режиме |application:bootstrap#Development vs Production Mode], который по соображениям производительности не проверяет изменения файлов и сохраняет ранее созданный кэш. + +Чтобы не очищать вручную кэш на рабочем сервере после каждой модификации, включите режим разработки для вашего IP-адреса в файле `Bootstrap.php`: + +```php +$this->configurator->setDebugMode('your.ip.address'); +``` + + Как отключить кэш во время разработки? .[#toc-how-to-disable-cache-during-development] -------------------------------------------------------------------------------------- Nette - умный продукт, и отключать кэширование в нем не нужно. Во время разработки он автоматически обновляет кэш при каждом изменении шаблона или конфигурации DI-контейнера. Более того, режим разработки включается по автоопределению, поэтому обычно не требуется ничего настраивать, [или только IP-адрес |application:bootstrap#development-vs-production-mode]. diff --git a/nette/sl/troubleshooting.texy b/nette/sl/troubleshooting.texy index 7cf04d42bf..b123b4a11d 100644 --- a/nette/sl/troubleshooting.texy +++ b/nette/sl/troubleshooting.texy @@ -32,6 +32,17 @@ Napaka 404, usmerjanje ne deluje .[#toc-error-404-routing-not-working] Če vse strani (razen domače strani) vrnejo napako 404, je videti, da gre za težavo s konfiguracijo strežnika za [lepe naslove URL |#How to Configure a Server for Nice URLs?]. +Spremembe v predlogah ali konfiguraciji se ne odražajo .[#toc-changes-in-templates-or-configuration-are-not-reflected] +---------------------------------------------------------------------------------------------------------------------- +"Spremenil sem predlogo ali konfiguracijo, vendar spletna stran še vedno prikazuje staro različico." To vedenje se pojavlja v [produkcijskem načinu |application:bootstrap#Development vs Production Mode], ki zaradi zmogljivosti ne preverja sprememb datotek in ohranja predhodno ustvarjen predpomnilnik. + +Če se želite izogniti ročnemu čiščenju predpomnilnika v produkcijskem strežniku po vsaki spremembi, v datoteki `Bootstrap.php` za svoj naslov IP omogočite razvojni način: + +```php +$this->configurator->setDebugMode('your.ip.address'); +``` + + Kako onemogočiti predpomnilnik med razvojem? .[#toc-how-to-disable-cache-during-development] -------------------------------------------------------------------------------------------- Nette je pameten in v njem vam ni treba onemogočiti predpomnjenja. Med razvojem samodejno posodablja predpomnilnik, kadar koli se spremeni predlogo ali konfiguracija vsebnika DI. Poleg tega se razvojni način aktivira s samodejnim zaznavanjem, zato običajno ni treba nastavljati ničesar [ali le naslova IP |application:bootstrap#development-vs-production-mode]. diff --git a/nette/tr/troubleshooting.texy b/nette/tr/troubleshooting.texy index 5e94434a53..8408992000 100644 --- a/nette/tr/troubleshooting.texy +++ b/nette/tr/troubleshooting.texy @@ -32,6 +32,17 @@ Hata 404, yönlendirme çalışmıyor .[#toc-error-404-routing-not-working] Tüm sayfalar (ana sayfa hariç) 404 hatası döndürdüğünde, [güzel URL' |#How to Configure a Server for Nice URLs?]ler için bir sunucu yapılandırma sorunu gibi görünür. +Şablonlarda veya yapılandırmada yapılan değişiklikler yansıtılmaz .[#toc-changes-in-templates-or-configuration-are-not-reflected] +--------------------------------------------------------------------------------------------------------------------------------- +"Şablonu veya yapılandırmayı değiştirdim, ancak web sitesi hala eski sürümü görüntülüyor." Bu davranış, performans nedenleriyle dosya değişikliklerini kontrol etmeyen ve önceden oluşturulmuş bir önbelleği koruyan [üretim modunda |application:bootstrap#Development vs Production Mode] ortaya çıkar. + +Her değişiklikten sonra üretim sunucusundaki önbelleği manuel olarak temizlemekten kaçınmak için `Bootstrap.php` dosyasında IP adresiniz için geliştirme modunu etkinleştirin: + +```php +$this->configurator->setDebugMode('your.ip.address'); +``` + + Geliştirme Sırasında Önbellek Nasıl Devre Dışı Bırakılır? .[#toc-how-to-disable-cache-during-development] --------------------------------------------------------------------------------------------------------- Nette akıllıdır ve içinde önbelleği devre dışı bırakmanıza gerek yoktur. Geliştirme sırasında, şablonda veya DI konteyner yapılandırmasında bir değişiklik olduğunda önbelleği otomatik olarak günceller. Dahası, geliştirme modu otomatik algılama ile etkinleştirilir, bu nedenle genellikle herhangi bir şeyi [veya yalnızca IP adresini |application:bootstrap#development-vs-production-mode] yapılandırmaya gerek yoktur. diff --git a/nette/uk/troubleshooting.texy b/nette/uk/troubleshooting.texy index 04aa3d523f..aa7dfd114a 100644 --- a/nette/uk/troubleshooting.texy +++ b/nette/uk/troubleshooting.texy @@ -32,6 +32,17 @@ Tracy повідомить вам, чому вона не може вести ж Коли всі сторінки (крім головної) повертають помилку 404, це схоже на проблему конфігурації сервера для [красивих URL-адрес |#How to Configure a Server for Nice URLs?]. +Зміни в шаблонах або конфігурації не відображаються .[#toc-changes-in-templates-or-configuration-are-not-reflected] +------------------------------------------------------------------------------------------------------------------- +"Я змінив шаблон або конфігурацію, але сайт все одно відображає стару версію". Така поведінка виникає у [виробничому режимі |application:bootstrap#Development vs Production Mode], який з міркувань продуктивності не перевіряє зміни файлів і зберігає раніше згенерований кеш. + +Щоб уникнути ручного очищення кешу на робочому сервері після кожної модифікації, увімкніть режим розробки для вашої IP-адреси у файлі `Bootstrap.php`: + +```php +$this->configurator->setDebugMode('your.ip.address'); +``` + + Як відключити кеш під час розробки? .[#toc-how-to-disable-cache-during-development] ----------------------------------------------------------------------------------- Nette розумний, і вам не потрібно відключати кешування в ньому. Під час розробки він автоматично оновлює кеш щоразу, коли змінюється шаблон або конфігурація контейнера DI. Більше того, режим розробки активується за допомогою автоматичного визначення, тому зазвичай не потрібно нічого налаштовувати, окрім [IP-адреси |application:bootstrap#development-vs-production-mode]. From 40b5c1ff3ff29d7bda8aa406f622ab9b8f470c0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Barto=C5=A1?= Date: Sun, 8 Dec 2024 18:22:09 +0100 Subject: [PATCH 5/5] Remove $message parameter from the translate filter $message is the parameter that the filter is called on and can't be passed after a colon as the other parameters. This change is consistent with how the other filters documentation is written. --- latte/en/filters.texy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/latte/en/filters.texy b/latte/en/filters.texy index 7b03a710aa..c255e5634e 100644 --- a/latte/en/filters.texy +++ b/latte/en/filters.texy @@ -815,7 +815,7 @@ Extracts a slice of a string. This filter has been replaced by a [#slice] filter ``` -translate(string $message, ...$args) .[filter] +translate(...$args) .[filter] ---------------------------------------------- It translates expressions into other languages. To make the filter available, you need [set up translator|develop#TranslatorExtension]. You can also use the [tags for translation|tags#Translation].