• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

djthyrax

Using PHP Namespaces

32 mensagens neste tópico

Uma das críticas que tenho ouvido ao PHP é a falta de suporte a namespaces. Bem, parece que isso agora acaba no PHP 5.3 :)

Aqui fica um artigo sobre namespaces @ PHP.

http://www.phpfever.com/using-php-namespaces.html


PHP 5.3 introduces a much requested feature for object-oriented programmers: namespaces. At the time of this writing, version 5.3 of PHP was in development, but is plan to be released in the near future.

One of the purposes object-oriented programming is to remove ambiguous development and data access items. This basically means identifying common functionality and creating the most reusable framework possible, typically in the form of classes. When creating this functionality, you will begin to have issues with naming conventions and narrowing down functionality even further. To resolve this scoping issue, namespaces allow you to contain those bits of code even more.

Getting your environment setup

Before going any further, you will need to download a release of PHP greater than or equal to 5.3. Since 5.3 is not currently production ready, you can download one of the development releases at snaps.php.net. Once you have that installed, you can use the examples described in this article.

Should I use namespaces?

That is a question that can cause controversy among developers. Namespaces are a solution for grouping large sets of libraries and common functionality. The keyword being “large“. You need to be realistic about this. While not definitive, here are some good signs that namespaces are right for you:

  1. Your application is not on shared hosting.

  2. You have so many libraries, or your framework requires less work by adding class paths to the include_path php.ini directive.

  3. More than one developer is working on the application (debatable)

  4. You have an existing MVC framework (Code Igniter, Symfony, Zend Framework) that your application is developed on.

Namespaces really can be handy, but they can also cause confusion. Just as you group methods and properties in a class for common, relational functionality, you may group classes and functions even further. However, there are some rules that you must follow.

Now for the rules

Here are the rules from php.net:

  1. All qualified names are translated during compilation according to current import rules. In example, if the namespace A::B::C is imported, a call to C::D::e() is translated to A::B::C::)::e().

  2. Unqualified class names are translated during compilation according to current import rules (full name substituted for short imported name). In example, if the namespace A::B::C is imported, new C() is translated to new A::B::C().

  3. Inside namespace, calls to unqualified functions that are defined in the current namespace (and are known at the time the call is parsed) are interpreted as calls to these namespace functions, at compile time.

  4. Inside namespace (say A::;), calls to unqualified functions that are not defined in current namespace are resolved at run-time. Here is how a call to function foo() is resolved:

        1. It looks for a function from the current namespace: A::B::foo().

        2. It tries to find and call the internal function foo().

      To call a user defined function in the global namespace, ::foo() has to be used.

  5. Inside namespace (say A::;), calls to unqualified class names are resolved at run-time. Here is how a call to new C() is resolved:

        1. It looks for a class from the current namespace: A::B::C.

        2. It tries to find and call the internal class C.

        3. It attemts to autoload A::B::C.

      To reference a user defined class in the global namespace, new ::C() has to be used.

  6. Calls to qualified functions are resolved at run-time. Here is how a call to A::B::foo() is resolved:

        1. It looks for a function foo() in the namespace A::B.

        2. It looks for a class A::B and call its static method foo(). It will autoload the class if necessary.

  7. Qualified class names are resolved in compile-time as class from corresponding namespace. For example, new A::B::C() refers to class C from namespace >A::B.

Okay, so how do I use them?

It seems that PHP will be going with a similar namespace setup as C++. In order to declare a namespace, you will use the “namespace” keyword.

      <?php
      namespace MyNamespace;
       
      class Test {
          public function hello() {
              echo ‘Hello’;
          }
      }
      ?>

The declaration above simply states that all elements contained in this script will be referenced with the “MyNamespace” namespace. You will need to place the “namespace” declaration at the top of the script.

In order to use a portion of functionality within this script, we will use the Scope Resolution Operator and instantiate the “Test” class.

      <?php
      // Requiring the namespace file is a good indication that you don’t need to use namespaces, but this is only an example!
      require(‘the_file_above.php’);
      $test = new MyNamespace::Test();
      $test->hello();
      // Prints ‘hello’
      ?>

Pretty nifty, huh? Okay, so let’s get a little deeper into this. What if you have a complicated set of namespaces that are three or four levels deep? Is this a viable solution?

      <?php
      $object = new Level1::Level2::Level3::SomeClass();
      $object->doSomething();
       
      $object2 = new Level1::Level2::Level3::AnotherClass();
      $object2->imTiredOfTyping();
      ?>

