PHP对象函数引用创建与类方法复用及调用技术咨询
嘿,我来帮你搞定这两个PHP问题,都是日常开发里很常见的场景:
1. 如何在PHP对象中创建函数引用?
在PHP里,你可以通过几种灵活的方式在对象中存储和使用函数引用:
- 用闭包存储可调用对象:你可以把外部函数、匿名函数或者类方法的引用存在对象的属性里,之后随时调用。比如:
class MyClass { private $funcRef; public function __construct(callable $func) { $this->funcRef = $func; } public function executeFunc() { // 调用存储的函数引用,还能传参 return call_user_func($this->funcRef, "Hi there"); } } // 外部函数 function sayHi($message) { return $message . " from external function!"; } $obj = new MyClass('sayHi'); echo $obj->executeFunc(); // 输出 Hi there from external function!
- 绑定闭包到对象上下文:如果需要让函数引用能访问对象的私有/受保护属性,可以用
Closure::bind()把闭包绑定到当前实例,这样闭包里就能用$this访问对象的内部数据了:
class User { private $username = "tristan"; public $getUsername; public function __construct() { $this->getUsername = Closure::bind(function() { return $this->username; }, $this, self::class); } } $user = new User(); echo $user->getUsername(); // 输出 tristan
- 直接声明callable类型属性:PHP 7.1及以上支持
callable类型声明,你可以直接把属性定义为这个类型,赋值时可以传入函数名、闭包,甚至是类方法的数组形式(比如[User::class, 'staticMethod']或者[$obj, 'instanceMethod'])。
2. 数据库行对象的通用方法实现与外部函数调用
当然支持!而且完全不用每个实例重复实现方法——PHP的类方法是存在类的内存空间中的,所有实例共享同一份方法实现,不会浪费内存。这里给你几种方案:
方案一:直接在类中定义通用方法(最推荐)
把格式化行数据的方法直接写在表示MySQL行的类里,所有行实例都会自动拥有这些方法:
class DbRow { private $rowData; public function __construct(array $data) { $this->rowData = $data; } // 拼接姓名的通用方法 public function getFullName() { return $this->rowData['first_name'] . ' ' . $this->rowData['last_name']; } // 支持自定义参数的方法,比如指定分隔符 public function getFormattedName(string $separator = ' ') { return $this->rowData['first_name'] . $separator . $this->rowData['last_name']; } } // 每个行实例都能调用这些方法,且方法只在类中存一份 $userRow = new DbRow(['first_name' => 'John', 'last_name' => 'Doe']); echo $userRow->getFullName(); // 输出 John Doe echo $userRow->getFormattedName('-'); // 输出 John-Doe
方案二:用Trait提取通用方法
如果有多个不同的行类(比如用户行、商品行)都需要类似的格式化方法,可以把这些方法放到Trait里,然后让各个行类引入Trait,避免代码重复:
trait RowFormatter { public function getFullName() { return $this->rowData['first_name'] . ' ' . $this->rowData['last_name']; } public function toJson() { return json_encode($this->rowData); } } class UserRow { use RowFormatter; private $rowData; public function __construct(array $data) { $this->rowData = $data; } } class ProductRow { use RowFormatter; private $rowData; // 商品专属的方法 public function getPrice() { return $this->rowData['price']; } }
方案三:调用外部函数并传递参数
如果你确实需要调用外部函数来处理行数据,也可以轻松实现。比如在类里定义一个方法,接收外部函数和参数,把当前行的数据传递过去:
class DbRow { private $rowData; public function __construct(array $data) { $this->rowData = $data; } public function runExternalFunc(callable $func, ...$args) { // 把当前行数据作为第一个参数,加上用户传入的其他参数 return $func($this->rowData, ...$args); } } // 外部函数:自定义格式化姓名的逻辑 function customNameFormat($rowData, $prefix) { return $prefix . $rowData['first_name'] . ' ' . $rowData['last_name']; } $row = new DbRow(['first_name' => 'Jane', 'last_name' => 'Smith']); echo $row->runExternalFunc('customNameFormat', 'Mr./Ms. '); // 输出 Mr./Ms. Jane Smith
你也可以把外部函数绑定为对象的动态属性,之后像调用普通方法一样使用:
$row = new DbRow(['first_name' => 'Bob', 'last_name' => 'Brown']); // 把匿名函数(或外部函数)赋值给对象属性 $row->formatName = function($separator) { return $this->rowData['first_name'] . $separator . $this->rowData['last_name']; }; // 调用时用call_user_func触发闭包 echo call_user_func($row->formatName, '_'); // 输出 Bob_Brown
内容的提问来源于stack exchange,提问作者Tristan Mastrodicasa
相关产品推荐
相关产品推荐

