Wat gezocht naar de rede, want natuurlijk zit er een rede achter. Je mag van me uitgaan dat de PHP FIG zoveel commentaar krijgt dat elk woord een rede heeft, en elke functie in hun code dus al helemaal.
I discovered some oddities with how class_exists() and is_callable()
work when you use fully qualified names; basically, the leading NS
separator results in a false negative lookup (i.e., existing class is
_not_ found). I found that simply doing an ltrim() on the classname as
the first operation in the reference implementation fixes this. This
also means the strripos() operation no longer needs to worry about a
position of 0, either.
[bron]https://groups.google.com/d/msg/php-fig/zaIwMnMQ1_M/N7TXasJ5cyYJ[/bron]
>> Ik heb speciaal voor jou PHP 5.3.0 gecompiled op een virtual machine.
Wow, wat een eer... thanks :-)
Ik heb de test ook bij mij even gedraaid (versie 5.4.10)... en geen slash te bekennen. Ik kan ltrim er dus gewoon uitslopen :-)))
Toevoeging op 13/11/2013 20:42:53:
Nog 1 laatste vraag over PSR-0.
Is het altijd zo dat de "hoofd"-namespace wordt gebruikt voor het laden van classes? Dus stel je wil een prefix instellen die het pad van de library aangeeft, is het dan altijd zo:
<?php
setPrefix('PDF' , '/pad/naar/pdf-library');
setPrefix('PostNL', '/pad/naar/PostNL-library');
// enz.
?>
Of kan het ook zijn dat je een hoofd- en subnamespace moet kunnen instellen?
<?php
setPrefix('PDF\Exceptions' , '/pad/naar/pdf-library/exceptions');
setPrefix('PostNL\betaling', '/pad/naar/PostNL-library/betaling');
?>
Of is dit laatste nooit aan de orde?
Emhe... wat?
Met "hoofd"-namespace bedoel je de actieve namespace?
Of de Fully Qualified Name? (Hoe je de class/interface zou benaderen als je vanaf \ (de global namespace) zou beginnen)
Wat ik bedoel is... je kunt aan je autoloader aangeven waar een bestand staat dat onder een bepaalde namespace valt. Dus stel, je hebt een of andere pdf library en de namespace (of heet dat vendor?) begint altijd met "PDF", dan geef je aan dat als de namespace met PDF begint dat ie het bestand dan moet zoeken in de map '/pad/naar/pdf-library': $autoloader->setPrefix('PDF', '/pad/naar/pdf-library');
Zou het nu ooit zo kunnen zijn dat dit niet enkel gebeurt op basis van de "hoofd"-namespace (vendor?), maar bijv. op basis van hoofdnamespace + subnamespace? Dus dat je zoiets krijgt:
<?php
$autoloader->setPrefix('PDF\Exceptions' , '/pad/naar/pdf-library/exceptions');
$autoloader->setPrefix('PostNL\betaling', '/pad/naar/PostNL-library/betaling');
?>
Ik denk het niet, maar ik vroeg het me dus af.
Toevoeging op 13/11/2013 23:29:24:
>> Ozzie, nee niet alleen beperken tot de hoofdnamespace. Jij bent alles veel te veel aan het beperken, niet doen dat is geen OO.
>> Ach ja, waarom zou je je ook zorgen maken over servers die nog geen 5.4 draaien?
Omdat ik op een eigen server draai misschien? :-s
Toevoeging op 13/11/2013 23:46:26:
@Wouter... er nog even verder over nadenkend... dat kan toch helemaal niet... dat je meer dan 1 namespace gebruikt? Stel je hebt dit:
<?php
$autoloader->setPrefix('PostNL\betaling\generator' , '/pad/naar/PostNL-library/betaling/generators');
?>
En dan wil je bijv. een pakket_code genereren:
<?php
$pakket_code = new PostNL\betaling\generator\pakket_code\nederland;
?>
Dan zou de autoloader nu dus eerst moeten kijken of er een pad is gekoppeld aan de namespace "PostNL". Nee! Volgende controle... is er een pad gekoppeld aan de namespace "PostNL\betaling". Nee, ook niet! Nog een controle: is er een pad gekoppeld aan de namespace "PostNL\betaling\generator". Ja, na 3 pogingen hebben we beet.
Kan aan mij liggen, maar dit is toch niet efficiënt? Of zie ik nu iets over het hoofd?
Kan aan mij liggen, maar dit is toch niet efficiënt? Of zie ik nu iets over het hoofd?
Ja, je ziet één ding over het hoofd: de autoloader zet de namespace-separator \ om in een directory-separator, bijvoorbeeld /, via de PHP-constante DIRECTORY_SEPARATOR. Het bruggetje is een directory- en bestandsstructuur die overeenkomt met de namespace-hiërarchie. Bijvoorbeeld Foo\Bar\Widget wordt gezocht in ../lib/Foo/Bar/Widget.php. Iets anders wil je meestal ook niet, want dan verlies je het overzicht.
Het lieft heb je alles wat de zelfde 'top-level namespace ("Vendor Name")' gebruikt onder de zelfde map staan.
Het hoeft niet. Misschien komt Library A met library B meegeleverd, deze gebruikt XYZ als top-level namespace. Vervolgens gebruik je naar library A ook nog lobrary D die ook XYZ als top-level namespace gebruikt. Dan zal je twee classloaders hebben die maar een deel van de XYZ namespace kunnen laden.
Omdat je niet met libraries wilt knoeien tenzij het echt moet. (Vanwege OCD is geen echte reden.) Laat je het zoals het is en heb je dus twee autoloaders die een top-level namespace delen.
Jij hoeft je in principe alleen zorgen te maken over jouw classes. Third party libraries zullen jouw classloader echt niet gebruiken.
>> Ja, je ziet één ding over het hoofd: de autoloader zet de namespace-separator \ om in een directory-separator, bijvoorbeeld /, via de PHP-constante DIRECTORY_SEPARATOR. Het bruggetje is een directory- en bestandsstructuur die overeenkomt met de namespace-hiërarchie. Bijvoorbeeld Foo\Bar\Widget wordt gezocht in ../lib/Foo/Bar/Widget.php. Iets anders wil je meestal ook niet, want dan verlies je het overzicht.
Dit principe begrijp ik. Maar ik heb m'n autoloader nu zo gemaakt dat ik kan zeggen: als de Vendor Name "Foo" is kijk dan in directory "x". En die directory "x" kan dan zijn wat ik zelf wil. Ik kan dus zeg maar dit doen:
<?php
$autoloader->setNamespacePath('Foo', '/pad/naar/blablabla');
?>
In de praktijk... stel ik zou dus iets met PostNL willen doen, heb ik er dan voldoende aan om de Vendor Name te koppelen aan een directory? Kan ik daar mee uit de voeten:
<?php
$autoloader->setNamespacePath('PostNL', '/pad/naar/postnl-library');
?>
>> Het lieft heb je alles wat de zelfde 'top-level namespace ("Vendor Name")' gebruikt onder de zelfde map staan.
Het hoeft niet. Misschien komt Library A met library B meegeleverd, deze gebruikt XYZ als top-level namespace. Vervolgens gebruik je naar library A ook nog lobrary D die ook XYZ als top-level namespace gebruikt. Dan zal je twee classloaders hebben die maar een deel van de XYZ namespace kunnen laden.
Oke, maar is het dan voldoende als ik met mijn autoloader dit kan doen:
<?php
$autoloader->setNamespacePath('XYZ', '/pad/naar/xyz');
?>
In het voorbeeld van de Symfony class loader zie ik namelijk ook dit:
<?php
$autoloader->setNamespacePath("XYZ\foo", '/pad/naar/xyz/foo');
?>
Hier wordt dus een sub-namespace gebruikt. Heb je dat in de praktijk nodig vraag ik me af. Moet mijn eigen autoloader dat kunnen?
Dan zou ik eens naar de SplClassLoader kijken. Die doet namelijk hetzelfde:
<?php
// Example which loads classes for the Doctrine Common package in the
// Doctrine\Common namespace.
$classLoader = new SplClassLoader('Doctrine\Common', '/path/to/doctrine');
$classLoader->register();
?>
De SplClassLoader heeft ook nog allerlei methoden aan boord om namespaces en packages een aparte behandeling te geven. Denk bijvoorbeeld aan packages die voor klassen de extensie .class of .class.php gebruiken in plaats van .php. Die komen "in het wild" vaker voor dan wij graag zien.