Ulepszanie kodu WordPress za pomocą nowoczesnego PHP
Opublikowany: 2022-03-10WordPress narodził się piętnaście lat temu, a ponieważ w przeszłości zachował kompatybilność wsteczną, nowsze wersje jego kodu nie mogły w pełni wykorzystać najnowszych możliwości oferowanych przez nowsze wersje PHP. Podczas gdy najnowsza wersja PHP to 7.3.2, WordPress nadal oferuje wsparcie do PHP 5.2.4.
Ale te dni wkrótce się skończą! WordPress zaktualizuje swoją minimalną obsługę wersji PHP, podskakując do PHP 5.6 w kwietniu 2019 i PHP 7 w grudniu 2019 (jeśli wszystko pójdzie zgodnie z planem). W końcu możemy zacząć korzystać z imperatywnych możliwości programowania PHP bez obawy, że złamiemy strony naszych klientów. Hurra!
Ponieważ piętnaście lat funkcjonalnego kodu WordPressa wpłynęło na sposób, w jaki programiści tworzyli go za pomocą WordPressa, nasze witryny, motywy i wtyczki mogą być zaśmiecone mniej niż optymalnym kodem, który z radością może otrzymać aktualizację.
Ten artykuł składa się z dwóch części:
- Najważniejsze nowe funkcje
Kolejne funkcje zostały dodane do PHP w wersjach 5.3, 5.4, 5.5, 5.6 i 7.0 (zauważ, że nie ma PHP 6) i omówimy te najbardziej odpowiednie. - Budowanie lepszego oprogramowania
Przyjrzymy się bliżej tym funkcjom i temu, jak mogą one pomóc nam w tworzeniu lepszego oprogramowania.
Zacznijmy od zbadania „nowych” funkcji PHP.
Klasy, OOP, SOLID i wzorce projektowe
Klasy i obiekty zostały dodane do PHP 5, więc WordPress korzysta już z tych funkcji, jednak niezbyt obszernie i wszechstronnie: Paradygmat kodowania w WordPressie to głównie programowanie funkcjonalne (wykonywanie obliczeń poprzez wywoływanie funkcji pozbawionych stanu aplikacji) zamiast obiektu programowanie zorientowane (OOP) (wykonywanie obliczeń poprzez manipulowanie stanem obiektów). Dlatego też opisuję klasy i obiekty oraz jak z nich korzystać poprzez OOP.
Programowanie OOP jest idealne do tworzenia aplikacji modułowych: klasy umożliwiają tworzenie komponentów, z których każdy może implementować określoną funkcjonalność i wchodzić w interakcje z innymi komponentami, a także zapewniać dostosowywanie poprzez swoje enkapsulowane właściwości i dziedziczenie, umożliwiając wysoki stopień ponownego wykorzystania kodu. W konsekwencji aplikacja jest tańsza w testowaniu i utrzymaniu, ponieważ poszczególne funkcje można odizolować od aplikacji i zająć się nimi samodzielnie; zwiększa się również produktywność, ponieważ programista może korzystać z już opracowanych komponentów i unikać wymyślania koła na nowo dla każdego zastosowania.
Klasa posiada właściwości i funkcje, którym można nadać widoczność za pomocą private
(dostępne tylko z poziomu klasy definiującej), protected
(dostępne z poziomu klasy definiującej i jej przodków oraz klas dziedziczących) oraz public
(dostępne z dowolnego miejsca). Z poziomu funkcji możemy uzyskać dostęp do właściwości klasy, dodając ich nazwy za pomocą $this->
:
class Person { protected $name; public function __construct($name) { $this->name = $name; } public function getIntroduction() { return sprintf( __('My name is %s'), $this->name ); } }
Klasa jest tworzona w obiekcie za pomocą słowa kluczowego new
, po czym możemy uzyskać dostęp do jej właściwości i funkcji poprzez ->
:
$person = new Person('Pedro'); echo $person->getIntroduction(); // This prints "My name is Pedro"
Klasa dziedzicząca może przesłonić funkcje public
i protected
ze swoich klas przodków i uzyskać dostęp do funkcji przodków, dodając do nich przedrostek parent::
:
class WorkerPerson extends Person { protected $occupation; public function __construct($name, $occupation) { parent::__construct($name); $this->occupation = $occupation; } public function getIntroduction() { return sprintf( __('%s and my occupation is %s'), parent::getIntroduction(), $this->occupation ); } } $worker = new WorkerPerson('Pedro', 'web development'); echo $worker->getIntroduction(); // This prints "My name is Pedro and my occupation is web development"
Metodę można uczynić abstract
, co oznacza, że musi być zaimplementowana przez klasę dziedziczącą. Klasa zawierająca metodę abstract
musi być sama w sobie abstract
, co oznacza, że nie można jej utworzyć; można utworzyć instancję tylko klasy implementującej metodę abstrakcyjną:
abstract class Person { abstract public function getName(); public function getIntroduction() { return sprintf( __('My name is %s'), $this->getName() ); } } // Person cannot be instantiated class Manuel extends Person { public function getName() { return 'Manuel'; } } // Manuel can be instantiated $manuel = new Manuel();
Klasy mogą również definiować static
metody i właściwości, które znajdują się w samej klasie, a nie w instancji klasy jako obiektu. Dostęp do nich uzyskuje się poprzez self::
z wnętrza klasy oraz poprzez nazwę klasy + ::
spoza niej:
class Factory { protected static $instances = []; public static function registerInstance($handle, $instance) { self::$instances[$handle] = $instance; } public static function getInstance($handle) { return self::$instances[$handle]; } } $engine = Factory::getInstance('Engine');
Aby jak najlepiej wykorzystać OOP, możemy użyć zasad SOLID, aby ustanowić solidną, ale łatwo dostosowywalną podstawę dla aplikacji, a także wzorce projektowe, aby rozwiązać określone problemy w wypróbowany i przetestowany sposób. Wzorce projektowe są ustandaryzowane i dobrze udokumentowane, co pozwala programistom zrozumieć, w jaki sposób różne komponenty aplikacji są ze sobą powiązane, i zapewniają sposób uporządkowania aplikacji, co pomaga uniknąć używania zmiennych globalnych (takich jak global $wpdb
) które zanieczyszczają globalne środowisko.
Przestrzenie nazw
Przestrzenie nazw zostały dodane do PHP 5.3, dlatego obecnie nie ma ich w rdzeniu WordPressa.
Przestrzenie nazw umożliwiają strukturalne zorganizowanie bazy kodu, aby uniknąć konfliktów, gdy różne elementy mają tę samą nazwę — w sposób podobny do katalogów systemu operacyjnego, które pozwalają na posiadanie różnych plików o tej samej nazwie, o ile są one przechowywane w różnych katalogach. Przestrzenie nazw wykonują tę samą sztuczkę enkapsulacji dla elementów PHP (takich jak klasy, cechy i interfejsy), unikając kolizji, gdy różne elementy mają tę samą nazwę, umieszczając je w różnych przestrzeniach nazw.
Przestrzenie nazw są koniecznością podczas interakcji z bibliotekami innych firm, ponieważ nie możemy kontrolować, jak ich elementy zostaną nazwane, co prowadzi do potencjalnych kolizji w przypadku używania standardowych nazw, takich jak „Plik”, „Logger” lub „Przesyłający” dla naszych elementów. Co więcej, nawet w ramach jednego projektu przestrzenie nazw zapobiegają nadmiernemu wydłużaniu nazw klas, aby uniknąć kolizji z innymi klasami, co może skutkować nazwami takimi jak „MyProject_Controller_FileUpload”.
Przestrzenie nazw są definiowane przy użyciu słowa kluczowego namespace
(umieszczanego w wierszu zaraz po otwierającym <?php
) i mogą obejmować kilka poziomów lub podprzestrzenie nazw (podobnie do kilku podkatalogów, w których umieszcza się plik), które są oddzielone za pomocą \
:
<?php namespace CoolSoft\ImageResizer\Controllers; class ImageUpload { }
Aby uzyskać dostęp do powyższej klasy, musimy w pełni zakwalifikować jej nazwę, w tym jej przestrzeń nazw (i zaczynając od \
):
$imageUpload = new \CoolSoft\ImageResizer\Controllers\ImageUpload();
Lub możemy również zaimportować klasę do bieżącego kontekstu, po czym możemy bezpośrednio odwołać się do klasy poprzez jej nazwę:
use CoolSoft\ImageResizer\Controllers\ImageUpload; $imageUpload = new ImageUpload();
Nazywając przestrzenie nazw zgodnie z ustalonymi konwencjami, możemy uzyskać dodatkowe korzyści. Na przykład, postępując zgodnie z zaleceniami standardów PHP PSR-4, aplikacja może korzystać z mechanizmu automatycznego ładowania Composera do ładowania plików, zmniejszając w ten sposób złożoność i dodając bezproblemową interoperacyjność między zależnościami. Konwencja ta zakłada uwzględnienie nazwy dostawcy (np. nazwy firmy) jako górnej podprzestrzeni nazw, po której opcjonalnie następuje nazwa pakietu, a dopiero potem wewnętrzna struktura, w której każda podprzestrzeni odpowiada katalogowi o tej samej nazwie. Wynik mapuje od 1 do 1 fizyczną lokalizację pliku na dysku z przestrzenią nazw elementu zdefiniowanego w pliku.
Cechy
Cechy zostały dodane do PHP 5.4, dlatego obecnie nie ma ich w rdzeniu WordPressa.
PHP obsługuje pojedyncze dziedziczenie, więc podklasa pochodzi z jednej klasy nadrzędnej, a nie z wielu. Dlatego klasy, które nie rozciągają się od siebie, nie mogą ponownie używać kodu poprzez dziedziczenie klas. Cechy to mechanizm, który umożliwia horyzontalną kompozycję zachowań, umożliwiając ponowne wykorzystanie kodu pomiędzy klasami, które żyją w różnych hierarchiach klas.
Cecha jest podobna do klasy, jednak nie można jej utworzyć samodzielnie. Zamiast tego kod zdefiniowany wewnątrz cechy można traktować jako „kopiowany i wklejany” do klasy komponowania w czasie kompilacji.
Cecha jest definiowana za pomocą słowa kluczowego trait
, po czym można ją zaimportować do dowolnej klasy za pomocą słowa kluczowego use
. W poniższym przykładzie dwie zupełnie niepowiązane ze sobą klasy Person
i Shop
mogą ponownie wykorzystać ten sam kod poprzez cechę Addressable
:
trait Addressable { protected $address; public function getAddress() { return $this->address; } public function setAddress($address) { $this->address = $address; } } class Person { use Addressable; } class Shop { use Addressable; } $person = new Person('Juan Carlos'); $person->setAddress('Obelisco, Buenos Aires');
Klasa może również składać się z więcej niż jednej cechy:
trait Exportable { public class exportToCSV($filename) { // Iterate all properties and export them to a CSV file } } class Person { use Addressable, Exportable; }
Cechy mogą również składać się z innych cech, definiować metody abstrakcyjne i oferować mechanizm rozwiązywania konfliktów, gdy dwie lub więcej złożonych cech ma między innymi tę samą nazwę funkcji.
Interfejsy
Interfejsy zostały dodane do PHP 5, więc WordPress już korzysta z tej funkcji, jednak niezwykle oszczędnie: rdzeń zawiera łącznie mniej niż dziesięć interfejsów!
Interfejsy umożliwiają tworzenie kodu, który określa, które metody mają zostać zaimplementowane, ale bez konieczności definiowania, w jaki sposób te metody są faktycznie zaimplementowane. Przydają się do definiowania kontraktów między komponentami, co prowadzi do lepszej modułowości i łatwości utrzymania aplikacji: Klasa implementująca interfejs może być czarną skrzynką kodu i dopóki sygnatury funkcji w interfejsie nie ulegną zmianie, kod można dowolnie aktualizować bez wprowadzania istotnych zmian, co może pomóc w zapobieganiu akumulacji długu technicznego. Ponadto mogą pomóc w zmniejszeniu uzależnienia od dostawcy, umożliwiając zamianę implementacji jakiegoś interfejsu na interfejs innego dostawcy. W konsekwencji konieczne jest zakodowanie aplikacji względem interfejsów zamiast implementacji (i definiowanie, które są rzeczywistymi implementacjami poprzez wstrzykiwanie zależności).
Interfejsy są definiowane za pomocą słowa kluczowego interface
i muszą zawierać tylko sygnatury swoich metod (tj. bez definiowania ich zawartości), które muszą mieć widoczność public
(domyślnie brak słowa kluczowego widoczności również czyni je publicznymi):
interface FileStorage { function save($filename, $contents); function readContents($filename); }
Klasa definiuje, że implementuje interfejs za pomocą słowa kluczowego implements
:
class LocalDriveFileStorage implements FileStorage { function save($filename, $contents) { // Implement logic } function readContents($filename) { // Implement logic } }
Klasa może implementować więcej niż jeden interfejs, oddzielając je ,
:
interface AWSService { function getRegion(); } class S3FileStorage implements FileStorage, AWSService { function save($filename, $contents) { // Implement logic } function readContents($filename) { // Implement logic } function getRegion() { return 'us-east-1'; } }
Ponieważ interfejs deklaruje intencję tego, co ma robić komponent, niezwykle ważne jest, aby odpowiednio nazwać interfejsy.
Domknięcia
Zamknięcia zostały dodane do PHP 5.3, dlatego obecnie nie ma ich w rdzeniu WordPressa.
Zamknięcia to mechanizm implementacji funkcji anonimowych, który pomaga oczyścić globalną przestrzeń nazw z funkcji jednorazowych (lub rzadko używanych). Technicznie rzecz biorąc, domknięcia są instancjami klasy Closure
, jednak w praktyce najprawdopodobniej możemy być w błogiej nieświadomości tego faktu bez żadnej szkody.
Przed domknięciami, ilekroć przekazujemy funkcję jako argument do innej funkcji, musieliśmy z góry zdefiniować funkcję i przekazać jej nazwę jako argument:
function duplicate($price) { return $price*2; } $touristPrices = array_map('duplicate', $localPrices);
Przy domknięciach funkcję anonimową (tj. bez nazwy) można już przekazać bezpośrednio jako parametr:
$touristPrices = array_map(function($price) { return $price*2; }, $localPrices);
Zamknięcia mogą importować zmienne do swojego kontekstu za pomocą słowa kluczowego use
:
$factor = 2; $touristPrices = array_map(function($price) use($factor) { return $price*$factor; }, $localPrices);
Generatory
Generatory zostały dodane do PHP 5.5, dlatego obecnie nie ma ich w rdzeniu WordPressa.
Generatory zapewniają łatwy sposób implementacji prostych iteratorów. Generator umożliwia pisanie kodu, który wykorzystuje foreach
do iteracji zestawu danych bez konieczności budowania tablicy w pamięci. Funkcja generatora jest taka sama jak normalna funkcja, z tą różnicą, że zamiast zwracać raz, może yield
tyle razy, ile jest to konieczne, aby dostarczyć wartości, które mają zostać powtórzone.
function xrange($start, $limit, $step = 1) { for ($i = $start; $i <= $limit; $i += $step) { yield $i; } } foreach (xrange(1, 9, 2) as $number) { echo "$number "; } // This prints: 1 3 5 7 9
Deklaracje typu argumentu i zwrotu
W różnych wersjach PHP wprowadzono różne deklaracje typów argumentów: WordPress jest już w stanie deklarować interfejsy i tablice (czego nie robi: ledwo znalazłem jedną instancję funkcji deklarującej tablicę jako parametr w rdzeniu i nie będzie żadnych interfejsów) wkrótce będzie w stanie deklarować callables (dodane w PHP 5.4) i typy skalarne: bool, float, int i string (dodane w PHP 7.0). Deklaracje typu zwrotu zostały dodane do PHP 7.0.
Deklaracje typu argumentu umożliwiają funkcjom deklarowanie, jaki konkretny typ musi być argumentem. Walidacja jest wykonywana w czasie wywołania, zgłaszając wyjątek, jeśli typ argumentu nie jest zadeklarowany. Deklaracje typu zwracanego to ta sama koncepcja, jednak określają typ wartości, która zostanie zwrócona przez funkcję. Deklaracje typu są przydatne, aby ułatwić zrozumienie intencji funkcji i uniknąć błędów środowiska uruchomieniowego związanych z otrzymywaniem lub zwracaniem nieoczekiwanego typu.
Typ argumentu jest deklarowany przed nazwą zmiennej argumentu, a typ zwracany jest deklarowany po argumentach, poprzedzonych :
:
function foo(boolean $bar): int { }
Deklaracje typu argumentów skalarnych mają dwie opcje: przymusową i ścisłą. W trybie przymusu, jeśli niewłaściwy typ zostanie przekazany jako parametr, zostanie on przekonwertowany na właściwy typ. Na przykład funkcja, której podano liczbę całkowitą dla parametru, który oczekuje ciągu, otrzyma zmienną typu ciąg. W trybie ścisłym akceptowana będzie tylko zmienna dokładnego typu deklaracji.

Tryb przymusu jest trybem domyślnym. Aby włączyć tryb ścisły, musimy dodać instrukcję declare
używaną z deklaracją strict_types
:
declare(strict_types=1); function foo(boolean $bar) { }
Nowa składnia i operatory
WordPress może już identyfikować listy argumentów o zmiennej długości za pomocą funkcji func_num_args
. Począwszy od PHP 5.6, możemy użyć tokena ...
do oznaczenia, że funkcja akceptuje zmienną liczbę argumentów, a te argumenty zostaną przekazane do danej zmiennej jako tablica:
function sum(...$numbers) { $sum = 0; foreach ($numbers as $number) { $sum += $number; } return $sum; }
Począwszy od PHP 5.6, stałe mogą zawierać wyrażenia skalarne zawierające literały numeryczne i łańcuchowe zamiast tylko wartości statycznych, a także tablice:
const SUM = 37 + 2; // A scalar expression const LETTERS = ['a', 'b', 'c']; // An array
Począwszy od PHP 7.0, tablice można również definiować za pomocą define
:
define('LETTERS', ['a', 'b', 'c']);
PHP 7.0 dodało kilka nowych operatorów: operator koalescencji Null ( ??
) i operator statku kosmicznego ( <=>
).
Operator koalescencji Null ??
jest cukrem składniowym w powszechnym przypadku konieczności użycia trójskładnika w połączeniu z isset(). Zwraca swój pierwszy operand, jeśli istnieje i nie ma wartości NULL; w przeciwnym razie zwraca drugi operand.
$username = $_GET['user'] ?? 'nobody'; // This is equivalent to: // $username = isset($_GET['user']) ? $_GET['user'] : 'nobody';
Operator statku kosmicznego <=>
jest używany do porównywania dwóch wyrażeń, zwracających -1, 0 lub 1, gdy pierwszy operand jest odpowiednio mniejszy, równy lub większy niż drugi operand.
echo 1 <=> 2; // returns -1 echo 1 <=> 1; // returns 0 echo 2 <=> 1; // returns 1
Oto najważniejsze nowe funkcje dodane do PHP w wersjach od 5.3 do 7.0. Listę dodatkowych nowych funkcji, nie wymienionych w tym artykule, można uzyskać przeglądając dokumentację PHP dotyczącą migracji z wersji na wersję.
Następnie analizujemy, w jaki sposób możemy w pełni wykorzystać wszystkie te nowe funkcje oraz najnowsze trendy w tworzeniu stron internetowych, aby tworzyć lepsze oprogramowanie.
Zalecenia dotyczące standardów PHP
Zalecenia dotyczące standardów PHP zostały stworzone przez grupę programistów PHP z popularnych frameworków i bibliotek, próbując ustalić konwencje, dzięki którym różne projekty mogą być bardziej płynnie integrowane, a różne zespoły mogą lepiej ze sobą współpracować. Rekomendacje nie są statyczne: istniejące rekomendacje mogą być deprecjonowane i w ich miejsce tworzone są nowsze, a nowe są publikowane na bieżąco.
Aktualne zalecenia są następujące:
Grupa | Rekomendacje | Opis |
---|---|---|
Style kodowania Standaryzowane formatowanie zmniejsza tarcia poznawcze podczas czytania kodu od innych autorów | PSR-1 | Podstawowy standard kodowania |
PSR-2 | Przewodnik po stylach kodowania | |
Automatyczne ładowanie Autoloadery eliminują złożoność dołączania plików, mapując przestrzenie nazw na ścieżki systemu plików | PSR-4 | Ulepszone automatyczne ładowanie |
Interfejsy Interfejsy upraszczają udostępnianie kodu między projektami dzięki przestrzeganiu oczekiwanych umów | PSR-3 | Interfejs rejestratora |
PSR-6 | Interfejs buforowania | |
PSR-11 | Interfejs kontenera | |
PSR-13 | Linki hipermedialne | |
PSR-16 | Prosta pamięć podręczna | |
HTTP Interoperacyjne standardy i interfejsy zapewniające niezależne podejście do obsługi żądań i odpowiedzi HTTP, zarówno po stronie klienta, jak i serwera | PSR-7 | Interfejsy wiadomości HTTP |
PSR-15 | Programy obsługi HTTP | |
PSR-17 | Fabryki HTTP | |
PSR-18 | Klient HTTP |
Myśl i koduj w komponentach
Komponenty umożliwiają korzystanie z najlepszych funkcji frameworka bez ograniczania się do samego frameworka. Na przykład Symfony zostało wydane jako zestaw komponentów PHP wielokrotnego użytku, które można zainstalować niezależnie od frameworka Symfony; Laravel, inny framework PHP, korzysta z kilku komponentów Symfony i wydał własny zestaw komponentów wielokrotnego użytku, które mogą być używane w dowolnym projekcie PHP.
Wszystkie te komponenty są publikowane w Packagist, repozytorium publicznych pakietów PHP i można je łatwo dodać do dowolnego projektu PHP za pomocą Composera, niezwykle popularnego menedżera zależności dla PHP.
WordPress powinien być częścią takiego cnotliwego cyklu rozwoju. Niestety sam rdzeń WordPressa nie jest zbudowany przy użyciu komponentów (o czym świadczy niemal całkowity brak interfejsów), a ponadto nie posiada nawet pliku composer.json wymaganego do instalacji WordPressa przez Composer. Dzieje się tak, ponieważ społeczność WordPressa nie uzgodniła, czy WordPress jest zależnością witryny (w takim przypadku instalacja go za pośrednictwem Composera byłaby uzasadniona), czy też jest samą witryną (w takim przypadku Composer może nie być odpowiednim narzędziem do pracy) .
Moim zdaniem, jeśli mamy oczekiwać, że WordPress pozostanie aktualny przez następne piętnaście lat (przynajmniej WordPress jako backend CMS), WordPress musi zostać rozpoznany jako zależność witryny i udostępniony do instalacji przez Composer . Powód jest bardzo prosty: za pomocą zaledwie jednej komendy w terminalu Composer umożliwia zadeklarowanie i zainstalowanie zależności projektu z tysięcy pakietów opublikowanych w Packagist, dzięki czemu możliwe jest tworzenie niezwykle wydajnych aplikacji PHP w krótkim czasie, a programiści uwielbiają pracując w ten sposób. Jeśli WordPress nie dostosuje się do tego modelu, może stracić wsparcie społeczności programistów i odejść w zapomnienie, podobnie jak FTP wypadł z łask po wprowadzeniu wdrożeń opartych na Git.
Twierdzę, że wydanie Gutenberga już pokazuje, że WordPress jest zależnością witryny, a nie samą witryną: Gutenberg traktuje WordPressa jako bezgłowy CMS i może działać również z innymi systemami zaplecza, jak przykłada to Drupal Gutenberg. Dlatego Gutenberg wyjaśnia, że CMS zasilający witrynę może być wymienialny, dlatego należy go traktować jako zależność. Co więcej, sam Gutenberg ma być oparty na komponentach JavaScript wydanych przez npm (jak wyjaśnił główny projektant Adam Silverstein), więc jeśli oczekuje się, że klient WordPress będzie zarządzał swoimi pakietami JavaScript za pomocą menedżera pakietów npm, to dlaczego nie rozszerzyć tej logiki na backend w celu zarządzania zależnościami PHP przez Composer?
Teraz dobra wiadomość: nie trzeba czekać na rozwiązanie tego problemu, ponieważ WordPress można już traktować jako zależność witryny i instalować za pomocą Composera. John P. Bloch wykonał kopię lustrzaną rdzenia WordPressa w Git, dodał plik composer.json i wydał go w Packagist, a Bedrock firmy Roots dostarcza pakiet do instalacji WordPressa z dostosowaną strukturą folderów z obsługą nowoczesnych narzędzi programistycznych i zwiększonym bezpieczeństwem. Tematy i wtyczki są również objęte; tak długo, jak są wymienione w katalogach motywów i wtyczek WordPress, są dostępne w WordPress Packagist.
W związku z tym rozsądną opcją jest tworzenie kodu WordPress nie myśląc o motywach i wtyczkach, ale myśląc w kategoriach komponentów, udostępniając je za pośrednictwem Packagist do wykorzystania przez dowolny projekt PHP, a dodatkowo pakując i udostępniając jako motywy i wtyczki do konkretnego wykorzystania WordPressa. Jeśli komponent musi wchodzić w interakcję z API WordPressa, wtedy te API mogą być umieszczone za interfejsem, który, jeśli zajdzie taka potrzeba, może być zaimplementowany również dla innych CMS-ów.
Dodawanie silnika szablonów w celu ulepszenia warstwy widoku
Jeśli zastosujemy się do rekomendacji myślenia i kodowania w komponentach i potraktujemy WordPressa jako inną niż sama witryna zależność witryny, to nasze projekty mogą wyzwolić się z narzuconych przez WordPress granic i zaimportować pomysły i narzędzia zaczerpnięte z innych frameworków.
Przykładem jest renderowanie treści HTML po stronie serwera, które odbywa się za pomocą zwykłych szablonów PHP. Tę warstwę widoku można ulepszyć za pomocą silników szablonów Twig (firmy Symfony) i Blade (firmy Laravel), które zapewniają bardzo zwięzłą składnię i potężne funkcje, które dają jej przewagę nad zwykłymi szablonami PHP. W szczególności dynamiczne bloki Gutenberga mogą z łatwością korzystać z tych silników szablonów, ponieważ ich proces renderowania kodu HTML bloku po stronie serwera jest oddzielony od architektury hierarchii szablonów WordPressa.
Architekt Aplikacja do użytku ogólnego
Kodowanie względem interfejsów i myślenie w kategoriach komponentów pozwala nam zaprojektować aplikację do ogólnego użytku i dostosować ją do konkretnego zastosowania, które musimy dostarczyć, zamiast kodowania tylko do konkretnego zastosowania w każdym projekcie, który mamy. Mimo że takie podejście jest bardziej kosztowne w krótkim okresie (wymaga dodatkowej pracy), w dłuższej perspektywie opłaca się, gdy dodatkowe projekty mogą być realizowane przy mniejszym wysiłku od dostosowania aplikacji ogólnego użytku.
Aby to podejście było skuteczne, należy wziąć pod uwagę następujące kwestie:
Unikaj stałych zależności (w miarę możliwości)
jQuery i Bootstrap (lub Foundation, lub <–wstaw tutaj swoją ulubioną bibliotekę–> ) mogły być uważane za niezbędne kilka lat temu, jednak stale tracą grunt w stosunku do waniliowego JS i nowszych natywnych funkcji CSS. W związku z tym projekt ogólnego użytku zakodowany pięć lat temu, który zależał od tych bibliotek, może nie być już odpowiedni w dzisiejszych czasach. Stąd, zgodnie z ogólną zasadą, im mniejsza liczba stałych zależności od bibliotek zewnętrznych, tym bardziej będzie ona aktualna w dłuższej perspektywie.
Stopniowe ulepszanie funkcjonalności
WordPress to w pełni rozbudowany system CMS, który obejmuje zarządzanie użytkownikami, stąd wsparcie dla zarządzania użytkownikami jest zawarte w pakiecie. Jednak nie każda witryna WordPress wymaga zarządzania użytkownikami. Dlatego nasza aplikacja powinna to uwzględniać i działać optymalnie w każdym scenariuszu: wspierać zarządzanie użytkownikami, gdy jest to wymagane, ale nie ładować odpowiednich zasobów, gdy nie jest to konieczne. Takie podejście może również działać stopniowo: powiedzmy, że klient wymaga zaimplementowania formularza kontaktowego, ale nie ma budżetu, więc kodujemy go za pomocą bezpłatnej wtyczki z ograniczonymi funkcjami, a inny klient ma budżet na zakup licencji z oferty wtyczek komercyjnych lepsze funkcje. Następnie możemy domyślnie zakodować naszą funkcjonalność do bardzo podstawowej funkcjonalności i coraz częściej korzystać z funkcji tej, która jest najbardziej wydajna z dostępnych w systemie wtyczek.
Ciągły przegląd kodu i dokumentacji
Okresowo przeglądając nasz wcześniej napisany kod i jego dokumentację, możemy sprawdzić, czy jest on aktualny pod kątem nowych konwencji i technologii, a jeśli nie, podjąć działania w celu jego aktualizacji, zanim dług techniczny stanie się zbyt kosztowny do przezwyciężenia i musimy to wszystko zakodować od nowa.
Zalecana lektura : Bądź czujny: funkcje PHP i WordPress, które mogą sprawić, że Twoja witryna stanie się niebezpieczna
Staraj się minimalizować problemy, ale bądź przygotowany, gdy się pojawią
Żadne oprogramowanie nie jest w 100% doskonałe: błędy są zawsze obecne, po prostu jeszcze ich nie znaleźliśmy. W związku z tym musimy upewnić się, że pojawiające się problemy są łatwe do naprawienia.
Uprość to
Złożonego oprogramowania nie można utrzymywać na dłuższą metę: nie tylko dlatego, że inni członkowie zespołu mogą go nie rozumieć, ale także dlatego, że osoba, która je kodowała, może nie rozumieć swojego złożonego kodu kilka lat później. Dlatego tworzenie prostego oprogramowania musi być priorytetem, tym bardziej, że tylko proste oprogramowanie może być poprawne i szybkie.
Błąd podczas kompilacji jest lepszy niż w czasie wykonywania
Jeśli fragment kodu może zostać zweryfikowany pod kątem błędów w czasie kompilacji lub w czasie wykonywania, powinniśmy nadać priorytet rozwiązaniu czasu kompilacji, aby błąd mógł wystąpić i zostać rozwiązany na etapie rozwoju i zanim aplikacja trafi do produkcji. Na przykład zarówno const
, jak i define
są używane do definiowania stałych, jednak podczas gdy const
jest sprawdzane w czasie kompilacji, define
jest sprawdzana w czasie wykonywania. Tak więc, gdy tylko jest to możliwe, używanie const
jest lepsze niż define
.
Zgodnie z tym zaleceniem, podpinanie funkcji WordPressa zawartych w klasach można ulepszyć poprzez przekazanie rzeczywistej klasy jako parametru zamiast ciągu znaków z nazwą klasy. W poniższym przykładzie, jeśli nazwa klasy Foo
zostanie zmieniona, podczas gdy drugie przechwycenie spowoduje błąd kompilacji, pierwsze przechwycenie nie powiedzie się w czasie wykonywania, dlatego drugie przechwycenie jest lepsze:
class Foo { public static function bar() { } } add_action('init', ['Foo', 'bar']); // Not so good add_action('init', [Foo::class, 'bar']); // Much better
Z tego samego powodu, co powyżej, powinniśmy unikać używania zmiennych globalnych (takich jak global $wpdb
): nie tylko zanieczyszczają kontekst globalny i nie są łatwe do wyśledzenia, skąd pochodzą, ale także, jeśli zostaną zmienione, błąd zostanie być produkowane w czasie wykonywania. Jako rozwiązanie możemy użyć Dependency Injection Container, aby uzyskać instancję wymaganego obiektu.
Radzenie sobie z błędami/wyjątkami
Możemy stworzyć architekturę obiektów Exception
, tak aby aplikacja mogła odpowiednio reagować na każdy konkretny problem, aby albo naprawić go, gdy tylko jest to możliwe, albo pokazać użytkownikowi pomocny komunikat o błędzie, gdy nie jest, i ogólnie rejestrować błąd dla administratora, aby rozwiązać problem. I zawsze chroń swoich użytkowników przed białym ekranem śmierci: wszystkie nieprzechwycone Error
i Exception
można przechwycić za pomocą funkcji set_exception_handler
, aby wyświetlić na ekranie nie przerażający komunikat o błędzie.
Zastosuj narzędzia do budowania
Narzędzia do kompilacji mogą zaoszczędzić dużo czasu, automatyzując zadania, których ręczne wykonywanie jest bardzo żmudne. WordPress nie oferuje integracji z żadnym konkretnym narzędziem do budowania, więc zadanie włączenia ich do projektu spadnie całkowicie na programistę.
Istnieją różne narzędzia do realizacji różnych celów. Na przykład istnieją narzędzia do kompilacji do wykonywania zadań związanych z kompresowaniem i zmianą rozmiaru obrazów, minimalizowaniem plików JS i CSS oraz kopiowaniem plików do katalogu w celu stworzenia wydania, takiego jak Webpack, Grunt i Gulp; inne narzędzia pomagają w tworzeniu szkieletu projektu, co jest pomocne przy tworzeniu struktury folderów dla naszych motywów lub wtyczek, takich jak Yeoman. Rzeczywiście, przy tak wielu narzędziach, przeglądanie artykułów porównujących różne dostępne narzędzia pomoże znaleźć najbardziej odpowiednie dla naszych potrzeb.
Jednak w niektórych przypadkach nie ma narzędzi do kompilacji, które mogą osiągnąć dokładnie to, czego potrzebuje nasz projekt, więc może być konieczne zakodowanie własnego narzędzia do kompilacji jako rozszerzenia samego projektu. Na przykład zrobiłem to, aby wygenerować plik service-worker.js, aby dodać obsługę Service Workers w WordPress.
Wniosek
Ze względu na duży nacisk na zachowanie kompatybilności wstecznej, rozszerzonej nawet do PHP 5.2.4, WordPress nie był w stanie korzystać z najnowszych funkcji dodanych do PHP, co sprawiło, że WordPress stał się niezbyt ekscytującą platformą do kodowania dla wielu programistów.
Na szczęście te ponure dni mogą wkrótce się skończyć, a WordPress może ponownie stać się błyszczącą i ekscytującą platformą do programowania: Wymagania PHP 7.0+ od grudnia 2019 r. udostępnią wiele funkcji PHP, umożliwiając programistom tworzenie wydajniejszych i wydajniejszych bardziej wydajne oprogramowanie. W tym artykule omówiliśmy najważniejsze nowo dostępne funkcje PHP i dowiedzieliśmy się, jak najlepiej je wykorzystać.
Niedawne wydanie Gutenberga może być oznaką nadchodzących dobrych czasów: nawet jeśli sam Gutenberg nie został w pełni zaakceptowany przez społeczność, przynajmniej pokazuje chęć włączenia najnowszych technologii (takich jak React i Webpack) do rdzenia . Ten obrót wydarzeń sprawia, że zastanawiam się: jeśli frontend może uzyskać taką metamorfozę, dlaczego nie rozszerzyć go na backend? Gdy WordPress wymaga co najmniej PHP 7.0, uaktualnienie do nowoczesnych narzędzi i metodologii może przyspieszyć: o ile npm stał się wybranym menedżerem pakietów JavaScript, dlaczego nie sprawić, by Composer stał się oficjalnym menedżerem zależności PHP? Jeśli bloki są nową jednostką do budowania witryn we frontendzie, dlaczego nie użyć komponentów PHP jako jednostki do włączania funkcjonalności do backendu? I wreszcie, jeśli Gutenberg traktuje WordPressa jako wymienny backendowy CMS, dlaczego nie rozpoznać, że WordPress jest zależnością witryny, a nie samą witryną? Zostawię te otwarte pytania do zastanowienia się i zastanowienia.