In case you’re wondering, the answer is NO. Instead, we can alias a namespace to save some keystrokes and future arthritis pains:

      <?php
      use Level1::Level2::Level3 as SomeAlias;
       
      $object = new SomeAlias::SomeClass();
      $object2 = new SomeAlias::AnotherClass();
      ?>

That saved some time! Now, how do we get that many levels of namespaces and why? Well, the more complicated your framework and libraries become, the more creative naming and depth of namespaces become. For instance, let’s consider a namespace that handles database actions. You may have a MySQL, Postgres, and MS SQL set of drivers. You could setup your namespace levels like this:

    * Database

          o Mysql

                + ActiveRecord

          o Pgsql

                + ActiveRecord

          o Mssql

                + ActiveRecord

In this example, albeit not the best, your namespaces could be setup in a relational manner:

Database::Mysql::ActiveRecord;

Database::Pgsql::ActiveRecord;

Database::Mssql::ActiveRecord;

Within the ActiveRecord namespace, you could have a class that handles common database transactions:

      <?php
      namespace Database::Mysql::ActiveRecord;
       
      class Manager  {
          public function select($sql) {
              // do a select
           }
       
          public function update($table,$params) {
              // do an update
          }
      }
      ?>

You could then have a directory outside of the web root called “database” which contains each of these DB namespaces, and add that to your INI “include_path” directive. This makes a large system a little better organized and maintainable. Just remember, namespaces add another layer of complexity to your codebase, so make sure your organization creates standards of developing namespaces.

You can also alias a class within a namespace for use:

      <?php
      use Database::Mysql::ActiveRecord::Manager as RecordManager;
      $manager = new RecordManager();
      ?>

This scenario is handy if you find yourself instantiating a class multiple times. Declare the use of the namespace all the way to the class level, alias the class, then use it as you would as a normal instantiation.

Global space

You can also redeclare PHP functionality that is available in the global space. Normally you can’t redeclare a function name without producing a fatal error. In the case of namespaces, it is possible!

Let’s say you want to recreate the function print_r. You might want to add a check to see if the script running is web or CLI (Command Line Interface). You can do so by prefixing the PHP function with the Scope Resolution Operator:

      <?php
      namespace String;
       
      function print_r($string) {
          // Assume CLI
          if (isset($argv)) {
              ::print_r($string);
          } else {
              // Add <pre> tags for better output to a browser
              printf(‘<pre>%s< /pre>’, ::print_r($string,1));
          }
      }
      ?>

You could then call this function:

      <?php
      require(‘String.php’);
      String::print_r(‘Test text’);
      ?>

This allows you to “redeclare” print_r.

Conclusion

As I took a glance at the upcoming namespace functionality in PHP 5.3, I was intrigued, but a little disappointed. I was really hoping that PHP would implement similar functionality to C#, but PHP is a very well-developed language that is constantly being improved, and the OOP implementation between versions 4 and 5 can account for that. I have high hopes that PHP will increase the functionality of namespaces, and satisfy users that have been using them for years with other tools. There is no doubt in my mind that PHP is heading in the right direction!

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Coool

Se bem que isto para projectos médios pequenos acaba por não ter grande utilidade. A grande vantagem dos namespaces, na minha opinião é afastar por completo problemas de colisão de nomes. Isso permite desenvolver em paralelo sem qualquer medo de incompatibilidades transversais. Projectos com um desenvolvimento equeno e fechado não têm esse problema.

Anyway,

Siga para bingo!

