문제

나는있다 비누 클리어 WSDL 파일에 대해 인스턴스가 생성되었습니다. 메소드 호출 중 하나를 제외한 모든 것은 사용자 이름과 비밀번호를 전달해야합니다.

사용자 이름과 비밀번호를 생략 할 수 있도록 메소드 호출을 카레를 만들 수있는 방법이 있습니까?

도움이 되었습니까?

해결책

PHP 5.3 기준으로 an을 저장할 수 있습니다 익명 기능 변수에서. 이 익명 함수는 일부 사전 정의 된 매개 변수로 "원본"기능을 호출 할 수 있습니다.

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

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

$bar('C');

편집 : 폐쇄를 사용하여 익명 기능의 생성을 매개 변수로 만들 수도 있습니다.

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 : 이것은 객체와도 작동합니다

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');

그러나 __call ()와 래퍼 클래스를 사용하는 다른 제안은 완전한 클래스를 "향상시키려는"경우 더 나을 수 있습니다.

다른 팁

다음은 자동 카레링 및 부분 응용 프로그램을 구현합니다.

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);
}

예시:

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

당신은 이것을 할 수 있습니다 :

$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는 그 자체로 카레를 가지고 있지 않지만 여러 가지 방법으로 그런 일을 할 수 있습니다. 특정한 경우 이와 같은 것이 효과가있을 수 있습니다.

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);

PHP> = 5.3에서 카레를위한보다 일반적인 솔루션이 있지만 :

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

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

나는 오늘 이것에 대해 몇 가지 관련 연구를했다. 이것은 내가 얻을 수있는만큼 가깝습니다.

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();

주요 문제는 PHP가 반환 값으로 직접 폐쇄를 실행할 수 없다는 것입니다 (PHP가 결합되지 않은 개체에서 메소드를 실행할 수없는 것과 같은 방식으로). 그러나 폐쇄는 유형 폐쇄의 대상이므로 __invoke ()가 내장 된 메소드가 있는데, 위의 내용은 작동합니다.

아주 좋은 솔루션은 아니지만 PHP를 사용한 기본 래퍼 클래스를 쓸 수 있습니다. 마법 방법 (특히 __call) 실제 함수를 호출하지만 사용자 이름과 암호를 인수 목록에 추가하십시오.

기본 예 :

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);
    }
}

당신이 사용할 수있는 부분 적용 그리고 카레 기능 비표준 PHP 라이브러리.

Ihor가 언급 한 바와 같이, 비표준 PHP 라이브러리는 흥미 롭습니다. 나는 이미 같은 방법을 구현했지만 ihor의 것과 약간 다릅니다. curried() 기능

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));
    };
}

용법 :

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);

이 답변 PHP에서 메소드 호출이 가능합니까? 카레를 보여주지 않습니다. 그 대답은 부분 적용을 보여줍니다. 이러한 개념의 차이점을 설명하는 멋진 튜토리얼은 여기에서 볼 수 있습니다. http://allthingsphp.blogspot.com/2012/02/currying-vs-partial-application.html

이것은 카레입니다 :

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);
        };
    };
}

PHP 7에서 카레 기능을 호출합니다

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

PHP 5에서 카레 기능을 호출합니다

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

//OUTPUT:
int 18

이것은 부분 적용입니다.

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
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top