抽象類
抽象類是無法例項化的類。抽象類可以定義抽象方法,這些方法是沒有任何主體的方法,只有一個定義:
abstract class MyAbstractClass {
abstract public function doSomething($a, $b);
}
抽象類應該由子類擴充套件,然後可以提供這些抽象方法的實現。
像這樣的類的主要目的是提供一種模板,允許子類繼承,強制結構遵守。讓我們舉一個例子詳細說明:
在這個例子中,我們將實現一個 Worker
介面。首先我們定義介面:
interface Worker {
public function run();
}
為了簡化進一步的 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) {
// Catch and rethrow all errors so they can be logged by the worker
$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) {
// Could throw some PDO or MYSQL exception, but that is handled by the AbstractWorker
$stmt = $this->pdo->query("UPDATE transactions SET processed = 1 WHERE id = {$transaction['id']} LIMIT 1");
$stmt->execute();
}
}
}
正如你所看到的,TransactionProcessorWorker
很容易實現,因為我們只需要指定記憶體限制並擔心它需要執行的實際操作。TransactionProcessorWorker
中不需要處理錯誤,因為這是在 AbsractWorker
中處理的。
重要的提示
從抽象類繼承時,父類的宣告中標記為 abstract 的所有方法都必須由子類定義(或者子類本身也必須標記為 abstract); 此外,必須使用相同(或限制較少)的可見性來定義這些方法。例如,如果將抽象方法定義為 protected,則必須將函式實現定義為 protected 或 public,而不是 private。
摘自 PHP 文件中的類抽象 。
如果你沒有在子類中定義父抽象類方法,則會丟擲致命的 PHP 錯誤,如下所示。
致命錯誤: 類 X 包含 1 個抽象方法,因此必須宣告為 abstract 或實現其餘方法(X::x)