Question

J'ai une instance SoapClient générée pour un fichier WSDL. Tous les appels de méthode sauf un exigent que le nom d'utilisateur et le mot de passe soient transmis id.

Existe-t-il un moyen de traiter les appels de méthode afin que je puisse omettre le nom d'utilisateur et le mot de passe?

Était-ce utile?

La solution

À partir de PHP 5.3, vous pouvez stocker une fonction anonyme dans une variable. Cette fonction anonyme peut appeler le " original " fonctionner avec des paramètres prédéfinis.

function foo($x, $y, $z) {
  echo "$x - $y - $z";
}

$bar = function($z) {
  foo('A', 'B', $z);
};

$bar('C');

modifier: vous pouvez également utiliser une fermeture pour paramétrer la création de la fonction anonyme

function foo($x, $y, $z) {
  echo "$x - $y - $z";
}

function fnFoo($x, $y) {
  return function($z) use($x,$y) {
    foo($x, $y, $z);
  };
}

$bar = fnFoo('A', 'B');
$bar('C');

edit2: Cela fonctionne aussi avec les objets

class Foo {
  public function bar($x, $y, $z) {
    echo "$x - $y - $z";
  }
}

function fnFoobar($obj, $x, $z) {
  return function ($y) use ($obj,$x,$z) {
    $obj->bar($x, $y, $z);
  };
}

$foo = new Foo;
$bar = fnFoobar($foo, 'A', 'C');
$bar('B');

Mais les autres suggestions utilisant __call () et une classe wrapper peuvent être meilleures si vous souhaitez "améliorer". une classe complète.

Autres conseils

Voici une classe implémentant le currying automatique et l'application partielle:

class lambda
{
    private $f;
    private $args;
    private $count;
    public function __construct($f, $args = [])
    {
        if ($f instanceof lambda) {
            $this->f = $f->f;
            $this->count = $f->count;
            $this->args = array_merge($f->args, $args);
        }
        else {
            $this->f = $f;
            $this->count = count((new ReflectionFunction($f))->getParameters());
            $this->args = $args;
        }
    }

    public function __invoke()
    {
        if (count($this->args) + func_num_args() < $this->count) {
            return new lambda($this, func_get_args());
        }
        else {
            $args = array_merge($this->args, func_get_args());
            $r = call_user_func_array($this->f, array_splice($args, 0, $this->count));
            return is_callable($r) ? call_user_func(new lambda($r, $args)) : $r;
        }
    }
}
function lambda($f)
{
    return new lambda($f);
}

Exemple:

$add = lambda(function($a, $b) { 
    return $a + $b; 
});
$add1 = $add(1);
echo $add1(2); // 3

Même vous pouvez le faire:

$int1 = lambda(function($f, $x) {
    return $f($x);
});

$successor = lambda(function($p, $f, $x) {
    return $f($p($f, $x));
}); 

$add = lambda(function($p, $q, $f, $x) {
    return $p($f, $q($f, $x));
}); 

$mul = lambda(function($p, $q, $x) {
    return $p($q($x));
}); 

$exp = lambda(function($m, $n) {
    return $n($m);
});

$int2 = $successor($int1);
$int3 = $add($int1, $int2);
$int6 = $mul($int3, $int2);
$int8 = $exp($int2, $int3);

PHP n’a pas de curry en soi, mais vous pouvez le faire de différentes manières. Dans votre cas particulier, quelque chose comme ceci peut fonctionner:

class MySoapClient extends SoapClient {
  ...
  public function __call($meth,$args) {
    if (substr($method,0,5) == 'curry') {
      array_unshift($args,PASSWORD);
      array_unshift($args,USERNAME);
      return call_user_func_array(array($this,substr($meth,5)),$args);
    } else {
      return parent::__call($meth,$args);
    }
  }
}
$soapClient = new MySoapClient();
...
// now the following two are equivalent
$soapClient->currysomeMethod($additionalArg);
$soapClient->someMethod(USERNAME,PASSWORD,$additionalArg);

Bien qu’il existe une solution plus générale pour traiter les problèmes en PHP > = 5.3:

$curriedMethod = function ($additionalArg) use ($soapClient) { return $soapClient->method(USERNAME,PASSWORD,$additionalArg); }

$result = $curriedMethod('some argument');

J'ai effectué des recherches dans ce domaine aujourd'hui. C’est aussi proche que possible:

function curryAdd($x)
{
  return function($y = null) use ($x)
  {
    if (is_null($y)) return $x;
    else return curryAdd($x + $y);
  };
}

// echo curryAdd(1)(2)(3)(4);
echo curryAdd(1)
  ->__invoke(2)
  ->__invoke(3)
  ->__invoke(4)
  ->__invoke();

Le problème majeur est que PHP ne vous permettra pas d’exécuter une fermeture directement sur une valeur de retour (de la même manière, PHP ne permet pas d’exécuter une méthode sur un objet non lié). Cependant, étant donné que les fermetures sont un objet de type Closure, qui possède une méthode intégrée __invoke (), la procédure ci-dessus fonctionnera.

Bien que ce ne soit pas une très bonne solution, vous pourriez écrire une classe de wrapper de base utilisant des PHP méthodes magiques (spécifiquement __call) pour appeler la fonction réelle mais ajouter le nom d'utilisateur et le mot de passe à la liste d'arguments.

Exemple de base:

class SC
{
    private $user;
    private $pass;

    public function __construct($user, $pass)
    {
        $this->user = $user;
        $this->pass = $pass;
    }

    public function __call($name, $arguments) 
    {
        $arguments = array_merge(array($this->user, $this->pass), $arguments);  
        call_user_func_array($name, $arguments);
    }
}

Comme mentionné par Ihor, la bibliothèque PHP non standard est intéressante. J'ai déjà implémenté la même méthode, c'est un peu différent de la fonction curried () d'Ihor

function curryfy($f, $args = []) {
    $reflexion = new ReflectionFunction($f);
    $nbParams = $reflexion->getNumberOfParameters();

    return function (...$arguments) use ($f, $reflexion, $nbParams, $args) {
        if (count($args) + count($arguments) >= $nbParams) {
            return $reflexion->invokeArgs(array_merge($args, $arguments));
        }

        return curryfy($f, array_merge($args, $arguments));
    };
}

Utilisation:

function display4 ($a, $b, $c, $d) {
    echo "$a, $b, $c, $d\n";
};
$curry4 = curryfy('display4');
display4(1, 2, 3, 4);
$curry4(1)(2)(3)(4);

Cette réponse est-il possible de se curry les appels de méthode en PHP? ne montre pas Currying. Cette réponse montre une application partielle. Un bon tutoriel expliquant la différence entre ces concepts est visible ici: http://allthingsphp.blogspot.com/2012/02/currying-vs-partial-application.html

Ceci est currying:

function sum3($x, $y, $z) {
    return $x + $y + $z;
}

// The curried function    
function curried_sum3($x) {
    return function ($y) use ($x) {
        return function ($z) use ($x, $y) {
            return sum3($x, $y, $z);
        };
    };
}

Appel de la fonction curryed dans PHP 7

$result = curried_sum3(1)(2)(3); 
var_dump($result); // int 6

Appel de la fonction curryed dans PHP 5

$f1 = curried_sum3(6);
$f2 = $f1(6);
$result = $f2(6);
var_dump($result);

//OUTPUT:
int 18

Ceci est une application partielle:

function sum3($x, $y, $z) {
    return $x + $y + $z;
}

function partial_sum3($x) {
    return function($y, $z) use($x) {
        return sum3($x, $y, $z);
    };
}

//create the partial
$f1 = partial_sum3(6);
//execute the partial with the two remaining arguments
$result = $f1(6, 6);

var_dump($result);

//OUTPUT:
int 18
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top