Skip to content

Instantly share code, notes, and snippets.

@vonglasow
Last active August 29, 2015 13:58
Show Gist options
  • Save vonglasow/10021599 to your computer and use it in GitHub Desktop.
Save vonglasow/10021599 to your computer and use it in GitHub Desktop.
traits properties
<?php
trait a {
public function getConfig()
{
return $this->world . '/config.php';
}
}
class B {
public $world = __DIR__;
use a;
}
$b = new B;
var_dump($b->getConfig());
@jubianchi
Copy link

<?php
trait a {
    public function getConfig($basedir)
    {
        return $basedir . '/config.php';
    }
}

class B {
    public $world = __DIR__;
    use a;

    public function getConfig() 
    {
        return parent::getConfig($this->world);
    }
}

$b = new B;
var_dump($b->getConfig());

@vonglasow
Copy link
Author

Oki mais du coup B::getConfig est obligatoire dans toutes nos classes et l'idée principale est de s'en soustraire malheureusement le chemin est basé sur le fichier de la class B

@jubianchi
Copy link

<?php
trait a {
    public function getConfig(BasePathable $c)
    {
        return $c->getBasePath() . '/config.php';
    }
}

interface BasePathable {
    public function getBasePath();  
}

class B implements BasePathable {
    use a;

    public function getConfig() 
    {
        return parent::getConfig($this);
    }
}

$b = new B;
var_dump($b->getConfig());

@vonglasow
Copy link
Author

<?php
trait a {
    public function getConfig($basedir)
    {
        return $basedir . '/config.php';
    }
}

class B {
    use a;

    public function getConfig() 
    {
        return parent::getConfig(__DIR__);
    }
}

$b = new B;
var_dump($b->getConfig());

Du coup la propriété n'est plus nécessaire.

@Adirelle
Copy link

Adirelle commented Apr 7, 2014

<?php
interface WorldAwareInterface {
  public function getWorld();
}

trait a {
    public function getConfig()
    {
        return $this->getWorld() . '/config.php';
    }
}

class B implements WorldAwareInterface {
    use a;
    public function getWorld() { return  __DIR__; }
}

$b = new B;
var_dump($b->getConfig());

@mageekguy
Copy link

Encore une problématique induite par une mauvaise utilisation de la POO…
Dans un monde parfait, le code devrait fonctionner comme ça :

(new B())->doSomething(new config());

Toujours ce fameux 'tell, don't ask!'…
donc, ça veut dire qu'en théorie, l'implémentation devrait être la suivante :

interface configuration
{
   public function setUp(configurable $configurable);
}

interface configurable
{
   public function setPath($path);
}

class config implements configuration
{
    public function setUp(configurable $configurable)
    {
       $configurable->setPath('con/figu/rat/ion.ini');
    }
}

class B implements configurable
{
    private $path = '';

    public function setPath($path)
    {
      $this->path = $path;

      return $this;
    }

   public function doSomething(configuration $configuration)
   {
       $configuration->setUp($this);

       echo $this->path . PHP_EOL;

       return $this;
   }
}

En dehors de cela, point de salut, tu es condamné à faire de la bricole qui ne te permettra jamais de t'affranchir totalement du chemin du fichier de configuration vu que ce n'est pas une abstraction.

@jubianchi
Copy link

@mageekguy: effectivement, ton implémentation rend abstrait tous les composants. Mais comme tu l'as dit, c'est ce qu'on fait dans "Dans un monde parfait" :)

Le problème de @vonglasow c'est que le chemin de la config est dépendant de l'emplacement de la classe qui utilise cette configuration.

Il faut donc que:

  • la classe config de ton implémentation soit dans le même dossier que la classe B (ce qui en soit n'est pas un problème de mon point de vue)
  • la classe config soit paramétrable afin d'être généralisable

D'autre part, je me pose une question au sujet de "tell, don't ask!" : la ligne $config->getBasePath() semble ne pas respecter la citation.

<?php

class B implements configurable
{
    private $config;

    public function setUp(config $config)
    {
      $this->config = $config;
      return $this;
    }

   public function doSomething()
   {
       // Do configured things
       // For example
       $config->createMyWorkingDIrectoryAtTherightPlace();

       // Do the rest of the work
       // For example: emit events to notify that job was successfully done

       return $this;
   }
}

Et là, je dirais que la classe config a sa place à côté de la classe B car l'une vient en support de l'autre.

Qu'en dites-vous ?

@vonglasow
Copy link
Author

Thanks à tous pour vos feedback !

L'application se base sur du ZF2 et chaque module est un répertoire contenant la classe Module.php (cf http://www.zendframework.com/manual/2.1/en/user-guide/modules.html) ainsi que les autres classes nécessaires au module. Et donc à chaque création d'un nouveau module on est obligé d'avoir cette fameuse méthode getConfig qu'on souhaiterais mutualiser quelque part car faisant toujours la même chose partout.

<?php
namespace Album;

class Module
{
    public function getAutoloaderConfig()
    {
        return array(
            'Zend\Loader\ClassMapAutoloader' => array(
                __DIR__ . '/autoload_classmap.php',
            ),
            'Zend\Loader\StandardAutoloader' => array(
                'namespaces' => array(
                    __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
                ),
            ),
        );
    }

    public function getConfig()
    {
        return include __DIR__ . '/config/module.config.php';
    }
}

Et donc à la vue de ce que tu expliques on devrait plutôt modifier la classe Module pour qu'elle implémente l'interface configurable. Ça ne devrait pas poser de soucis mais le problème est que l'on devrait avoir une classe config qui implémente configuration dans chaque module cela reviens à déplacer la méthode getConfig dans une autre classe. Pourquoi pas mais à la création d'un nouveau module ce n'est pas une méthode que l'on va devoir réécrire à l'identique mais bien une classe complète. Ou alors il faudrait partir sur un système de config qui se gère automatiquement par rapport au noms de la classe appelée et qui aille rechercher la config d'après le nom de classe + namespace ?

@mageekguy
Copy link

Surtout qu'en fait ma première implémentation était de la merde (j'ai repiqué du code pour aller vite, et j'ai été trop vite pour le nettoyer…), donc @jubianchi, ta remarque par rapport au getBasePath() était donc pertinente (j'ai mis à jour le code).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment