17 mai 2011

CMD, une facade PHP pour les commandes système

Dans la lignée de mes précédents billets, voici une nouvelle classe de type Facade. Cette fois-ci, l'idée est de pouvoir lancer des commandes système autrement qu'avec les fonctions system, shell_exec, popen, etc. Car pour les rares habitués de ce blog, vous aurez remarqué que ma lubie du moment est de chercher à voir de quelle manière on peut écrire le moins de code PHP, tout en gardant un code lisible.

Démonstration


       // Afficher le résultat
       echo CMD::factory('/bin/ls')
            ->option('all')
            ->option('b')
            ->option('color', 'never')
            ->option('format', 'single-column')
            ->option('t')
            ->option('reverse')
            ->param('/usr')
            ->fire()
            ->fetchAll()
            ->toString();

       // Envoyer le résultat dans un fichier
       CMD::factory('/bin/ls')
            ->option('all')
            ->param('/usr')
            ->bind(1, '/tmp/t.txt')            
            ->fire();


       // On lit le résultat en "streaming"
       $c = CMD::factory('/usr/bin/curl', array('long_option_operator' => ' '))
           ->option('no-buffer')
           ->option('request', 'GET')
           ->param('http://www.google.com')
           ->fire();

       while($buf = $c->fetch()) {
           echo $buf;
       }

       // On lance une commande en parallèle de l'exécution du script courant
       $c = CMD::factory('/bin/sleep')
            ->param('1')
            ->fire();
       echo 'On attend';

       while($c->isAlive()) {
            usleep(500000);
            echo '.';
       }
       echo 'Fini !';

Vous remarquerez que l'interface est quasiment identique à la classe PQO. Parcourir le résultat d'une commande ou d'une requête SQL se traduit par un code simple et similaire.

PSOStream

Lancer une commande, c'est bien mais pouvoir lui envoyer et recevoir des données, c'est mieux. Et dans ce cas précis, la classe PSOStream a tout son sens. Celle-ci va permettre de lier entrée et sortie standard avec une chaîne de caractère PHP. Le paradigme POO imposerait du polymorphisme or ici, on impose une chaîne de caractères contenant une URL


// Envoie d'une chaîne de caractères sur l'entrée standard
$in = new PSO('Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce lacinia placerat tortor auctor ultricies.');
$out = new PSO;
CMD::factory('/usr/bin/fmt')
    ->option('width', '40')
    ->bind(0, $in->toURL())
    ->bind(1, $out->toURL())
    ->fire();

echo $out;

// Récupération de la sortie standard
$out = new PSO;

CMD::factory('/bin/ls')
    ->option('all')
    ->option('b')
    ->option('color', 'never')
    ->option('format', 'single-column')
    ->option('t')
    ->option('reverse')
    ->param('/usr')
    ->bind(1, $out->toURL())
    ->fire();

echo $out;

Téléchargement et code source

Le code source est disponible sur GitHub : http://github.com/touv/plor

Ou, on peut directement l'installer avec PEAR en s'abonnant au Channel Respear :


% pear channel-discover pear.respear.net
% pear install respear/plor

4 commentaires:

  1. J'aime bcp mais que ce passe t'il si le script appelant se termine avant la fin des fetch() ou du isAlive() ? La commande est tuée ? Mise en tâche de fond ? Y a t'il moyen de continuer les fetch() restant plus tard dans un autre script ?

    RépondreSupprimer
  2. Intéressant ! Merci.

    (le lien vers wikipedia est tronqué)

    RépondreSupprimer
  3. @faf2019 j'ai corrigé le lien. merci pour l'info.

    RépondreSupprimer
  4. @kerphi
    Si la commande ne renvoie rien sur la sortie standard, le fetch n'a aucune influence sur l’exécution de la commande.
    Si la commande renvoie des données (en mode bloquant, c'est généralement le cas), la commande se terminera uniquement quand le fetch sera arrivé au bout.

    A ma connaissance, PHP ne permet pas nativement de partager un processus entre plusieurs scripts. Donc avec cette classe, on ne peut lancer la commande avec un script et récupérer son contenu avec un autre.

    RépondreSupprimer