# 综合实例

## 文件中写数据

简单写法,使用单例

```php
<?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
<?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
<?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
<?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
<?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
<?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
<?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
<?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
<?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
<?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
<?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
<?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();
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://phper.shujuwajue.com/php-gao-ji-te-xing/zong-he-shi-li.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
