Scriptorama.nl

Header image showing a keyboard, mouse, laptop and books on design patterns

PHP 5.3: Backslash als namespace separator?

Zoals je inmiddels wel gehoord hebt zal PHP 5.3 namespaces introduceren in PHP. Echter, net als de vorige keer (er is voor PHP 5.0 al geprobeerd om namespaces te introduceren), waren er wel de nodige problemen bij deze introductie.

Het grootste probleem was dat de namespace separator, tot voorheen ::, leidt tot ambiguïteit bij aanroepen van functies en statische methodes op klassen. Daarom is er besloten, na veel - heel veel overleg, een nieuw karakter te kiezen als namespace separator, namelijk: een backslash.

Het probleem

Zoals gezegd levert het gebruik van :: (ook wel 'bekend' als T_PAAMAYIM_NEKUDOTAYIM) een lastige situatie op. Neem deze code:

PHP:
  1. namespace scriptorama;
  2. function analyze() { echo 'FUNCTIE'; }
  3.  
  4. class scriptorama {
  5.         public static function analyze() { echo 'STATIC METHODE'; }
  6. }
  7.  
  8. scriptorama::analyze();

Door de manier waarop PHP deze code verwerkt is het niet duidelijk voor PHP of je nu de functie analyze() uit de namespace scriptorama wilt gebruiken, of juist de statische methode analyze() uit de klasse scriptorama.

Vanwege de regels die PHP gebruikte om dit probleem op te lossen betekent dat je in deze context eigenlijk nooit de statische methode analyze op de klasse scriptorama kán aanroepen en dat is een behoorlijke beperking.

De oplossing

De PHP ontwikkelaars hebben er voor gekozen de ambiguiteit op te heffen door een geheel nieuw karakter te kiezen als scheiding tussen de namespace elementen; de backslash. Om de scriptorama::analyze() methode in het vorige voorbeeld aan te roepen zou je dan de volgende code gebruiken:

PHP:
  1. namespace scriptorama;
  2. function analyze() { echo 'FUNCTIE'; }
  3.  
  4. class scriptorama {
  5.         public static function analyze() { echo 'STATIC METHODE'; }
  6. }
  7.  
  8. scriptorama\scriptorama::analyze(); // STATIC METHODE
  9. scriptorama::analyze(); // STATIC METHODE
  10.  
  11. scriptorama\analyze(); // FUNCTIE
  12. analyze(); // FUNCTIE

Teminste, dat denk ik, aangezien het nog niet te testen is. De patch wordt momenteel nog ontwikkeld - met ineenstemming van vrijwel alle ontwikkelaars - en zal binnenkort opgenomen worden in de PHP 5.3 branch.

Het gekozen karakter is volgens de ontwikkelaars een van de mindere kwaden, maar het ziet er wel wat raar uit. Daarbij zijn er wel enkele situaties waarbij het feit dat de backslash gebruikt wordt problematisch kan zijn, bijvoorbeeld waar je een klassenaam in een string als deel van een callback doorgeeft, al is dat wel simpel op te lossen.

De volledige motivatie voor het gebruik van de backslash vind je in de RFC pagina's op de PHP wiki:

Wat denk jij? Rare keuze, of elegante oplossing?

Reageer ook!

Het staat wat raar, maar dat komt wellicht omdat het wat onwennig is. Het is wel een goede oplossing zonder ambiguïteit, dus kom maar op met 5.3 \o/

Het is ongewoon, maar het is niet heel vreemd. Nu lijkt het een bestandspad, waarbij de directories een package zijn en het 'bestand' of laatste element de class is in jouw voorbeeld.
Men had ook de / kunnen gebruiken, meer in url-stijl dus.
zend/soap/server::foo()

Dan krijgt het deelteken 2 betekenissen. Maarja, dan zouden we nooit die verfoeide $ kwijt kunnen raken. Is daar trouwens niet eens over nagedacht?

Het is meerdere malen besproken en alle keren weer afgeschoten. Er is namelijk geen echt voordeel te behalen aan het weghalen van het dollar teken.

En voor het wijzigen van de static method call in:

scriptorama->analyse()

is het te laat...

Het is meerdere malen besproken en alle keren weer afgeschoten. Er is namelijk geen echt voordeel te behalen aan het weghalen van het dollar teken.

Geen voordeel? Ik erger me na jaren coderen nog aan de extra aanslag, die ook nog eens lastig is. shift+4 vereist een behoorlijk gecoördineerde handeling, waarna je al je vingers van de linkerhand moet herpositioneren in de goede positie. De kans op een fout is erg groot:
* #
* capslock + 4
* capslock + 3
* fouten na herpositionering linkerhand.

Is de optie van een punt ook geopperd? Dat lijkt mij namelijk een ideale separator aangezien die ook gebruikt wordt in talen als Java en C#?

En is er misschien ook gekeken naar een meer internationale naam voor T_PAAMAYIM_NEKUDOTAYIM? :)

