web-dev-qa-db-fra.com

est-il possible d'obtenir la liste des espaces de noms définis

Salut,

Je me demandais s'il existe un moyen dans php 5.3+ d'obtenir une liste d'espaces de noms définis dans une application. alors

si file 1 has namespace FOO et file 2 has namespace BAR

Maintenant, si j'inclus le fichier 1 et le fichier 2 dans le fichier 3, j'aimerais savoir avec une sorte d'appel de fonction que l'espace de noms FOO et BAR sont chargés.

Je veux y parvenir pour être sûr qu'un module dans mon application est chargé avant de vérifier si la classe existe (avec is_callable).

Si ce n'est pas possible, j'aimerais savoir s'il existe une fonction pour vérifier si un espace de noms spécifique est défini, quelque chose comme is_namespace ().

J'espère que vous avez l'idée. et ce que j'essaye d'accomplir

31
DonSeba

Premièrement, pour voir si une classe existe, utilisé class_exists .

Deuxièmement, vous pouvez obtenir une liste de classes avec namespace en utilisant get_declared_classes .

Dans le cas le plus simple, vous pouvez utiliser ceci pour trouver un espace de noms correspondant à partir de tous les noms de classe déclarés:

function namespaceExists($namespace) {
    $namespace .= "\\";
    foreach(get_declared_classes() as $name)
        if(strpos($name, $namespace) === 0) return true;
    return false;
}

Autre exemple, le script suivant produit une structure de tableau hiérarchique d'espaces de noms déclarés:

<?php
namespace FirstNamespace;
class Bar {}

namespace SecondNamespace;
class Bar {}

namespace ThirdNamespace\FirstSubNamespace;
class Bar {}

namespace ThirdNamespace\SecondSubNamespace;
class Bar {}

namespace SecondNamespace\FirstSubNamespace;
class Bar {}

$namespaces=array();
foreach(get_declared_classes() as $name) {
    if(preg_match_all("@[^\\\]+(?=\\\)@iU", $name, $matches)) {
        $matches = $matches[0];
        $parent =&$namespaces;
        while(count($matches)) {
            $match = array_shift($matches);
            if(!isset($parent[$match]) && count($matches))
                $parent[$match] = array();
            $parent =&$parent[$match];

        }
    }
}

print_r($namespaces);

Donne:

Array
(
    [FirstNamespace] => 
    [SecondNamespace] => Array
        (
            [FirstSubNamespace] => 
        )
    [ThirdNamespace] => Array
        (
            [FirstSubNamespace] => 
            [SecondSubNamespace] => 

        )
)
39
Hamish

Je sais que cette question a déjà une réponse, mais je voulais apporter une solution plus réaliste à ce que je pense être votre problème. Si j'avais eu plus de temps hier quand j'ai fait mon commentaire, j'aurais publié ceci. Désolé de ne pas l'avoir fait.

On dirait qu'OP a un système de modules dont il a besoin pour savoir si un module particulier est chargé avant d'autoriser un appel.

Tout d'abord, j'aimerais dire que l'utilisation d'espaces de noms simplement pour déclarer des modules actifs est, IMO, abuser de leur utilité. Si vous suivez le but de l'espacement des noms à la lettre, votre structure pourrait ressembler davantage à ceci:

L'ensemble de votre système doit être dans son propre espace de noms. Appelons cet espace de noms System. Ensuite, les modules seraient probablement sous le System\Module espace de noms. Ensuite, en fonction de la complexité, il serait possible que chaque module ait un espace de noms sous System\Module. Prenant vos exemples, System\Module\FOO et System\Module\BAR.

Maintenant, passons à la création d'un système de modules qui s'enregistre en charge.

Tout d'abord, nous avons besoin d'un endroit pour nous inscrire. Appelons ça System\Module\Registry et, comme il y aura probablement beaucoup de registres différents, il implémentera le System\iRegistry. Par souci de concision, je ne publie que System\Module\Registry. Selon toute vraisemblance, il implémentera également une sorte de modèle de cohérence globale, comme un singleton, mais je ne le montre pas non plus. C'est ici:

<?php
namespace System\Module
{
    class Registry extends System\Registry
    {
        protected $registered = array();

        public function register( $name=null )
        {
            $this->registered[] = $name;
        }

        public function isRegistered( $module )
        {
            // Code to find module
        }

        public function getModule( $module )
        {
            // Code to find module

            // OR, if you can't find it...
            throw new ModuleNotRegisteredException("Module named \"{$module}\" could not be found in the registry.");
        }
    }
}
?>

Maintenant, dans chaque module, vous devez appeler cette fonction de registre lorsque le fichier est chargé. Il y a plusieurs façons de faire ça. La première consiste à avoir du code dans l'espace de noms de votre module qui s'exécute à la charge similaire au code procédural typique:

namespace System\Module\FOO
{
    // Load this module
    $system->module->register("FOO");
}

Ce qui précède signifierait cependant une duplication de code. Vous pouvez également utiliser le chargement automatique pour cela à la place, de cette façon le code "d'enregistrement" est en un seul endroit. Voici un concept très basique pour faire cela:

spl_autoload_register(
    function ($className)
    {
        // Code to load files.
        // Once loaded register our modules.
        if( $namespace = "System\\Module" )
        {
            $system->module->register( $classname );
        }
    }
); 

Une autre façon possible de faire cela serait de définir une interface pour les modules avec une fonction spécifique pour l'enregistrement lorsque le module est initialisé. Cependant, cela signifie que le module doit être chargé en premier et peut causer ses propres problèmes en fonction de vos besoins.

Après avoir fait ceci:

  • vous disposez d'un espace de noms cohérent dans lequel les modules peuvent vivre
  • vous avez une interface cohérente qui permet à n'importe quel module de savoir comment s'enregistrer
  • vous pouvez facilement étendre le module ou les interfaces de registre à l'avenir pour de nouvelles choses, tout en gardant votre code propre et facile à comprendre.
  • et, le plus important, vous saurez que vos modules déclareront réellement qu'ils sont chargés et/ou prêts au lieu de compter sur la magie noire pour le faire à votre place.
14
Kevin Peno