Namespaces en dynamische classname

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Erwin H

Erwin H

04/08/2014 04:43:26
Quote Anchor link
Van het weekend probeerde ik een class aan te maken met een dynamische classname en opeens kwam ik tot de ontdekking dat dat niet helemaal werkte zoals ik had verwacht.

De sitatuatie is dat ik een factory class heb in de namespace 'API'. In de namespace 'API\Flickr' heb ik een class met de naam Datamapper (volledig dus \API\Flickr\Datamapper). Nu heb ik de volgende situaties geprobeerd en het verbaasde me dat de de tweede niet werkt:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
//code dus in de factory \API\Factory die \API\Flickr\Datamapper moet aanmaken

//direct aanmaken, werkt

$obj = new Flickr\Datamapper()

//met een dynamische naam, werkt niet
$classname = 'Flickr\\Datamapper';
$obj = new $classname();

//dynamische naam met volledige namespace, werkt wel
$classname = '\\API\\Flickr\\Datamapper';
$obj = new $classname();
?>

Kan iemand mij uitleggen waarom de tweede optie met relatieve namespace niet werkt, terwijl het wel werkt als de classname niet dynamisch is?
 
PHP hulp

PHP hulp

27/11/2024 05:19:18
 
Ward van der Put
Moderator

Ward van der Put

04/08/2014 07:22:36
Quote Anchor link
Waarom werkt de eerste wel?

We missen hier wat context, aangezien de eerste onder normale omstandigheden in een "Fatal error: Class 'Flickr\Datamapper' not found" zou moeten stranden.
 
Erwin H

Erwin H

04/08/2014 09:05:18
Quote Anchor link
Serieus? Enige wat ik daarop kan zeggen is dat de eerste wel werkt, waarschijnlijk omdat dat wordt opgelost in mijn autoloader (?).

Mijn namespace kennis is nog vrij pril, dus wellicht dat ik nog gewoon wat kennis mis. Maar als ik het goed begrijp is de classname Flickr\Datamapper een relatieve namespace tov de factory waarin die wordt aangemaakt en is de absolute namespace dan \API\Flickr. Mijn autoloader krijgt dus als naam door \API\Flickr\Datamapper en vertaalt dat naar een pad waarin het bestand gevonden kan worden met de Datamapper class. Tot zover werkt het in elk geval en mijn veronderstelling was dat dat ook zou moeten werken met een dynamische classname.
 
Ward van der Put
Moderator

Ward van der Put

04/08/2014 09:47:25
Quote Anchor link
Het lijkt me een kleinigheid. Als je $classname = 'Flickr\\Datamapper' inkort tot $classname = 'Flickr\Datamapper' met één backslash, dan werkt het wel:

http://3v4l.org/oi8Ld
 
Erwin H

Erwin H

04/08/2014 10:09:50
Quote Anchor link
Nope. Dan krijg ik dus de foutmelding: "Fatal error: Class 'Flickr\Datamapper' not found"
 
Ward van der Put
Moderator

Ward van der Put

04/08/2014 10:23:02
Quote Anchor link
Dat is inderdaad raar: waarom vindt je autoloader de eerste wel maar de (gelijknamige) tweede niet?
 
Erwin H

Erwin H

04/08/2014 10:31:38
Quote Anchor link
Daar zeg je me wat, even de autoloader de classnames laten printen die hij doorkrijgt. Bij de eerste optie krijgt hij door '\API\Flickr\Datamapper', dus inclusief volledige namespace. Bij de tweede optie krijgt hij door 'Flickr\Datamapper', dus dan wordt de namespace blijkbaar niet aangevuld.
 
A Vreugdenhil

A Vreugdenhil

07/08/2014 16:43:14
Quote Anchor link
Het komt doordat de dynamische versie (blijkbaar) buiten de huidige scope uitgevoerd wordt, oftewel in de globale scope.
Oftewel de huidige namespace en eventuele uses worden genegeerd.
 
Erwin H

Erwin H

07/08/2014 17:25:15
Quote Anchor link
Had hier alweer een reply op gedicht.... maar die is verdwenen. Nog een keer dan :-)

Het lijkt er inderdaad op dat de huidige namespace in zo'n situatie niet meegenomen wordt. Vraag blijft bij mij wel staan waarom.
Oplossing is er op zich wel, zoals gemeld in de eerst post, door gewoon de volledige namespace op te geven. Nog ietsje mooier wat mij betreft kwam ik net achter, ik kan de huidige namespace er ook voorzetten via de __NAMESPACE__ constante. Dus dan krijg ik dit:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
<?php
$classname
= __NAMESPACE__.'\\Flickr\\Datamapper';
$obj = new $classname();
?>

Dit werkt ook en vind ik op het moment de best werkbare oplossing.
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.