{"id":233892,"date":"2023-02-24T10:06:00","date_gmt":"2023-02-24T07:06:00","guid":{"rendered":"https:\/\/wordpress.mediadoma.com\/?p=233892"},"modified":"2022-11-11T13:02:00","modified_gmt":"2022-11-11T10:02:00","slug":"como-implementar-um-carregador-automatico-com-namespaces-em-seu-tema-ou-plugin-do-wordpress","status":"publish","type":"post","link":"https:\/\/wordpress.mediadoma.com\/pt-pt\/como-implementar-um-carregador-automatico-com-namespaces-em-seu-tema-ou-plugin-do-wordpress\/","title":{"rendered":"Como implementar um carregador autom\u00e1tico com namespaces em seu tema ou plugin do WordPress"},"content":{"rendered":"\n<p>Se voc\u00ea estiver escrevendo c\u00f3digo orientado a objetos, um autoloader \u00e9 obrigat\u00f3rio. Sem um autoloader, voc\u00ea precisaria adicionar uma linha incluindo o arquivo de classe, antes de poder inicializ\u00e1-lo. Pode ser rapidamente complicado quando voc\u00ea trabalha com muitas classes. Um autoloader \u00e9 uma fun\u00e7\u00e3o que dispara toda vez que uma nova classe \u00e9 instanciada e inclui o arquivo de classe antes que a instancia\u00e7\u00e3o aconte\u00e7a.<\/p>\n<p>Os namespaces s\u00e3o uma forma de estruturar e encapsular seu c\u00f3digo e ajudam a evitar colis\u00f5es de nomes. Se voc\u00ea for escrever OOP, \u00e9 recomend\u00e1vel usar namespaces tamb\u00e9m. Tenha em mente que voc\u00ea pode implementar um autoloader sem usar namespaces em seu c\u00f3digo OOP.<\/p>\n<p>Voc\u00ea pode usar este c\u00f3digo para o seu tema ou plugin do WordPress, ou qualquer c\u00f3digo PHP fora do WordPress \u2013 apenas modifique os caminhos de forma correspondente. Para este exemplo estou criando um autoloader para um tema WordPress.<\/p>\n<h2>Regras para namespace e estrutura de classe<\/h2>\n<p>A implementa\u00e7\u00e3o de um autoloader exigiria algumas regras definidas para sua estrutura de c\u00f3digo e onde encontr\u00e1-las. O uso de namespaces simplifica um pouco isso, pois seu namespace pode se referir a qual pasta as classes est\u00e3o.<\/p>\n<p>Primeiro, decida qual deve ser o nome do seu namespace. Normalmente \u00e9 algo \u00fanico para o seu c\u00f3digo, por exemplo, o nome do seu tema. Por exemplo, o namespace para o tema deste site \u00e9 <code>AWhitePixelTheme<\/code>. Isso significa que para o autoloader funcionar, todas as classes devem estar dentro desse namespace.<\/p>\n<pre><code>namespace AWhitePixelTheme;<\/code><\/pre>\n<p>Minha primeira regra \u00e9 que qualquer arquivo de classe sempre conter\u00e1 apenas uma classe, e o nome da classe deve ser o mesmo que o nome do arquivo. Por exemplo; uma classe <code>MyTest<\/code>deve ser definida dentro de um arquivo <code>MyTest.php<\/code>.<\/p>\n<p>Minha segunda regra \u00e9 como estruturar as classes em pastas. Eu decido que todas as classes v\u00e3o para dentro de uma pasta <code>src<\/code>no meu tema. Posso colocar arquivos de classe diretamente nesta pasta, e para isso eles devem estar dentro do namespace &quot;raiz&quot; definido acima. Mas se eu quiser criar subpastas e colocar arquivos de classe nelas, seus namespaces devem incluir a estrutura de pastas. Por exemplo, uma classe arquivo <code>MyTest.php<\/code>que reside na pasta <code>src\/Test\/<\/code>, deve ter este namespace definido:<\/p>\n<pre><code>namespace AWhitePixelThemeTest;<\/code><\/pre>\n<h2>Criando o carregador autom\u00e1tico<\/h2>\n<p>Eu gosto de manter o autoloader em um arquivo separado e fora da <code>src\/<\/code>pasta que \u00e9 definida apenas para arquivos de classe com namespace. Como exemplo vou criar um arquivo <code>autoloader.php<\/code>na pasta <code>inc\/<\/code>do meu tema.<\/p>\n<p>O PHP tem uma fun\u00e7\u00e3o de autoloader embutida: <a href=\"https:\/\/www.php.net\/manual\/en\/function.spl-autoload-register.php\" target=\"_blank\" rel=\"noopener nofollow\" class=\"external external_icon\">spl_autoload_register<\/a>. Voc\u00ea fornece o nome da sua fun\u00e7\u00e3o de autoloader como par\u00e2metro e nessa fun\u00e7\u00e3o voc\u00ea obt\u00e9m a classe solicitada como argumento (o que voc\u00ea coloca depois <code>new<\/code>ao instanciar a classe). Ao instanciar classes com namespaces, por exemplo <code>new AWhitePixelThemeTestMyTest()<\/code>, a vari\u00e1vel fornecida para esta fun\u00e7\u00e3o seria <code>\"AWhitePixelThemeTestMyTest\"<\/code>.<\/p>\n<p>Vamos adicionar a fun\u00e7\u00e3o autoloader, e nela definimos nosso namespace necess\u00e1rio para o autoloader:<\/p>\n<pre><code>&lt;?php\nspl_autoload_register('awhitepixel_autoloader');\nfunction awhitepixel_autoloader($class) {\n    $namespace = 'AWhitePixelTheme';\n\u00a0\n}<\/code><\/pre>\n<p>Ent\u00e3o precisamos incluir este arquivo para que nosso autoloader seja registrado. Como isso est\u00e1 em um tema, adicionarei o include no arquivo <code>functions.php<\/code>. Se voc\u00ea estiver usando isso para um plug-in, coloque-o dentro de seus arquivos de plug-in. O arquivo autoloader precisa ser adicionado antecipadamente, antes de qualquer instancia\u00e7\u00e3o de classes. Estou colocando isso na primeira linha do meu <code>functions.php<\/code>:<\/p>\n<pre><code>require_once(get_template_directory(). '\/inc\/autoloader.php');<\/code><\/pre>\n<p>Se voc\u00ea o estiver usando para um tema filho ou um plug-in, modifique o caminho para suas necessidades.<\/p>\n<p>E \u00e9 isso. Agora o autoloader est\u00e1 no lugar, mas n\u00e3o est\u00e1 fazendo nada. Vamos retornar \u00e0 fun\u00e7\u00e3o autoloader e finaliz\u00e1-la.<\/p>\n<h2>Escrevendo e testando a fun\u00e7\u00e3o de autoloader<\/h2>\n<p>Primeiro, precisamos garantir que o nome da classe solicitada esteja realmente dentro do nosso namespace. Simplesmente verificamos se o nome da classe do namespace fornecido cont\u00e9m a string do namespace e, caso contr\u00e1rio, sa\u00edmos da fun\u00e7\u00e3o. Depois disso, removemos o nome do namespace da string, para que possamos resolver quaisquer subpastas e arquivos de classe.<\/p>\n<pre><code>&lt;?php\nspl_autoload_register('awhitepixel_autoloader');\nfunction awhitepixel_autoloader($class) {\n    $namespace_name = 'AWhitePixelTheme';\n\u00a0\n    if (strpos($class, $namespace) !== 0) {\n        return;\n    }\n    $class = str_replace($namespace, '', $class);\n}<\/code><\/pre>\n<p>Agora vamos transformar o namespace fornecido em um caminho real para o arquivo. Primeiro, substituiremos qualquer barra invertida <code>\"\"<\/code>no namespace pelo caractere separador de pasta \u2013 para isso, usamos a constante PHP <code>DIRECTORY_SEPARATOR<\/code>. No final adicionamos um <code>\".php\"<\/code>. E, finalmente, antes da string, adicionamos o caminho raiz completo. Como isso est\u00e1 dentro de um tema, estou usando <code>get_template_directory()<\/code>. Se voc\u00ea estiver usando isso para um plug-in, use um m\u00e9todo que retorne o caminho completo para seu plug-in.<\/p>\n<pre><code>    ...\n    $class = str_replace($namespace, '', $class);\n\u00a0\n    $class = str_replace('', DIRECTORY_SEPARATOR, $class). '.php';\n    $directory = get_template_directory();\n    $path = $directory. DIRECTORY_SEPARATOR. 'src'. DIRECTORY_SEPARATOR. $class;\n}<\/code><\/pre>\n<p>Tudo o que precisamos fazer agora \u00e9 verificar se o arquivo existe e, se existir, exigi-lo.<\/p>\n<pre><code>    ...\n    $path = $directory. DIRECTORY_SEPARATOR. 'src'. DIRECTORY_SEPARATOR. $class;\n\u00a0\n    if (file_exists($path)) {\n        require_once($path);\n    }\n}<\/code><\/pre>\n<p>\u00c9 isso!<\/p>\n<p>Vamos test\u00e1-lo. Crie uma subpasta <code>Test<\/code>na pasta do seu tema <code>src\/<\/code>e dentro dela coloque um arquivo php chamado <code>MyTest.php<\/code>. Defina uma classe <code>MyTest<\/code>nele, seguindo as regras para namespace: <code>AWhitePixelThemeTest<\/code>. Vou apenas adicionar uma impress\u00e3o de &#8216;Sucesso&#8217; na fun\u00e7\u00e3o de constru\u00e7\u00e3o para que possamos ver facilmente que ela realmente inicializa a classe.<\/p>\n<pre><code>&lt;?php\nnamespace AWhitePixelThemeTest;\n\u00a0\nclass MyTest {\n    public function __construct() {\n        var_dump('Success!');\n    }\n}<\/code><\/pre>\n<p>Em nosso functions.php, ap\u00f3s solicitar o autoloader, simplesmente instanciamos a classe:<\/p>\n<pre><code>$test = new AWhitePixelThemeTestMyTest();<\/code><\/pre>\n<p>Atualize seu site WordPress e veja se voc\u00ea obt\u00e9m o &#8216;Sucesso!&#8217; emitido.<\/p>\n<p>O autoloader carregar\u00e1 automaticamente quaisquer arquivos de classe que estejam dentro do nosso namespace definido e siga as regras corretas. Voc\u00ea pode instanciar classes de qualquer lugar dentro do seu tema, at\u00e9 mesmo dentro das pr\u00f3prias classes.<\/p>\n<h2>A fun\u00e7\u00e3o de autoloader completa<\/h2>\n<p>Para refer\u00eancia, aqui est\u00e1 nossa fun\u00e7\u00e3o final de autoloader:<\/p>\n<pre><code>spl_autoload_register('awhitepixel_autoloader');\nfunction awhitepixel_autoloader($class) {\n    $namespace = 'AWhitePixelTheme';\n\u00a0\n    if (strpos($class, $namespace) !== 0) {\n        return;\n    }\n\u00a0\n    $class = str_replace($namespace, '', $class);\n    $class = str_replace('', DIRECTORY_SEPARATOR, $class). '.php';\n\u00a0\n    $directory = get_template_directory();\n    $path = $directory. DIRECTORY_SEPARATOR. 'src'. DIRECTORY_SEPARATOR. $class;\n\u00a0\n    if (file_exists($path)) {\n        require_once($path);\n    }\n}<\/code><\/pre>\n<p><div id=\"PostUnique_PostSource\" style=\"padding-top: 50px\">Fonte de grava\u00e7\u00e3o:  <a target=\"_blank\" rel=\"noopener nofollow\" href=\"\/\/awhitepixel.com\" class=\"external external_icon\">awhitepixel.com<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Um guia sobre como escrever um autoloader permitindo namespaces para seu c\u00f3digo orientado a objetos para um tema ou plugin do WordPress.<\/p>\n","protected":false},"author":1,"featured_media":224072,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_wp_rev_ctl_limit":""},"categories":[930,898,898,722,722,837,920,1110,920,837,930,846,846,867,867],"tags":[1170],"class_list":["post-233892","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-assuntos","category-codigo-2","category-desenvolvedor","category-guia-para-iniciantes","category-outro","category-n-a","category-tutoriais","category-wordpress-8","tag-affiai-pt-pt"],"_links":{"self":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/posts\/233892","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/comments?post=233892"}],"version-history":[{"count":0,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/posts\/233892\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/media\/224072"}],"wp:attachment":[{"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/media?parent=233892"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/categories?post=233892"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wordpress.mediadoma.com\/pt-pt\/wp-json\/wp\/v2\/tags?post=233892"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}