PHP类型提示可调用函数

PHP类型提示可调用函数,php,Php,好的,我已经定义了这个类方法来接受回调,并且我已经根据类型提示文档将其类型提示为可调用 protected function AddTransformData(array $definition,array $where,callable $callback){ $this->transforms[]=[$definition,$where,$callback]; } 下面是一个我可以调用此函数的示例。使用数组语法将方法和对象作为回调传递 public function __co

好的,我已经定义了这个类方法来接受回调,并且我已经根据类型提示文档将其类型提示为可调用

protected function AddTransformData(array $definition,array $where,callable $callback){
    $this->transforms[]=[$definition,$where,$callback];
}
下面是一个我可以调用此函数的示例。使用数组语法将方法和对象作为回调传递

public function __construct(PostalZoneMapping $pzm){
    $this->pzm=$pzm;
    $this->AddTransformData(Countries::region,['filter'],[$this,'TransformId']);
    $this->AddTransformData(PostalZones::id,['filter'],[$this,'TransformId']);
    $this->ReceiveData();
}
这会抛出一个错误,如下图所示,抱怨参数3不可调用,而是一个数组。从逻辑上讲,我想这是有道理的,因为它是数组,但它是一个可调用函数的数组——当然它必须检测到它是一个回调

这是PHP的怪癖还是我做错了什么

如果您的PHP版本低于7.4,则应改为:

$callable = fn() => $this->$method();
这样做:

$callable = function() use ($method) { $this->$method() };
您还可以收到一个参数:

$callable = fn($param) => $this->$method($param);


看起来
TransformId
不是该类上的方法。可能是打字错误,可能是属性,但不是方法

为了使数组成为有效回调,它必须是:
实例化对象的方法作为数组传递,数组包含索引0处的对象和索引1处的方法名称。

这项工作:

class A {
  function __construct() {
    $this->asd2([$this, 'asd']);
  }
  private function asd() {}

  public function asd2(callable $c) {}
}

$a = new A();
这并不是:

class A {
  function __construct() {
    $this->asd2([$this, 'somethingElse']);
  }
  private function asd() {}

  public function asd2(callable $c) {}
}

Fatal error: Uncaught TypeError: Argument 1 passed to A::asd2() must be callable, array given, called in

如果我错了-粘贴整个类代码,包括
TransformId
方法。

我创建了一些测试代码来重现错误,注意到我将回调声明为私有!此代码将不起作用,但如果将TransformId方法更改为protected或public,则此代码将起作用

<?php

abstract class CommonDataInterface{
    private $transforms=[];
    /**
     * Adds a callback that transform data 
     *
     * @param array $definition Definition, where, if matches, callback is called.
     * @param array $where Where to transform data, array values one or more of 'set','insert' or'filter'
     * @param callable $callback Function that takes value as parameter, and returns transformed value.
     * @return void
     */
    protected function AddTransformData(array $definition,array $where,callable $callback){
        $this->transforms[]=[$definition,$where,$callback];
    }
}


class Api_PostalZoneMapping extends CommonDataInterface{
    private $pzm;

    public function __construct($pzm){
        $this->pzm=$pzm;
        $this->AddTransformData(['blah'],['filter'],[$this,'TransformId']);
        $this->AddTransformData(['blah2'],['filter'],[$this,'TransformId']);
        //$this->ReceiveData();
    }

    private function TransformId($data){
        if($data==-1)
            return null;
        return $data;
    }
}

$p=new Api_PostalZoneMapping('not relevant for test');

是什么导致了异常?我试图创造一些类似的东西,但无法重现结果。你能创建一组简单的代码来重现问题中的这个错误吗?这不是一个简单的IDE错误吗?这是实际运行代码时遇到的真正异常吗?这是什么IDE?可能它不理解可调用数组表示法。哪种可视性有“TransformId”方法?它是私有的还是受保护的?@IvanShumakov根据文档:
允许从类中访问受保护的和私有的方法-所以即使它在这个类的上下文中是私有的,它也应该是有效的可调用的?好的,事实证明它不是在单个类的上下文中,而是在父-子上下文中。然后必须至少对其进行保护,以便可以在父级中调用它。
class A {
  function __construct() {
    $this->asd2([$this, 'somethingElse']);
  }
  private function asd() {}

  public function asd2(callable $c) {}
}

Fatal error: Uncaught TypeError: Argument 1 passed to A::asd2() must be callable, array given, called in
<?php

abstract class CommonDataInterface{
    private $transforms=[];
    /**
     * Adds a callback that transform data 
     *
     * @param array $definition Definition, where, if matches, callback is called.
     * @param array $where Where to transform data, array values one or more of 'set','insert' or'filter'
     * @param callable $callback Function that takes value as parameter, and returns transformed value.
     * @return void
     */
    protected function AddTransformData(array $definition,array $where,callable $callback){
        $this->transforms[]=[$definition,$where,$callback];
    }
}


class Api_PostalZoneMapping extends CommonDataInterface{
    private $pzm;

    public function __construct($pzm){
        $this->pzm=$pzm;
        $this->AddTransformData(['blah'],['filter'],[$this,'TransformId']);
        $this->AddTransformData(['blah2'],['filter'],[$this,'TransformId']);
        //$this->ReceiveData();
    }

    private function TransformId($data){
        if($data==-1)
            return null;
        return $data;
    }
}

$p=new Api_PostalZoneMapping('not relevant for test');