Falta a implementação de threads e as críticas vão-se reduzindo à 'pentelhice' da nomenclatura das funções da API nativa.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Lembro-me de já ver "isto" na documentação faz algum tempo(trabalho com coders de C# e tão sempre a mandar vir ^^ por eu não as ter).

Agora... até que ponto será util? Não seria melhor pensarem noutras coisas mais importantes? (threads/suporte nativo a mais protocolos etc etc).

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

A que te referes com suporte a mais protocolos? (Deixo a resposta às threads quando tiver a tua resposta a isto)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Isto não estava previsto para o PHP6 apenas? Estava na ideia que sim...

Anyway, alguém me explica, como se eu fosse muito burro e de uma forma muito simples e básica o que realmente são namespaces, para que servem e que utilidade têm? Eu li o artigo e os vossos comentários mas ainda não assimilei bem para que serve isto dos namespaces.

Tipo, eu trabalho com C# e entendo bem a utilidade de namespaces, mas aqui no PHP parece-me um contexto um pouco diferente e não estou a conseguir assimilar...

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

nazgulled, o conceito é o mesmo que C#, digo eu que nunca escrevi uma linha de C#.

Ao definires um namespace entras no teu próprio reino de nomenclatura, não tens que te preocupar pois podes usar qualquer nome (excepto as palavras-chave reservadas da linguagem). Depois podes aceder-lhes naturalmente com o operador de acesso :: como está no exemplo  A::B::meuobjecto

Ou, se preferires, e aí é que entra a parte pratica disto, entras no namespace (use namespace mycoolnamespace) e aí tens acesso aos objectos desse namespace sem mais 'frescuras'.

Basicamente antes só tinhas o namespace principal, aqui tens vários. Entende um namespace como um universo em que duas identidades não podem ter o mesmo nome. Dois namespaces podem ter individuos com o mesmo nome porque não estão no mesmo namespace.

Agora, podes desenvolver uma biblioteca em que crias um namespace e a partir daí podes usar nomes para funções tipo add() delete() find() sem te preocupares com colisões de nomes quando esta é utilizada por terceiros.

Não é uma feature assim brutal, mas ainda assim era das coisas que o PHP era mais criticado, pelo menos já temos que aturar menos ignorancia não fundamentada. :)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Mas tipo, em C# os namespaces não servem só para isso. Há certas Classes que só posso aceder depois de fazer um "import" ao namespace, caso contrário é como se esses objectos não existissem. Essa era mais ou menos a ideia que tinha de namespace mas em PHP isso parece não ser a mesma coisa, ou será?

O que estou a perguntar é o seguinte: usando o exemplo que está no artigo com a class "Test" no namespace "MyNamespace", segundo o artigo fazemos o seguinte:

$test = new MyNamespace::Test();

Mas será que o facto de estar a fazer um "namespace MyNamespace;" me impede de fazer isto:

$test = new Test();

?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Mas tipo, em C# os namespaces não servem só para isso. Há certas Classes que só posso aceder depois de fazer um "import" ao namespace, caso contrário é como se esses objectos não existissem. Essa era mais ou menos a ideia que tinha de namespace mas em PHP isso parece não ser a mesma coisa, ou será?

O que estou a perguntar é o seguinte: usando o exemplo que está no artigo com a class "Test" no namespace "MyNamespace", segundo o artigo fazemos o seguinte:

$test = new MyNamespace::Test();

Mas será que o facto de estar a fazer um "namespace MyNamespace;" me impede de fazer isto:

$test = new Test();

?

Não:

You can also alias a class within a namespace for use:

      <?php
      use Database::Mysql::ActiveRecord::Manager as RecordManager;
      $manager = new RecordManager();
      ?>

use MyNamespace::Test as Test;
$test = new Test();

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Sim, eu também li isso... Mas isso não é necessariamente a resposta a minha pergunta.

Isso não diz que não podes fazer o que eu perguntei se podias, apenas diz que podes criar alias para fazer dessa forma, mas não diz que não podias sem criar o alias.

Capice? :)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Não estou a ver outra forma de fazer o que dizes então... A não ser que use MyNamespace; no file principal e no incluido dê.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Eu nunca disse que estava a procura de alguma forma de fazer o que eu disse. Tu por acaso lês o que as pessoas dizem ou respondes à toa?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Eu nunca disse que estava a procura de alguma forma de fazer o que eu disse. Tu por acaso lês o que as pessoas dizem ou respondes à toa?

Apenas procurei uma solução seguindo isto:

Mas será que o facto de estar a fazer um "namespace MyNamespace;" me impede de fazer isto:

$test = new Test();

?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Defenição leiga de namespaces:

  Class de objectos, conjunto de objectos ou simplesmente contentor de objectos.

@Nazgulled.

obvio, que enquanto n tiveres o System.Web ("conjunto de classes") nunca terás o "IHttpModule"

Imagina o seguinte, se trabalhares em equipa, tens a class "imovel"(que se refere aos detalhes(quantos quartos etc...)) mas eu que sou da mesma equipa dei o mesmo nome, dentro do namespace "kimico" logo, tu poderas instanciar o "kimico.imovel" sem entrar em conflitos com o "imovel". é isto que sei explicar, basicamente...

