PHP 抽象类
示例
抽象类是无法实例化的类。抽象类可以定义抽象方法,这些方法没有任何主体,只有一个定义:
abstract class MyAbstractClass { abstract public function doSomething($a, $b); }
应该通过子类扩展抽象类,然后可以提供这些抽象方法的实现。
这样的类的主要目的是提供一种模板,该模板允许子类继承,“强制”遵循的结构。让我们用一个例子来详细说明一下:
在此示例中,我们将实现一个Worker接口。首先我们定义接口:
interface Worker { public function run(); }
为了简化进一步的Worker实现的开发,我们将创建一个抽象worker类,该类已经run()从接口提供了方法,但是指定了一些子类必须填充的抽象方法:
abstract class AbstractWorker implements Worker { protected $pdo; protected $logger; public function __construct(PDO $pdo, Logger $logger) { $this->pdo = $pdo; $this->logger = $logger; } public function run() { try { $this->setMemoryLimit($this->getMemoryLimit()); $this->logger->log("Preparing main"); $this->prepareMain(); $this->logger->log("Executing main"); $this->main(); } catch (Throwable $e) { //捕获并重新抛出所有错误,以便工人可以记录下来 $this->logger->log("Worker failed with exception: {$e->getMessage()}"); throw $e; } } private function setMemoryLimit($memoryLimit) { ini_set('memory_limit', $memoryLimit); $this->logger->log("Set memory limit to $memoryLimit"); } abstract protected function getMemoryLimit(); abstract protected function prepareMain(); abstract protected function main(); }
首先,我们提供了一种抽象方法getMemoryLimit()。从扩展的任何类都AbstractWorker需要提供此方法并返回其内存限制。在AbstractWorker随后将内存限制,并记录它。
其次,在记录已调用之后,AbstractWorker调用prepareMain()和main()方法。
最后,所有这些方法调用都分组在try-catch块中。因此,如果子类定义的任何抽象方法抛出异常,我们将捕获该异常,将其记录并重新抛出。这样可以避免所有子类都必须自己实现。
现在让我们定义一个继承自的子类AbstractWorker:
class TranscactionProcessorWorker extends AbstractWorker { private $transactions; protected function getMemoryLimit() { return "512M"; } protected function prepareMain() { $stmt = $this->pdo->query("SELECT * FROM transactions WHERE processed = 0 LIMIT 500"); $stmt->execute(); $this->transactions = $stmt->fetchAll(); } protected function main() { foreach ($this->transactions as $transaction) { //可能引发一些PDO或MYSQL异常,但这由AbstractWorker处理 $stmt = $this->pdo->query("UPDATE transactions SET processed = 1 WHERE id = {$transaction['id']} LIMIT 1"); $stmt->execute(); } } }
如您所见,它TransactionProcessorWorker非常容易实现,因为我们只需要指定内存限制并担心它需要执行的实际操作。不需要进行错误处理,TransactionProcessorWorker因为该错误是在中处理的AbsractWorker。
重要的提示
从抽象类继承时,父类声明中标记为抽象的所有方法都必须由子代定义(或者子代本身也必须标记为抽象);此外,必须以相同(或较少限制)的可见性定义这些方法。例如,如果抽象方法定义为protected,则函数实现必须定义为protected或public,但不能定义为private。
摘自用于类抽象的PHP文档。
如果未在子类中定义父抽象类方法,则将引发致命PHP错误,如下所示。
致命错误:类X包含1抽象方法,因此必须声明为抽象,或在其中实现其余方法(X::x)