综合实例
文件中写数据
简单写法,使用单例
<?php
// singleton & late static
class fileDb {
private $_filePath;
private $_fp;
protected static $_instance;
public static function getInstance($filePath) {
if(!isset(self::$_instance)) {
self::$_instance = new static($filePath);
}
return self::$_instance;
}
private function __construct($filePath) {
$this->_filePath = $filePath;
$this->_fp = fopen($this->_filePath, 'a+');
}
public function __destruct() {
fclose($this->_fp);
}
public function insert(array $row) {
fputcsv($this->_fp, $row);
}
}
$fileDb = fileDb::getInstance('./test.txt');
var_dump($fileDb);
$fileDb->insert(array('revin', '509129@qq.com'));
引入代码复用(Trait)
将单例模式提出来
禁止反序列化,
禁止克隆
<?php
// trait
trait Singleton {
protected static $_instance;
final public static function getInstance($config = array()) {
if(!isset(self::$_instance)) {
self::$_instance = new static($config);
}
return self::$_instance;
}
private function __construct($config) {
$this->init($config);
}
protected function init() {}
final private function __wakeup() {}
final private function __clone() {}
}
class fileDb {
use Singleton;
private $_filePath;
private $_fp;
protected function init($config) {
$this->_filePath = $config['filePath'];
$this->_fp = fopen($this->_filePath, 'a+');
}
public function __destruct() {
fclose($this->_fp);
}
public function insert(array $row) {
fputcsv($this->_fp, $row);
}
}
// step 1:
$fileDb = fileDb::getInstance(array('filePath' => './test.txt'));
$fileDb->insert(array('revin', '509129@qq.com'));
引入事件,闭包和回调函数
当除了插入操作还有其他附加操作,引入事件
<?php
// callback & closure & Event
trait Singleton {
protected static $_instance;
final public static function getInstance($config = array()) {
if(!isset(self::$_instance)) {
self::$_instance = new static($config);
}
return self::$_instance;
}
private function __construct($config) {
$this->init($config);
}
protected function init() {}
final private function __wakeup() {}
final private function __clone() {}
}
abstract class Component {
protected $_events = [];
public final function on($eventName, $handler) {
if(!isset($this->_events[$eventName])) {
$this->_events[$eventName] = [];
}
if(is_callable($handler)) {
$this->_events[$eventName][] = $handler;
}
}
public final function trigger($eventName, $data) {
if(isset($this->_events[$eventName])) {
foreach($this->_events[$eventName] as $handler) {
call_user_func($handler, $data);
}
}
}
public function hasEventHandlers($eventName) {
return !empty($this->_events[$eventName]);
}
}
class FileDb extends Component {
use Singleton;
private $_filePath;
private $_fp;
protected function init($config) {
$this->_filePath = $config['filePath'];
$this->_fp = fopen($this->_filePath, 'a+');
}
public function __destruct() {
fclose($this->_fp);
}
public function insert(array $row) {
fputcsv($this->_fp, $row);
if($this->hasEventHandlers('afterInsert')) {
$this->trigger('afterInsert', $row);
}
}
}
$fileDb = fileDb::getInstance(array('filePath' => './test.txt'));
$fileDb->on('afterInsert', function($row) {
echo "Inserted (From ".__FUNCTION__.")\n";
});
$fileDb->on('afterInsert', function($row) {
echo "Inserted2 (From ".__FUNCTION__.")\n";
});
$fileDb->insert(array('revin', '509129@qq.com'));
引入行为机制(装饰模式)
引入行为模式:动态的向一些类加入一些比不存在的功能, 比如DbBehavior,并不存在于fileDb类中,但是我们又可以使用fileDb实例调用DbBehavior中的方法
<?php
// behavior & decorator
trait Singleton {
protected static $_instance;
final public static function getInstance($config = array()) {
if(!isset(self::$_instance)) {
self::$_instance = new static($config);
}
return self::$_instance;
}
private function __construct($config) {
$this->init($config);
}
protected function init($config) {}
final private function __wakeup() {}
final private function __clone() {}
}
class FileDb extends Component {
use Singleton;
private $_filePath;
private $_fp;
protected function init($config) {
$this->_filePath = $config['filePath'];
$this->_fp = fopen($this->_filePath, 'a+');
}
public function __destruct() {
fclose($this->_fp);
}
public function getFilePointer() {
return $this->_fp;
}
public function insert(array $row) {
fputcsv($this->_fp, $row);
if($this->hasEventHandlers('afterInsert')) {
$this->trigger('afterInsert', $row);
}
}
}
abstract class Component {
protected $_events = [];
protected $_behaviors = [];
public final function on($eventName, $handler) {
if(!isset($this->_events[$eventName])) {
$this->_events[$eventName] = [];
}
if(is_callable($handler)) {
$this->_events[$eventName][] = $handler;
}
}
public final function trigger($eventName, $data) {
if(isset($this->_events[$eventName])) {
foreach($this->_events[$eventName] as $handler) {
call_user_func($handler, $data);
}
}
}
public function hasEventHandlers($eventName) {
return !empty($this->_events[$eventName]);
}
public function attachBehavior($name, $behavior) {
if($behavior instanceof Behavior) {
$this->_behaviors[$name] = $behavior;
$behavior->attach($this);
}
}
public function __call($name, $params) {
foreach($this->_behaviors as $behavior) {
if(method_exists($behavior, $name)) {
$method = new ReflectionMethod($behavior, $name);
if($method->isPublic()) {
return call_user_func_array([$behavior, $name], $params);
}
}
}
throw new Exception('Unknown method: '.get_class($this)."::$name()");
}
}
abstract class Behavior {
public $owner;
public function attach($to) {
$this->owner = $to;
}
}
class DbBehavior extends Behavior {
public function getFirstRecord() {
$fp = $this->owner->getFilePointer();
$pos = ftell($fp);
rewind($fp);
$firstLine = fgets($fp);
fseek($fp, $pos);
return $firstLine;
}
}
$fileDb = fileDb::getInstance(array('filePath' => './test.txt'));
$fileDb->on('afterInsert', function($row) {
echo "Inserted (From ".__FUNCTION__.")\n";
});
$fileDb->insert(array('revin', '509129@qq.com'));
$fileDb->attachBehavior('DbBehavior', new DbBehavior());
echo "The First Line is: ".$fileDb->getFirstRecord();
进一步优化,将行为机制和事件机制结合
自动注册绑定事件回调函数
<?php
// behavior & decorator
trait Singleton {
protected static $_instance;
final public static function getInstance($config = array()) {
if(!isset(self::$_instance)) {
self::$_instance = new static($config);
}
return self::$_instance;
}
private function __construct($config) {
$this->init($config);
}
protected function init($config) {}
final private function __wakeup() {}
final private function __clone() {}
}
class FileDb extends Component {
use Singleton;
private $_filePath;
private $_fp;
protected function init($config) {
$this->_filePath = $config['filePath'];
$this->_fp = fopen($this->_filePath, 'a+');
}
public function __destruct() {
fclose($this->_fp);
}
public function getFilePointer() {
return $this->_fp;
}
public function insert(array $row) {
fputcsv($this->_fp, $row);
if($this->hasEventHandlers('afterInsert')) {
$this->trigger('afterInsert', $row);
}
}
}
abstract class Component {
protected $_events = [];
protected $_behaviors = [];
public final function on($eventName, $handler) {
if(!isset($this->_events[$eventName])) {
$this->_events[$eventName] = [];
}
if(is_callable($handler)) {
$this->_events[$eventName][] = $handler;
}
}
public final function trigger($eventName, $data) {
if(isset($this->_events[$eventName])) {
foreach($this->_events[$eventName] as $handler) {
call_user_func($handler, $data);
}
}
}
public function hasEventHandlers($eventName) {
return !empty($this->_events[$eventName]);
}
public function attachBehavior($name, $behavior) {
if($behavior instanceof Behavior) {
$this->_behaviors[$name] = $behavior;
$behavior->attach($this);
}
}
public function __call($name, $params) {
foreach($this->_behaviors as $behavior) {
if(method_exists($behavior, $name)) {
$method = new ReflectionMethod($behavior, $name);
if($method->isPublic()) {
return call_user_func_array([$behavior, $name], $params);
}
}
}
throw new Exception('Unknown method: '.get_class($this)."::$name()");
}
}
abstract class Behavior {
public $owner;
public function attach($to) {
$this->owner = $to;
$methods = get_class_methods($this);
foreach($methods as $methodName) {
if(strpos($methodName, 'on') === 0 && strlen($methodName) > 2) {
$this->owner->on(lcfirst(substr($methodName, 2)), [$this, $methodName]);
}
}
}
}
class DbBehavior extends Behavior {
public function getFirstRecord() {
$fp = $this->owner->getFilePointer();
$pos = ftell($fp);
rewind($fp);
$firstLine = fgets($fp);
fseek($fp, $pos);
return $firstLine;
}
public function onAfterInsert($row) {
echo "Inserted (From ".__CLASS__.")\n";
}
}
$fileDb = fileDb::getInstance(array('filePath' => './test.txt'));
$fileDb->attachBehavior('DbBehavior', new DbBehavior());
$fileDb->insert(array('revin', '509129@qq.com'));
echo "The First Line is: " . $fileDb->getFirstRecord();
进一步引入命名空间,自动加载
文件结构
base目录
---Behavior.php
---Component.php
---Singleton.php
DbBehavior.php
FileDb.php
index.php
base/Behavior.php
<?php
namespace app\base;
abstract class Behavior {
public $owner;
public function attach($to) {
$this->owner = $to;
$methods = get_class_methods($this);
foreach($methods as $methodName) {
if(strpos($methodName, 'on') === 0 && strlen($methodName) > 2) {
$this->owner->on(lcfirst(substr($methodName, 2)), [$this, $methodName]);
}
}
}
}
base/Component.php
<?php
namespace app\base;
include_once(APP_ROOT.DIRECTORY_SEPARATOR.'base'.DIRECTORY_SEPARATOR.'Behavior.php');
use app\base\Behavior;
use \ReflectionMethod;
abstract class Component {
protected $_events = [];
protected $_behaviors = [];
public final function on($eventName, $handler) {
if(!isset($this->_events[$eventName])) {
$this->_events[$eventName] = [];
}
if(is_callable($handler)) {
$this->_events[$eventName][] = $handler;
}
}
public final function trigger($eventName, $data) {
if(isset($this->_events[$eventName])) {
foreach($this->_events[$eventName] as $handler) {
call_user_func($handler, $data);
}
}
}
public function hasEventHandlers($eventName) {
return !empty($this->_events[$eventName]);
}
public function attachBehavior($name, $behavior) {
if($behavior instanceof Behavior) {
$this->_behaviors[$name] = $behavior; $behavior->attach($this);
}
}
public function __call($name, $params) {
foreach($this->_behaviors as $behavior) {
if(method_exists($behavior, $name)) {
$method = new ReflectionMethod($behavior, $name);
if($method->isPublic()) {
return call_user_func_array([$behavior, $name], $params);
}
}
}
throw new Exception('Unknown method: '.get_class($this)."::$name()");
}
}
base/Singleton.php.php
<?php
namespace app\base;
trait Singleton {
protected static $_instance;
final public static function getInstance($config) {
if(!isset(self::$_instance)) {
self::$_instance = new static($config);
}
return self::$_instance;
}
private function __construct($config) {
$this->init($config);
}
protected function init() {}
final private function __wakeup() {}
final private function __clone() {}
}
DbBehavior.php
<?php
namespace app;
include_once(APP_ROOT.DIRECTORY_SEPARATOR.'base'.DIRECTORY_SEPARATOR.'Behavior.php');
use app\base\Behavior;
class DbBehavior extends Behavior {
public function getFirstRecord() {
$fp = $this->owner->getFilePointer();
$pos = ftell($fp);
rewind($fp);
$firstLine = fgets($fp);
fseek($fp, $pos);
return $firstLine;
}
public function onAfterInsert($row) {
echo "Inserted (From ".__CLASS__.")\n";
}
}
FileDb.php
<?php
namespace app;
include_once(APP_ROOT.DIRECTORY_SEPARATOR.'base'.DIRECTORY_SEPARATOR.'Component.php');
include_once(APP_ROOT.DIRECTORY_SEPARATOR.'base'.DIRECTORY_SEPARATOR.'Singleton.php');
use app\base\Component;
use app\base\Singleton;
class FileDb extends Component {
use Singleton;
private $_filePath;
private $_fp;
protected function init($config) {
$this->_filePath = $config['filePath'];
$this->_fp = fopen($this->_filePath, 'a+');
}
public function __destruct() {
fclose($this->_fp);
}
public function getFilePointer() {
return $this->_fp;
}
public function insert(array $row) {
fputcsv($this->_fp, $row);
if($this->hasEventHandlers('afterInsert')) {
$this->trigger('afterInsert', $row);
}
}
}
index.php
<?php
namespace app;
error_reporting(E_ALL);
ini_set('display_errors', true);
define('APP_ROOT', __DIR__);
include(APP_ROOT.'/FileDb.php');
include(APP_ROOT.'/DbBehavior.php');
$fileDb = fileDb::getInstance(array('filePath' => APP_ROOT .DIRECTORY_SEPARATOR. 'test.txt'));
$fileDb->on('afterInsert', function($row) {
echo "Inserted (From ".__FUNCTION__.")\n";
});
$fileDb->attachBehavior('DbBehavior', new DbBehavior());
$fileDb->insert(array('revin', '509129@qqcom'));
echo "The First Line is: ".$fileDb->getFirstRecord();
进一步优化,使用自动加载机制
使用了自动加载机制,其它文件中的include删掉即可.
<?php
namespace app;
define('APP_ROOT', __DIR__);
function autoload($className) {
if (strpos($className, 'app\\') === 0) {
$className = str_replace('app\\', '', $className);
}
$classFile = APP_ROOT.DIRECTORY_SEPARATOR.str_replace('\\', DIRECTORY_SEPARATOR, $className).'.php';
include ($classFile);
}
spl_autoload_register('app\autoload'); //注册
try {
$fileDb = fileDb::getInstance(array('filePath' => APP_ROOT .DIRECTORY_SEPARATOR. 'test.txt'));
} catch (Exception $e) {
echo $e->getMessage();
}
$fileDb->on('afterInsert', function($row) {
echo "Inserted (From ".__FUNCTION__.")\n";
});
$fileDb->attachBehavior('DbBehavior', new DbBehavior());
$fileDb->insert(array('revin', '509129@qqcom'));
echo "The First Line is: ".$fileDb->getFirstRecord();
Last updated