O objectivo principal julgo(agradeço que me neguem caso esteja errado, caso estejam certos), é evitar o conflito entre nomenclaturas, e ter a certeza que o conteúdo X se refere a X de uma forma abstracta, "name" refere-se a "username" e a "user" etc. mas não se refere a "uname" pois é isso que está definido na namespace.

Desculpem a minha insanidade de tentar explicar algo, quando sei que não sei explicar ^^  :cheesygrin: :eek:

Ps: "A que te referes com suporte a mais protocolos? (Deixo a resposta às threads quando tiver a tua resposta a isto)"

Pah, expliquei-me mal... xD. Mais interacção com tecnologias externas... like windows XD (não me venhas falar dos "COM"!!! LOL), menos bugs...

Falando como programador, tenho a dizer que o php é excelente, não encontrei nada que não pudesse fazer, com mais ou menos dificuldade, desde criar web sites em iss com php, a registar dns num servidor, tudo com jeito se faz, mas deveria de ser mais fácil...

Quando me refiro a "protocolos" externos, posso-te dar um exemplo, para falar daquilo que não me consguei expressar... visto tarmos a meter o "C cardinal" ao barulho... em php, julgo que nativamente, sem andares a ler um "xml" n lês um dataset de C#

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

@djthyrax

Aquilo que eu perguntei, basta uma resposta "sim" ou "não" com + pintelho - pintelho, não pedi soluções. Apenas perguntei se me impedia de fazer aquilo ou não. Mas esquece, não vale a pena... Tu e a tua mania de complicar tudo e mais alguma coisa...

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Parece-me uma excelente adição ao PHP que cada vez mais se torna numa linguagem moderna. O PHP 6 promete bastante. Alguém sabe para quando está previsto? Suponho que ainda demore algum tempo.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites
Mas será que o facto de estar a fazer um "namespace MyNamespace;" me impede de fazer isto:

$test = new Test();

Não impede, possibilita. Isto se Test() estiver no MyNamespace.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Se não escreveres nenhuma declaração de namespace estás no namespace principal.

Se lá tiveres um um identificador chamado Test, podes então chama-lo

$test = new Test();

Se entrates noutro namespace ( quando escreves use MyNamespace )

e escreveres a mesma coisa, vais estar a chamar o Test() que está definido no MyNamespace, não é o mesmo. O outro estava definido no namespace principal. Se não tiveres um Test() definido no MyNamespace então dá erro.

Por outras palavras, estando tu no namespace principal, estas duas expressões são iguais:

#assim entras no namespace primeiro e depois acedes ao objecto la definido
use MyNamespace;
$test = new Test();

#assim acedes directamente ao objecto expecificanto o namespace
$test = new MyNamespace::Test();

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Mas qual é a utilidade de andar e evitar nomes diferentes ? Isto serve para ninguem se preocupar com nomes de ficheiros e classes que os outros programadores criam ( isto supostamente está a pensar em multi coding, ou seja, programar em equipa). Os namespaces então, quando definimos uma classe pertencente a x namespace, acaba por ser um directrório virtual.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Aqueles atrasados mentais decidiram mudar o namespace operator para \... HELLOOOOOOOOOOOOOOOO? O :: não dava? Se formos a ver bem, é tal qual como C++ usa e nunca deu problemas. Mas nãoooooooooooooooo, temos de ser diferentes. Enfim...

http://news.php.net/php.internals/41374

http://wiki.php.net/rfc/namespaceseparator

http://www.reddit.com/r/programming/comments/79cut/php_is_going_to_use_backslash_as_a_namespace/

Cada vez ando mais inclinado para usar Python para webdevelopment...

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Pelo que está nos logs o :: não podia ser pois como já é usado como operador de acesso a métodos estaticos de classes havia situações em que as duas funçoes colidiam. Era um bug.

Mas realmente a barra não é grande pistola. Por mim preferia o :::

a barra parece tudo menos um separador de namespace, mas tá-se

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

pedrotuga, em C++ funciona sem problemas como operador de acesso a métodos estáticos de classes.

djthyrax, não é o fim do mundo. Ao início também fiquei mesmo WTf, mas depois de pensar no assunto, / até faz mais sentido que :: ou . como separador. Mas foi o que se convencionou e agora é complicado alterar e agradar ao resto dos programadores.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Triton, não é /, é \. Anyway, eu não considero o Python por causa disto, é por mais coisas que não gosto/não me agradam tanto na linguagem.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Triton, não é /, é \.

Não é isso que diz num dos links que apresentaste...

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora