I den tidigare handledningen täckte vi en handfull koncept, vilka alla kommer att vara nödvändiga för att fullt ut förstå vad vi gör i denna handledning.
Specifikt omfattade vi följande ämnen:
I vissa serier är det lätt att hoppa över tutorials som kanske inte bygger på varandra. Denna serie är dock inte avsedd att vara så. I stället är det meningen att det läses i sekventiell ordning, och det är meningen att man bygger på innehållet i varje tidigare handledning.
Med det sagt antar jag att du är helt upptagen.
Trots att jag kanske har nämnt detta i den första handledningen vill jag fortfarande se till att vi alla är på samma sida med vad vi gör i varje handledning och med vilken programvara du behöver.
Så i denna handledning är planen följande:
I slutändan kommer vi inte att skriva mycket kod i den här handledningen, men vi skriver några. Det är dock en praktisk handledning genom att vi utför objektorienterad analys och design. Detta är en nödvändig fas för många stora projekt (och något som borde hända för småskaliga projekt).
Om du har följt med, borde du redan ha det här. Men för att vara säker, här är den korta versionen av allt du behöver:
Med allt det på plats är vi redo att arbeta med koden som delades i den tidigare handledningen. Så låt oss börja.
Det allra första vi vill göra är att analysera dagens autoloader. Det kan tyckas som mycket kod att klistra in i ett enda kvarter, men det visar sig i sig att vi har lite arbete att göra.
Med det sagt, här är vår autoloader nuvarande tillstånd:
0; $ i--) // Läs nuvarande komponent i fildelen. $ current = strtolower ($ file_parts [$ i]); $ current = str_ireplace ('_', '-', $ current); // Om vi är vid första posten, så är vi på filnamnet. om (count ($ file_parts) - 1 === $ i) / * Om "gränssnitt" finns i delarna av filnamnet, ange sedan $ filnamnet på annat sätt så att det är korrekt laddat. * Annars, sätt bara $ filnamnet lika med klassen * filnamnstruktur. * / if (strpos (strtolower ($ file_parts [count ($ file_parts) - 1]), "gränssnitt")) // Ta gränsens namn från sitt kvalificerade namn. $ interface_name = explodera ('_', $ file_parts [count ($ file_parts) - 1]); $ interface_name = $ interface_name [0]; $ file_name = "interface- $ interface_name.php"; else $ file_name = "class- $ current.php"; annat $ namespace = '/'. $ nuvarande. $ Namespace; // Skapa nu en sökväg till filen med kartläggning till filens plats. $ filepath = trailingslashit (dirname (dirname (__FILE__)). $ namespace); $ filepath. = $ filnamn; // Om filen finns i den angivna sökvägen, ta med den. om (file_exists ($ filepath)) include_once ($ filepath); else wp_die (esc_html ("Filen som försöker laddas till $ filepath existerar inte."));
På den här tiden, kom ihåg att principen om enhetsansvar anger följande:
En klass bör bara ha en anledning att ändra.
Just nu har vi inte ens en klass, än mindre flera individuella metoder som bara har en enda anledning att ändra.
Och även om det kan vara meningsfullt att börja med att bryta denna autoloader-metod i mindre, individuella metoder, låt oss börja från en högre nivå och börja tänka på en autoloader när det gäller ett gränssnitt. Då ska vi borra ner för att skapa en klass (eller klasser).
Minns från tidigare handledning om att ett gränssnitt definieras av PHP-manualen enligt följande:
Objektgränssnitt gör det möjligt att skapa kod som anger vilka metoder en klass måste implementera, utan att behöva definiera hur dessa metoder hanteras.
Med tanke på koden och definitionerna ovan, låt oss tänka på vad en autoloader behöver göra från ett mer modulärt perspektiv. Låt oss i synnerhet bryta ner det i punkter som representerar vad som är tillräckligt för att förändras. Nej, vi får inte använda alla dessa punkter, men det är därför det kallas analys. Vi arbetar senare med designen.
Koden gör följande:
$ class_name
är ett dåligt variabelt namn).Således gör ovanstående kod nio saker-det har det åtminstone Nio skäl att byta - innan det är klart att jobbet fullbordas.
Detta borde vara självklart, men den här funktionen är ett perfekt exempel som vi kan refactor för att demonstrera objektorienterad analys, design, gränssnitt och implementering.
Och det här ställer en fråga: Var börjar vi ens?
Vid det här laget är det rättvist att säga att vi kan börja göra objektorienterad analys, det vill säga se vilka potentiella klasser vi kan ha och hur de interagerar - med tanke på allt vi har listat ovan. Kom ihåg att vi också vill att principen om enansvar att hjälpa oss att styra oss i vårt beslutsfattande.
Vid denna tidpunkt är vi inte hemskt bekymrade över hur klasserna kommer att kommunicera med varandra. I stället är vi mer fokuserade på att skapa klasser som har en enda anledning att ändra.
Med det sagt kommer jag att ge ett urval av klasser som jag tror kan fungera. Innan du går längre, kolla på vad vi har gjort och försök att komma med din egen lista. Då kan vi jämföra anteckningar.
Observera att du kanske har en bättre idé än vad som anges nedan, eller du kan ta bort något från vad vi har delat. Oavsett, det här är en inlärningsövning. Vi försöker förbättra vår kod, vår organisation och i slutändan bli bättre programmerare.
Med tanke på vad jag har listat ovan har jag kommit fram till följande klasser:
Och det är allt. Nu är klasser från tredje part i vårt plugin bara att veta om autoloader-klassen, men autoloadern behöver kunskap om en annan klass, och andra klasser behöver kunskap om ännu andra klasser.
där är sätt att hantera detta (med hjälp av beredningsbehållare, men det ligger utanför ramen för detta projekt). Men vad vi syftar till att göra genom vår kod är att minimera hur många klasser som vet om varandra.
Vid denna tidpunkt kommer olika utvecklare, företag, byråer och team att ta ett annat tillvägagångssätt för hur de utformar det system de arbetar på.
Ett av de vanligaste sätten att gå om att göra detta är att använda något som kallas ett UML-diagram. Även om det är användbart är det inte något som är värt att göra inom ramen för denna handledning eftersom det kommer att kräva en hel annan handledning för att förklara alla bitar.
Så med tanke på vår handledning, och eftersom vi arbetar med så lite kod, försöker vi stubba hur var och en av de ovanstående klasserna kan fungera innan vi implementerar dem. På det här sättet får vi en uppfattning om hur vi kan organisera vår kod.
Observera att vi inte kommer att namnpacing någon av denna kod än, och ingen av denna kod ska implementeras eller testas mot WordPress just än. Vi kommer in i det i nästa handledning.
Låt oss börja med Autoloader
och jobba därifrån.
Kom ihåg att den här klassen är ansvarig för att inkludera den nödvändiga filen. Det här är filen som kommer att registreras hos spl_autoload_register
fungera.
namespace_validator = nytt NamespaceValidator (); $ this-> file_registry = nya FileRegistry (); public function load ($ filnamn) if ($ this-> namespace_validator-> is_valid ($ filnamn)) $ this-> file_registry-> ladda ($ filnamn);
Observera att denna klass beror på NamespaceValidator
och den FileRegistry
klass. Vi kommer att se var och en av dessa mer detaljerat på ett ögonblick.
Den här filen kommer att se på det inkommande filnamnet och avgöra om det är giltigt. Detta görs genom att titta på namnrymden i filnamnet.
Om filen gör i själva verket tillhör vår namnrymd, då kan vi anta att det är säkert att ladda vår fil.
FileInvestigator
Den här klassen gör en hel del arbete, men en del av det görs via mycket enkla, väldigt lilla hjälpar metoder. Under genomförandet ser det på vilken typ av fil den har passerat.
Den hämtar sedan det fullt kvalificerade filnamnet för typen av fil.
get_file_name ($ file_parts, $ current, $ i); om (räkna ($ file_parts) - 1! == $ i) $ filepath = trailingslashit ($ filepath); returnera $ filepath; privat funktion get_file_name ($ file_parts, $ current, $ i) $ filnamn = "; om (räkna ($ file_parts) - 1 === $ i) if ($ this-> is_interface ($ file_parts)) $ filnamn = $ this-> get_interface_name ($ file_parts); annat $ filnamn = $ this-> get_class_name ($ current); annat $ filnamn = $ this-> get_namespace_name ($ current); returnera $ filnamn; privat funktion is_interface ($ file_parts) return strpos (strtolower ($ file_parts [count ($ file_parts) - 1]), 'gränssnitt'); privat funktion get_interface_name ($ file_parts) $ interface_name = explodera ('_' $ file_parts [count ($ file_parts) - 1]); $ interface_name = $ interface_name [0]; returnera "interface- $ interface_name.php"; privat funktion get_class_name ($ current) return "class- $ current.php" ; privat funktion get_namespace_name ($ current) return '/'. $ current;Om det finns en fil som kan refactored lite mer, så är det här. När allt kommer omkring försöker vi bestämma om vi arbetar med en klass, ett gränssnitt eller en klass. En enkel fabrik kan vara bättre lämpad för detta.
När det kommer dags att genomföra vår kod, kanske vi refactor detta vidare. Fram till dess är detta en preliminär design som kan fungera tillräckligt bra.
FileRegistry
Detta kommer att använda den fullt kvalificerade filbanan och inkludera filen; Annars kommer det att använda WordPress API för att visa ett felmeddelande.
klass FileRegistry privat $ investigator; offentlig funktion __construct () $ this-> investigator = ny FileInvestigator (); public function load ($ filepath) $ filepath = $ this-> investigator-> get_filetype ($ filepath); $ filepath = rtrim (plugin_dir_path (dirname (__FILE__)), '/'). $ Filepath; om (file_exists ($ filepath)) include_once ($ filepath); else wp_die (esc_html ('Den angivna filen existerar inte.'));Ett annat alternativ till att använda WordPress API skulle vara att kasta ett anpassat undantagsmeddelande. På det sättet skulle vi kunna helt skilja eller avkalla vår kod från WordPress.
Återigen är denna kod en överföring från den ursprungliga autoloadern. Under genomförandet kan vi också ändra det här.
Slutsats
Okej, så vi har tittat på den befintliga koden för vår autoloader, och sedan har vi stött ut en viss potentiell kod som vi kan använda utifrån en del objektorienterad analys och design.
Är den lösning som vi arbetar mot mer underhållbara än vad vi har? Absolut. Kommer detta att fungera inom ramen för WordPress och vårt befintliga plugin? Vi kommer inte veta förrän vi börjar koppla upp det här till plugin.
Som tidigare nämnts finns det fortfarande vissa områden där vi eventuellt kan refactor denna kod. Om vi träffar dessa typer av problem när vi implementerar vår kod i den slutliga versionen av vårt plugin, tar vi en titt på att göra exakt det.
Oavsett fallet måste koden som vi har nu vara mer läsbar (även om vi fortfarande har DocBlocks och några inline kommentarer att presentera) och mer underhållbara och ännu mer testbara.
Med allt det sagt hoppas jag att detta har gett dig en uppfattning om hur man tar en lång metod och bryter den in i mer ändamålsenliga klasser. Visst, att ha flera klasser kan känna sig konstigt först, men det betyder inte att det är en dålig sak. Har fler filer (och därmed klasser) med mindre kod än en fil med mycket kod är bättre.
Omfatta den motstridiga naturen av objektorienterad programmering i detta avseende. I nästa handledning kommer vi att återvända till vårt plugin och kommer att arbeta för att implementera en variant av koden ovan. Vi kommer sannolikt att felsöka en del av det också. När allt kommer sällan får vi det rätt första gången
Fram till dess, om du är intresserad av att läsa mer om objektorienterad programmering i samband med WordPress, kan du hitta alla mina tidigare handledning på min profilsida. Följ mig på min blogg eller följ mig på Twitter, där jag ofta pratar om båda.
Medel