namespaces
Pagina: « vorige 1 2 3 4 volgende »
Wouter J op 12/11/2013 19:11:35:
Natuurlijk optie B. Daardoor kun je makkelijk en snel het namespace aanpassen en kun je gaan aliasen.
Optie B is echt de best practise.
Optie B is echt de best practise.
Waarom is B de best practice? Ik zou in dit voorbeeld explicieter Foo\Bar als sub-namespace gebruiken en use specifieker richten op de daaruit gebruikte klasse. Of zie ik het verkeerd?
Ward, wat bedoel je?
namespace Foo;
use Bar\Test;
ten opzichte van (alternatief C):
namespace Foo\Bar;
use Test;
Gewoon een vraag. Ik ben geneigd de tweede te gebruiken als je enkel in de sub-namespace opereert, zoals in het voorbeeld van Ozzie het geval was.
namespace Foo;
use Bar\Test;
Betekend niet dat je Foo\Bar\Test krijgt, maar Bar\Test.
Ten tweede, de namespace zegt iets over de plek van de huidige code. De use zegt iets over de namespace van de klasse die je gebruikt.
Een real live voorbeeldje, je hebt een HTML tree met nodes erin:
Code (php)
Dit ga ik natuurlijk niet veranderen naar:
Code (php)
Want nu zit het HtmlTree object ineens in de Ozzie\Core\Tree\Node namespace, waar die helemaal niet thuis hoort.
Gewijzigd op 13/11/2013 10:41:44 door Wouter J
Daarom zou ik bij het voorbeeld van Ozzie zeggen: als Foo\Bar\FooBar de klasse Foo\Bar\Test gebruikt, delen ze de sub-namespace Foo\Bar. Toch?
Ja, dat klopt. Dan wordt in de meeste OSS projects geen use statement gebruikt (zelfde voor global PHP classes)
Zoals je in mijn voorbeeld kunt zien is er sprake van 2 verschillende namespaces (Foo waarin class Foobar zich bevindt, en Bar waarin class Test zich bevindt). Er worden dus geen namespaces gedeeld. Is optie B dan nog steeds de beste keuze?
Optie A:
Code (php)
Optie B:
Met de namespace 'Bar' en wanneer je Bar\Test maar een keer gebruikt kan je net zo goed new \Bar\Test() gebruiken.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?php
namespace Foo\Bar\Meow\Woof;
class Test {
public function meow(\Organism\Animal\Mammal\Feline\Cat $cat) {
$cat->feed();
}
public function woof(\Organism\Animal\Mammal\Canine $dog) {
$dog->feed();
}
}
// Versus
namespace Foo\Bar\Meow\Woof;
use Organism\Animal\Mammal;
class Test {
public function meow(Mammal\Feline\Cat $cat) {
$cat->feed();
}
public function woof(Mammal\Canine\Dog $dog) {
$dog->feed();
}
}
// Versus
namespace Foo\Bar\Meow\Woof;
use Organism\Animal\Mammal\Feline\Cat;
use Organism\Animal\Mammal\Canine\Dog;
class Test {
public function meow(Cat $cat) {
$cat->feed();
}
public function woof(Dog $dog) {
$dog->feed();
}
}
?>
namespace Foo\Bar\Meow\Woof;
class Test {
public function meow(\Organism\Animal\Mammal\Feline\Cat $cat) {
$cat->feed();
}
public function woof(\Organism\Animal\Mammal\Canine $dog) {
$dog->feed();
}
}
// Versus
namespace Foo\Bar\Meow\Woof;
use Organism\Animal\Mammal;
class Test {
public function meow(Mammal\Feline\Cat $cat) {
$cat->feed();
}
public function woof(Mammal\Canine\Dog $dog) {
$dog->feed();
}
}
// Versus
namespace Foo\Bar\Meow\Woof;
use Organism\Animal\Mammal\Feline\Cat;
use Organism\Animal\Mammal\Canine\Dog;
class Test {
public function meow(Cat $cat) {
$cat->feed();
}
public function woof(Dog $dog) {
$dog->feed();
}
}
?>
Gewijzigd op 13/11/2013 14:10:17 door Dos Moonen
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
function autoload($className)
{
$className = ltrim($className, '\\');
$fileName = '';
$namespace = '';
if ($lastNsPos = strrpos($className, '\\')) {
$namespace = substr($className, 0, $lastNsPos);
$className = substr($className, $lastNsPos + 1);
$fileName = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
}
$fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
require $fileName;
}
?>
function autoload($className)
{
$className = ltrim($className, '\\');
$fileName = '';
$namespace = '';
if ($lastNsPos = strrpos($className, '\\')) {
$namespace = substr($className, 0, $lastNsPos);
$className = substr($className, $lastNsPos + 1);
$fileName = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
}
$fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
require $fileName;
}
?>
Ward, jij gebruikt deze versie volgens mij ook.
Nu mijn vraag. De allereerste regel van deze method is:
Die regel staat daar blijkbaar met een reden... maar wie vertelt mij waarom? Aangezien het een autoload functie betreft, wordt deze nooit handmatig aangeroepen. Nu heb ik eens verschillende manieren getest om een class in te laden, dus met de complete class-naam en door "use" te gebruiken. In geen enkel geval krijg ik het voor elkaar dat de variabele $className met een backslash begint. Waarom wordt die dan toch getrimd? Kan iemand dat uitleggen? Ward misschien, aangezien jij het ook in jouw autoload method gebruikt?
@Dos:
>> Met de namespace 'Bar' en wanneer je Bar\Test maar een keer gebruikt kan je net zo goed new \Bar\Test() gebruiken.
Jawel, dat kan... je zou echter ook kunnen zeggen dat je door "use" te gebruiken meteen kunt zien wat voor "vreemde" (niet tot de namespace behorende) classes er in je code aanwezig zijn.
Het verschil tussen versie 2 en 3 is ook wel grappig inderdaad. Ik denk dat ik toch voor de laatste variant dan zou gaan, omdat je dan specifieker weet om welke classes het gaat. Van de andere kant... stel dat je 20 classes uit die namespace zou gebruiken, dan moet je 20x "use" gebruiken??? Ward en Wouter, welke versie van Dos zouden jullie gebruiken. De 2e of de 3e?
Gewijzigd op 13/11/2013 14:25:48 door Ozzie PHP
Ozzie PHP op 13/11/2013 14:22:57:
In geen enkel geval krijg ik het voor elkaar dat de variabele $className met een backslash begint. Waarom wordt die dan toch getrimd? Kan iemand dat uitleggen? Ward misschien, aangezien jij het ook in jouw autoload method gebruikt?
Ik vermoed dat het met unserialize() mogelijk is. Ergens tussen 5.3 en de huidige versies is support voor FQNS's toegevoegd geloof ik. Dus als je een up-to-date PHP versie hebt zou je het weg kunnen halen. Maar laat het er in zitten voor backwards compatibility.
Ozzie PHP op 13/11/2013 14:22:57:
@Dos:
>> Met de namespace 'Bar' en wanneer je Bar\Test maar een keer gebruikt kan je net zo goed new \Bar\Test() gebruiken.
Jawel, dat kan... je zou echter ook kunnen zeggen dat je door "use" te gebruiken meteen kunt zien wat voor "vreemde" (niet tot de namespace behorende) classes er in je code aanwezig zijn.
Het verschil tussen versie 2 en 3 is ook wel grappig inderdaad. Ik denk dat ik toch voor de laatste variant dan zou gaan, omdat je dan specifieker weet om welke classes het gaat. Van de andere kant... stel dat je 20 classes uit die namespace zou gebruiken, dan moet je 20x "use" gebruiken??? Ward en Wouter, welke versie van Dos zouden jullie gebruiken. De 2e of de 3e?
>> Met de namespace 'Bar' en wanneer je Bar\Test maar een keer gebruikt kan je net zo goed new \Bar\Test() gebruiken.
Jawel, dat kan... je zou echter ook kunnen zeggen dat je door "use" te gebruiken meteen kunt zien wat voor "vreemde" (niet tot de namespace behorende) classes er in je code aanwezig zijn.
Het verschil tussen versie 2 en 3 is ook wel grappig inderdaad. Ik denk dat ik toch voor de laatste variant dan zou gaan, omdat je dan specifieker weet om welke classes het gaat. Van de andere kant... stel dat je 20 classes uit die namespace zou gebruiken, dan moet je 20x "use" gebruiken??? Ward en Wouter, welke versie van Dos zouden jullie gebruiken. De 2e of de 3e?
Je kunt 2 en 3 combineren en je code leesbaar houden.
Ah, oké. Dan laat ik het erin staan.
>> Je kunt 2 en 3 combineren en je code leesbaar houden.
Zoiets bedoel je?
Code (php)
Klopt dit eigenlijk wel? Ik heb jouw 2e voorbeeld gepakt en in de code "Feline\Cat" gebruikt ipv "Mammal\Feline\Cat". Maar misschien doe ik nu iets verkeerd.
Code (php)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
<?php
// (a) Niks autoloader, we gebruiken Exception van PHP:
namespace Foo;
throw new \Exception();
// (b) Via de autoloader laden we Foo\Exception in ../lib/Foo/Exception.php:
namespace Foo;
throw new Exception();
?>
// (a) Niks autoloader, we gebruiken Exception van PHP:
namespace Foo;
throw new \Exception();
// (b) Via de autoloader laden we Foo\Exception in ../lib/Foo/Exception.php:
namespace Foo;
throw new Exception();
?>
Met andere woorden: de autoloader mag geen klassen die met \ beginnen laden, want dat is het domein van PHP. En vice versa: als de autoloader aan bod komt, moet die een van onze eigen klassen laden, geen klasse van PHP.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
use Organism\Animal\Mammal;
// Is de kortere versie van
use Organism\Animal\Mammal as Mammal;
// Als er een class Mammal bestaat in de namespace \Organism\Animal dan werkt het volgende:
$mammal = new Mammal; // er vanuitgaant dat het geen abstracte class is :p
// Als er een class Feline bestaat in de namespace \Organism\Animal\Mammal dan werkt het volgende:
$feline = new Mammal\Feline;
$feline = new \Organism\Animal\Mammal\Feline; // de eerste \ hoeft niet ZOLANG je niets als 'Organism' aliased. OK, behalve \Organism maar ik zou niet weten waarom je dat zou doen.
?>
use Organism\Animal\Mammal;
// Is de kortere versie van
use Organism\Animal\Mammal as Mammal;
// Als er een class Mammal bestaat in de namespace \Organism\Animal dan werkt het volgende:
$mammal = new Mammal; // er vanuitgaant dat het geen abstracte class is :p
// Als er een class Feline bestaat in de namespace \Organism\Animal\Mammal dan werkt het volgende:
$feline = new Mammal\Feline;
$feline = new \Organism\Animal\Mammal\Feline; // de eerste \ hoeft niet ZOLANG je niets als 'Organism' aliased. OK, behalve \Organism maar ik zou niet weten waarom je dat zou doen.
?>
Bij jouw voorbeeld is er niets als 'Feline' of 'Canine' ge-aliased. Dus typehint je op \Feline\Cat en \Canine'\Dog.
Met 2 & 3 combineren bedoelde ik het volgende:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
[code]<?php
namespace Foo\Bar\Meow\Woof;
use Organism\Animal\Mammal\Canine\Dog;
use Organism\Animal\Mammal\Canine\Wolf;
use Organism\Animal\Mammal\Feline;
$dog = new Dog;
$wolf = new Wolf;
$cat = new Feline\Cat;
$lion = new Feline\Lion;
$tiger = new Feline\Tiger;
$leopard = new Feline\Leopard
?>
[code]<?php
namespace Foo\Bar\Meow\Woof;
use Organism\Animal\Mammal\Canine\Dog;
use Organism\Animal\Mammal\Canine\Wolf;
use Organism\Animal\Mammal\Feline;
$dog = new Dog;
$wolf = new Wolf;
$cat = new Feline\Cat;
$lion = new Feline\Lion;
$tiger = new Feline\Tiger;
$leopard = new Feline\Leopard
?>
>> De ltrim() laadt dus alle behalve wat niet geladen hoeft te worden: klassennamen die beginnen met \.
De vraag is waarom die ltrim daar staat. De php classes komen sowieso de autoloader niet binnen, want die zijn al geladen aan het begin van ieder request. Daarnaast... als je in jouw autoload method $className echoot (probeer maar eens), dan zul je zien dat geen enkele classnaam met een \ begint. Vandaar dus mijn vraag wat die ltrim daar doet.
@Dos: ah oké. Da's een duidelijk voorbeeld.
Even nog een kleine nuance...
Code (php)
1
2
3
4
5
2
3
4
5
<?php
use Organism\Animal\Mammal;
// Is de kortere versie van
use Organism\Animal\Mammal as Mammal;
?>
use Organism\Animal\Mammal;
// Is de kortere versie van
use Organism\Animal\Mammal as Mammal;
?>
Dit is niet helemaal waar. In het 1e geval zeg je "gebruik de class Organism\Animal\Mammal". In het 2e geval zeg je "gebruik voor de class Organism\Animal\Mammal vanaf nu Mammal". Komt in dit geval weliswaar op hetzelfde neer, maar in de parktijk zul je dat alleen gebruiken om iets te "hernoemen", bijv.
Ward van der Put op 13/11/2013 15:04:35:
De PHP-namespace begint met \ maar daarvoor heb je geen autoloader nodig. De ltrim() laadt dus alle behalve wat niet geladen hoeft te worden: klassennamen die beginnen met \.
Met andere woorden: de autoloader mag geen klassen die met \ beginnen laden, want dat is het domein van PHP. En vice versa: als de autoloader aan bod komt, moet die een van onze eigen klassen laden, geen klasse van PHP.
Code (php)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
<?php
// (a) Niks autoloader, we gebruiken Exception van PHP:
namespace Foo;
throw new \Exception();
// (b) Via de autoloader laden we Foo\Exception in ../lib/Foo/Exception.php:
namespace Foo;
throw new Exception();
?>
// (a) Niks autoloader, we gebruiken Exception van PHP:
namespace Foo;
throw new \Exception();
// (b) Via de autoloader laden we Foo\Exception in ../lib/Foo/Exception.php:
namespace Foo;
throw new Exception();
?>
Met andere woorden: de autoloader mag geen klassen die met \ beginnen laden, want dat is het domein van PHP. En vice versa: als de autoloader aan bod komt, moet die een van onze eigen klassen laden, geen klasse van PHP.
Emhe...
Als je begint met een \ geef je aan dat je vanaf de root begint. Ik weet behoorlijk zeker dat het trimmem van de eerste \ er mee te maken had dat dit niet gedaan werd in PHP's core.
Code (php)
1
2
3
4
5
2
3
4
5
<?php
$miauw = Miauw\Woef; // spl_autoload_call('Miauw\Woef')
$miauw = \Miauw\Woef; // spl_autoload_call('\Miauw\Woef') in bepaalde PHP versies voor het gefixt was. ltrim() was dus nodig.
?>
$miauw = Miauw\Woef; // spl_autoload_call('Miauw\Woef')
$miauw = \Miauw\Woef; // spl_autoload_call('\Miauw\Woef') in bepaalde PHP versies voor het gefixt was. ltrim() was dus nodig.
?>
Gewijzigd op 13/11/2013 15:17:00 door Dos Moonen
Hier wordt toch geen class geladen? Je vergeet het keyword "new".
In de autoloader zal de class-naam nu gewoon "Miauw\Woef" zijn (zonder slash aan het begin). Vandaar dat ik het zo raar vindt dat daar ltrim staat.
Maar eerder zei je dat het in eerdere versies fout ging. Als ik altijd een nieuwere PHP versie gebruik, kan ik die ltrim dan gewoon achterwege laten?
Gewijzigd op 13/11/2013 15:23:07 door Ozzie PHP
Ozzie PHP op 13/11/2013 15:15:26:
Dit is niet helemaal waar. In het 1e geval zeg je "gebruik de class Organism\Animal\Mammal". In het 2e geval zeg je "gebruik voor de class Organism\Animal\Mammal vanaf nu Mammal". Komt in dit geval weliswaar op hetzelfde neer, maar in de parktijk zul je dat alleen gebruiken om iets te "hernoemen", bijv.
http://www.php.net/manual/en/language.namespaces.importing.php
Voorbeeld 1:
Dos Moonen op 13/11/2013 15:21:39:
Dit klopt... in die zin dat het op hetzelfde neerkomt, omdat je dezelfde naam gebruikt. Maar in de praktijk zul je dat niet zo doen. Je zult alleen hernoemen als de naam anders is.
use Dierentuin\Beesten\Olifant
Dit wil zeggen: gebruik de class "Olifant" van de namespace "Dierentuin\Beesten"
use Dierentuin\Beesten\Olifant as Olifant
Dit wil zeggen: gebruik de class "Olifant" van de namespace "Dierentuin\Beesten" en noem deze class "Olifant". Hé... maar dat is een beetje onzinnig. De class heet al "Olifant" en dan ga ik 'm hernoemen naar "Olifant". Dat heeft niet zoveel zin!
use Dierentuin\Beesten\Olifant as Dombo
Dit wil zeggen: gebruik de class "Olifant" van de namespace "Dierentuin\Beesten" en noem deze class "Dombo". Nu heeft het wel zin. In plaats van "Olifant" kan ik nu "Dombo" gebruiken. Vraag me niet waarom je dat zou willen, maar dat even terzijde :)
Een praktijkvoorbeeld zou bijv kunnen zijn:
use My\Exception\Mailer as MyExceptionMailer
Ik snap niet wat er volgens jou mis is aan de volgende stelling:
'use My\Full\NSname;' en 'use My\Full\NSname as NSname;' doen PRECIES het zelfde wat PHP betreft.
Gewijzigd op 13/11/2013 15:38:28 door Dos Moonen