@Rutger
Ik vind de :: voor statische methodes juist wel fijn. Dan weet je bij de aanroep al dat het om een statische call geaat en je dus geen gebruik kunt maken van properties van het object.

@Timo:

Het is denk ik goed dat een static method call en een normale object method call qua syntax consistent is. Het onderscheid is duidelijk omdat er bij een object instantie een $ voor staat.

De punt word gebruikt als lijm karakter.
'string1'.'string2'.

De keuze van de '\' is wel heel vreemd :|
Het wordt altijd gebruikt als escape teken, (Windows niet maar hé zo is M$).

':::' zou wel een goede zijn.
Dat je een typefout maakt is jouw probleem, je code werkt dan niet naar behoren en dat kan je dan ook oplossen. Hoek vaak je wel niet de fout gemaakt van '=' ipv '=='...

Het dollar teken weglaten geeft een weer een ander probleem! namelijk constants ;)

Ik type gewoon met tien vinger blind, maar ik hou ze niet op de zelfde positie dat is voor mij geen probleem.

:: aan het begin zou ook een oplossing zijn.

Dan heb je probleem met meer vergissing en het duidelijk dat het om een namespace gaat!

He wat is?
Me PHP code is verdwenen!

de c bij list staat voor een class.
http://wiki.phpfreakz.nl/Overzichtelijk_programmeren#Duidelijke_benamingen

OH AGGG IK WORD GEK HIER!!

new ::Rollerscapes::Webhosting::Accounts::cList();

@Sebastiaan: je kunt, als het goed is, [php][/php] gebruiken om je code te laten highlighten.

Het dollar teken weglaten geeft een weer een ander probleem! namelijk constants ;)

Dat is helemaal geen probleem als het goed is. Een constante is een 'final' identifier. In Java gebruik je dan ook static final in de declararatie.

PHP:
  1. define('EEN_CONS', 1);
  2. eenVar = 3;
  3. echo EEN_CONS + eenVar;
  4. EEN_CONS = 4; // <-- error: constante kan niet gewijzigd worden.

een probleem treedt op wanneer je een variabele wilt interpreteren:

PHP:
  1. class Foo () {}
  2. Foo = 6;
  3. obj = new Foo;

Het is een ontwerpfout in php dat een constructor aanroep geen '()' vereist, wat een inconistent is, het is immers een methode.
Een elegante oplossing is om de $ te blijven ondersteunen. Variabelen met een $ worden wel geïnterpreteerd, en variabelen zonder $ niet.

PHP:
  1. class Foo () {}
  2. class Bar () {}
  3. Foo = 'Bar;
  4. obj = new Foo;  // type is Foo
  5. obj = new $Foo; // type is Bar
  6. $declaratieOudeStijl = "werkt ook";
  7. echo declaratieOudeStijl;
  8. echo $declaratieOudeStijl; // zelfde als vorige

Op die manier valt er nog een prestatiewinst te behalen, omdat je van dollarloze variabelen weet dat je ze niet hoeft te interpreteren.

@Alfa: Je vergeet de allerstomste conversie die in PHP zit: Het omzetten van een undefined constant naar een string. :X Voor weak typing en de rest van de conversies is prima het een en ander te zeggen, maar strings kunnen schrijven zonder quotes is echt een hele grote WTF.

@Maarten
Argh ja, wat een kudt-taal is het ook. Nou, dat faseren we dan mooi uit. Geven we voortaan een error, want nu krijg je toch al een notice.

Probleem is dat de mensen die wel kunnen programmeren zich aan moeten passen bij de mensen die 1MB aan E_NOTICE's genereren bij het laden van een simpele pagina.

Waarom in godsnaam een '\' ???

Waarom niet gewoon ::: of : of :> of ><

scriptorama:::scriptorama::analyze();
scriptorama:scriptorama::analyze();
scriptorama:>scriptorama::analyze();
scriptorama><scriptorama::analyze();

Ik zou zelf denken dat :. een goede keuze zou zijn. Het zit dicht bij elkaar op een toetsenbord, het is een nietbestaand token, en het is toch redelijk duidelijk. :)

Het is opzich niet heel raar. In principe kan je bedenken dat namespaces uit een mappenstructuur bestaat. / is het delendoor teken, dus is \ een logisch iets voor een mappenstructuur. Zo moet je namespaces ook bekijken.

@Terence Het probleem is niet dat het raar is, het probleem is dat de \ al in gebruik is binnen dubbel gequote strings.

@RvV: :. is natuurlijk een probleem, weliswaar bestaat :. nog niet, maar : en . afzonderlijk natuurlijk wel.

Kijk eens hier:

define('test',.5);

// Als $a==3, echo 0.5, anders 0.1
echo $a == 3 ? test:.1

Hier staat: test:.1
Op zijn minst verwarrend te noemen. Ik denk niet dat je een klasse, functie, constante ofzo '1' kan noemen, maar als je hier '1' door iets anders vervangt, verandert dus de betekenis van :.

Leave a comment
Line and paragraph breaks automatic, e-mail address never displayed, HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>