Door
Ozzie PHP
op 30-12-2010 16:10
gewijzigd op 06-01-2011 13:17
50.697 views
Hmmm, laat ik de vraag toch maar eens stellen. Ik wil graag een eigen framework / beheersysteem maken. De bedoeling is dat ik als het systeem klaar is heel makkelijk een website kan maken waar meteen al een standaard cms gedeelte in zit.
Ik ben al begonnen met een framework en ik maak daarbij gebruik van Zend Framework, maar nu vraag ik me het volgende af. Ik heb behoorlijk wat PHP kennis en ervaring inmiddels, maar ik heb hier geen opleiding voor gehad. Ik wil het mezelf dan ook altijd zo makkelijk mogelijk maken als ik aan het programmeren ben. Voorbeeld, als ik een databasequery wil uitvoeren dan wil ik niet een hele query in te hoeven typen, maar wil ik simpele functies kunnen gebruiken, bijvoorbeeld: $database->setTable('tabel') en $row = $database->select('naam') etc.
Ook vind ik het handig dat ik in Zend Framework een route makkelijk kan koppelen aan een controller en een actie. Daarnaast gebruik ik de MVC structuur (modules), de Zend_Registry functie om iets op te slaan en gebruik ik de caching functie voor het cachen van gegevens.
Ik gebruik Zend Framework dus voornamelijk voor:
- maken van mooie routes
- routes koppelen aan controller en actie
- MVC structuur (modules)
- Zend_Registry om variabelen op te slaan
- Caching
Voor de rest gebruik in Zend Framework eigenlijk niet. Ik weet dat er heeeel veel mogelijkheden in Zend Framework zitten, maar ik ben niet iemand die dat allemaal wil uitvogelen, en ik wil toch altijd graag mijn eigen code schrijven zodat ik precies weet wat de code doet en hoe deze in elkaar zit (zodat het voor mijzelf logisch is en makkelijk te gebruiken).
Nu vraag ik me 2 dingen af:
1) is het voor mij eigenlijk wel zinvol om Zend Framework te gebruiken aagezien ik er niet heel veel mogelijkheden van benut.
2) zijn de 5 functies waar ik gebruik van maak (makkelijk) ook zelf te maken of is dat heel erg ingewikkeld?
Wat raden jullie aan? Zend Framework blijven gebruiken ook al gebruik ik er maar weinig van? Of toch zelf mijn eigen functies maken en Zend Framework niet meer gebruiken? Ik stel deze vraag ook omdat Zend Framework zo'n 23mb aan serverruimte in beslag neemt.
Thanks Jelmer... hoe jij die database omschrijft "net niet helemaal singleton maken, zodat je en de default instantie hebt, en je nog eigen instanties kan maken" zo heb ik 'm laatst eens gemaakt :))))
In welke gevallen gebruik je een interface als ik vragen mag? Toch niet overal neem ik aan?
In welke gevallen gebruik je een interface als ik vragen mag? Toch niet overal neem ik aan?
Ik doe het zelf eigenlijk alleen als ik een functie/method maak die een bepaald object als argument accepteert, en dan verwacht dat dat object een bepaalde method heeft. Of, en dat komt bij mij in de praktijk vaker voor, die de interface gebruikt om te kijken of het object bepaalde features ondersteunt.
Voorbeeldje: een method die een willekeurig object naar HTML kan omzetten. Maar sommige objecten kunnen dat zelf beter, dus die mogen het dan zelf doen.
<?php
interface HTMLExporter {
public function asHTML();
}
class Color implements HTMLExporter
{
public function asHTML()
{
return sprintf('#%02x%02x%02x', $this->red, $this->green, $this->blue);
}
}
class String implements HTMLExporter
{
public function asHTML()
{
return htmlspecialchars($this->chars, ENT_COMPAT, $this->encoding);
}
}
class Registery
{
// dit ding omzetten naar HTML heeft geen zin, dus niet geïmplementeerd.
}
function printHTML(HTMLExporter $object)
{
echo $object->asHTML();
}
?>
Een instantie van Registery kan je niet aan printHTML geven, Color en String wel. Maar dit voorbeeld is wat te gestript om nuttig te zijn. Je komt het later vast nog wel eens tegen, het is iets waar je je in je begintijd van OOP nog niet druk over hoeft te maken.
Interfaces hebben in PHP sowieso niet veel toegevoegde waarde aangezien ze pas bij runtime worden gecontroleerd (in tegenstelling tot bijv. C++) en je net zo goed van ducktyping* kan uitgaan, aangezien dat ook wel een fout genereert tijdens runtime.
* ducktyping is dat het PHP niet uitmaakt wat voor object het is, zolang het maar werkt. If it walks like a duck and quacks like a duck, it is a duck. In C++ e.d. heb je dat niet omdat je daar nog met allemaal geheugendingen zit, en een hele (heerlijk) strenge compiler.
Begin eerst maar eens, en maak er tegelijkertijd een simpele website mee zodat je direct ziet wat je allemaal nog mist. Een weblog of een simpel forum, iets met database en formulieren en een-op-meer relaties.
Andere dingen die handig zijn:
Helaas, geen design patterns of architectures, maar gewoon ouderwetse tips voor programmeren. Want zeker bij een framework zijn die dodelijk essentieel.
- duidelijke variabelenamen. Dingen als $counter zijn niet duidelijk, want wat telt die $counter dan? Je kan hele mooie code schrijven, maar als niemand begrijpt wat er staat gaat niemand het gebruiken, inclusief jijzelf over een jaar.
- begin simpel. KISS. Implementeer pas iets als je merkt dat je het nodig hebt, en wees hier heel strikt in. Aanpassen voor andere doeleinden, features implementeren die je voor een andere site nodig zou kunnen hebben kan altijd nog. Het beste framework heeft niet meer features dan anderen, maar het beste framework lost jou probleem het gemakkelijkst en mooist op.
Mooi gezegd... maar dat is gelijk ook een beetje mijn valkuil... omdat ik bepaalde dingen niet weet, los ik ze op m'n eigen manier op... terwijl daar misschien betere design patterns voor zijn. Maar ja, wat is goed en wat is slecht.
Voorbeeld... als een class maar 1 keer mag worden aangemaakt, dan kun je singleton toepassen, maar volgens mij kijkt die bij iedere aanroep van de class of de instantie al een keer is aangemaakt. Stel dat je een of andere config class hebt die per pagina aanroep misschien wel 15 keer op verscihllende plekken wordt gebruikt, dan betekent dit dat die controle of die instantie bestaat ook 15 keer wordt uitgevoerd. Niet goed voor je performance lijkt me. Dus wat had ik gedaan... per pagina request wordt de betreffende class 1x geset en kun je de class aanspreken met get(). Als je probeert een nieuwe class aan te maken, dan werd een functie aangeroepen die een exception gooit waarin staat dat je die class alleen met get() kunt verkrijgen. Het werkt prima, maar of dit de juiste manier is...... ???????? Maar het werkt dus wel heel makkelijk, want als je de class nodig hebt gebruik je altijd get, er hoeft geen controle te worden gedaan omdat de instantie altijd geset is. Een nieuwe class aanmaken gaat niet, want dan krijg je een exception.
Dat is een oplossing, en alleen het (vind ik sterke) argument tegen static methods gebruiken blijft over: Je class die die X::get() aanroept is direct en onlosmakelijk gekoppeld aan X. Er is geen mogelijkheid om X te vervangen door een andere class. En dat is nu juist een van de eigenschappen van objecten, dat je het ene object zo in kan wisselen voor een ander object, zolang de public interface maar hetzelfde is.
Maar dit is maar een relatief klein probleem waar je tegenaan gaat lopen, er zijn nog veel grotere zodra je probeert daadwerkelijk iets werkends te maken.
Hoe bedoel je dat je X niet kunt vervangen? Stel je roept in een class de database aan met Database::get() en nu wil je de database class vervangen... dan kun je de huidige database class toch vervangen door een andere? Of bedoel jij iets anders (misschien een code voorbeeldje?)
Je kan de code van de class Database veranderen, maar je kan niet in plaats van Database plotseling Database2, of TestDatabase gebruiken zonder alle code die verwijst naar Database aan te passen. Of je moet heel Database uit je code te gooien en daarvoor TestDatabase in de plaats zetten, en die dan hernoemen naar Database.
Stel dat je zo'n dependency injection container gebruikt, dan kan je ergens in een bestandje waar je de container opbouwt zeggen dat Container::get('database') niet een Database object teruggeeft, maar een TestDatabase. Je kan er zelfs een if-else statement omheen bouwen. IF dit-is-mijn-localhost THEN TestDatabase ELSE Database.
Ah oke, op die manier. Ik snap ongeveer wat je bedoelt nu. Maar wel lastig om dat allemaal in elkaar te zetten denk ik :) Ben er wel even zoet mee vrees ik...
1) MVC framework link
2) Router vervangen door betere versielink
3) Database active record link
4) method chaining $this->db->select('title')->from('mytable')->where('id', $id)->limit(10, 20);
5) Lazy registreren objecten link
Wat moet er nog bij?
Om op je lijstje terug te komen:
2 is geen betere router... (Die in de comments wel ;) )
5 vind ik niet zo sterk, omdat je bij de configuratie van de te lazy-loaden objecten geen methode op kan geven die bij het maken aangeroepen moet worden. Ook heeft het geen mooie interface om te kunnen configureren, omdat je niet mooi data uit dezelfde registry/container kan halen. Kijk toch eens naar Pimple.
Een voorbeeld van wat wel kan met zo'n container, maar niet met de door jou genoemde registry:
<?php
$c = new Container();