Любые реальные простые образцы использования абстрактного класса? Я пытаюсь войти в ООП PHP, но я все еще не могу понять – зачем использовать абстрактный класс и когда (Да, я знаю, что невозможно создать экземпляр абстрактного класса, только экземпляр класса, наследующий его).
Возможно, у вас есть класс изображений, и у вас есть 2 драйвера, GD и ImageMagick.
Ваш базовый класс может быть
abstract class Image { public function resize($width, $height) { // Some prep code... } }
Тогда ваш драйвер GD будет похож на
class Image_Gd extends Image { public function resize($width, $height) { // Actual code } }
Посмотрите на источник Коханы на GitHub . Он имеет класс Image
который является abstract
.
ОК, допустим, вы хотите загрузить конфигурацию скрипта. Эта конфигурация может быть сохранена в файле базы данных / XML / INI / YAML. Каждый драйвер должен реализовать некоторый интерфейс, назовем его ConfigurationLoader
.
interface ConfigurationLoader { public function load(); public function get($key, $default = null); } // The final usage of the code: $configuration = new XMLConfiguration('./some/file.xml'); $configuration = new YAMLConfiguration('./some/file.yaml'); $configuration = new DatabaseConfiguration($dbHandler, 'table_name'); $configuration->load(); echo $configuration->get('abc.def.ghi');
Теперь нам нужно внедрить наши драйверы. Первое, что вы должны заметить, это то, что драйверы на основе файлов, вероятно, работают одинаково. Единственное различие заключается в том, что каждый из них разбирает источники файлов по-разному. С другой стороны, драйвер базы данных работает совсем по-другому.
class DatabaseConfiguration implements ConfigurationLoader { protected $config = array(); protected $pdo, $tableName; public function __construct(PDO $dbHandler, $tableName) { $this->pdo = $pdo; $this->tableName = $tableName; } public function load() { $this->config = /* fetch data from database */; } public function get($key, $default = null) { return array_key_exists($this->config, $key) ? $this->config[$key] : $default; } }
Теперь нам нужно реализовать драйвер XML, INI и YAML. Все они работают почти одинаково, поэтому … давайте создадим абстрактный класс, который будет обрабатывать общий код:
abstract class FileConfiguration implements ConfigurationLoader { // Each file-based configuration loader has a constructor that takes file name as first argument protected $filename; public function __construct($filename) { $this->filename = $filename; $this->getFileContents(); } // Each file-based driver has to store file content protected $fileContent; protected function getFileContents() { $this->fileContents = file_get_contents($this->filename); } // Each driver will have to implement its own implementation of load(). // XMLConfiguration will parse XML, INIConfiguration will parse INI etc. abstract public function load(); // However all of them will store parsed configuration in $config array: protected $config = array(); public function get($key, $default = null) { return array_key_exists($this->config, $key) ? $this->config[$key] : $default; } }
FileConfiguration
должен быть абстрактным, потому что он не знает, как разбирать содержимое файла. Только доставленные классы знают, как это сделать:
class XMLConfiguration extends FileConfiguration { public function load() { $xml = simplexml_load_string($this->fileContents); foreach ($xml->root as $config) { $this->config[(string) $config->key] = (string) $config->value; } } } class YAMLConfiguration extends FileConfiguration { public function load() { $yaml = new SomeYAMLParser($this->fileContents); foreach ($yaml->parse() as $config) { $this->config[$config['key']] = $config['value']; } } } class INIConfiguration extends FileConfiguration { public function load() { ... } }
Как вы можете видеть в этом примере, может быть еще один абстрактный класс AbstractConfiguration
который будет хранить $config
property и get($key, $default = null)
и это будет родительский класс для DatabaseConfiguration
и FileConfiguration
.