1、实例演示四个属性重载的魔术方法;
2、实例演示call_user_func_array()回调执行函数/对象/类的方法的流程与方式;
3、实例演示方法重载的实现原理与参数获取方式;
4、实例演示数据库连接调用的实现原理与过程(静态方法重载__callStatic实现)
总结:
【1.2.3】集中到一个实例中演示。【4】数据库连接调用在一个实例中演示。
经过练习发现听得懂看得懂,轮到自己写感觉还是不熟练。总结一下完成过程中发现的问题:
1、使用__unset()自动重载unset()来删除类内成员属性,发现unset后确实访问不到了,但是isset()检查这个属性还是存在,还可以赋值,赋值后又可以正常访问到了。
2、为了避免外部访问重载的魔术方法,我把__set()设为private,结果php会给出警告,建议设为public,这是为什么?
3、对于__call()和__callStatic(),在练习中发现,__call()是可以不管你是静态方法还是实例方法,只要使用$obj->methodname()来调用无权访问或不存在的方法,都自动执行到__call(),在这里随便是private方法还是static方法,都可以在类内转调用,也就是可以实现外部访问类内的私有方法。而__callStatic()则只能针对ClassName::methodname()的自动处理,如果在这里执行类内的常规成员方法,会执行,但要给出一个“非静态声明”的警告。
4、没搞明白的是 --->下面这句代码 应该是调用了5次 __callStatic(),那是不是在__callStatic()里,建立了5次连接,实例化了5次 Query?我在代码中做了微调,竟然也成功了。
$staffs = DB::table('staff')
->field('staff_id,name,position,mobile')
->where('staff_id>4')
->limit(6)
->select();
代码如下:
实例 ---- 【1.2.3】集中到一个实例中演示 <?php namespace _1008; //创建一个画图类,为了练习类常量、静态属性、静态方法以及属性重载和方法重载; class Draw { const DPI = 72; //屏幕分辨率;类常量; public static $width = 600; //画布的宽度;静态成员: 用static限定,是类属性 public static $height = 400; //画布的高度;静态成员: 用static限定,是类属性 private $pen; //画布的笔 ;私有成员属性; private $color; //画笔的颜色;私有成员属性; private $bkcolor = '白色'; //画布的背景颜色;私有成员属性; protected $scale = 1; //图画的比例;受保护的成员属性; //构造函数 public function __construct($pen, $color) { $this->pen = $pen; $this->color = $color; } //设置属性重载:针对访问一个不存在的 public function __get($property) { return isset($property) ? $this->$property : '属性不存在'; } public function __set($property, $value) { switch (true) { case $property == 'scale': $this->$property = (($value > 0) && ($value <= 1)) ? $value : 1; break; case $property == 'pen': $this->$property = (is_string($value) ? $value : '铅笔'); break; case $property == 'color': $this->$property = (is_string($value) ? $value : '黑色'); break; case $property == 'bkcolor': $this->$property = (is_string($value) ? $value : '白色'); break; default: if (isset($property)) { $this->$property = $value; } break; } } public function __isset($property) { $has = isset($property) ? true : false; return ($property == 'scale') ? false : $has; // return ($property == 'scale') ? false : (isset($property) ? true : false); } public function __unset($property) { if ($property == 'bkcolor') { unset($this->$property); echo '成功删除 ' . $property . '属性', '<br>'; } else { echo '不允许删除' . $property . '属性', '<br>'; } return; } //设置一个静态方法来重置静态属性 //静态方法中不允许调用实例属性,但实例方法中可以使用静态属性。 public static function resetCanvas($newWidth, $newHeight) { self::$width = $newWidth; self::$height = $newHeight; } //设置一个私有的成员方法 private function drawLine() { return '画一条直线'; } private static function drawRect() { return '画一个矩形'; } //设置__call()方法重载,访问不存在或无权访问的成员方法时自动执行; public function __call($method, $params) { if (method_exists(self::class, $method)) { return call_user_func_array([(self::class), $method], $params); } return '实例方法调用:' . $method . ' 不存在!<br>参数:<pre>' . print_r($params, true) . '</pre>'; // return method_exists(self,$method)?'yes':'no'; } //设置__callStatic()方法重载,访问不存在或无权访问的静态方法时自动执行; public static function __callStatic($method, $params) { if (method_exists(self::class, $method)) { return call_user_func_array([(self::class), $method], $params); } return '静态方法调用:' . $method . ' 不存在!<br>参数:<pre>' . print_r($params, true) . '</pre>'; } } //---------------客户端测试----属性重载-----------------// echo '类常量 DPI: ' . Draw::DPI, '<br>'; echo '画布宽度: ' . Draw::$width, ' 画布高度: ' . Draw::$height, '<br>'; echo '利用静态方法重设画布尺寸', '<br>'; Draw::resetCanvas(800, 600); echo '画布宽度: ' . Draw::$width, ' 画布高度: ' . Draw::$height, '<br>'; echo '类常量和类静态属性方法,不需要实例化即可使用执行'; echo '<hr>'; $draw = new Draw('细毛笔', '黑色'); echo $draw->pen, '<br>'; echo $draw->color = '红色', '<br>'; echo isset($draw->scale) ? '有scale属性' : '无scale属性', '<br>'; echo isset($draw->bkcolor) ? '有bkcolor属性' : '无bkcolor属性', '<br>'; echo '<hr>'; echo $draw->bkcolor, '<br>'; unset($draw->bkcolor); // echo $draw->bkcolor = '红色', '<br>'; echo $draw->bkcolor, '<br>'; // echo isset($draw->bkcolor) ? '有bkcolor属性' : '无bkcolor属性', '<br>'; echo '<hr>'; unset($draw->pen); echo isset($draw->pen) ? '有pen属性' : '无pen属性', '<br>'; echo '<hr>'; //---------------客户端测试----方法重载-----------------// echo '方法重载测试:', '<br>'; echo $draw->drawLine(0, 10, 100, 10); echo '<hr>'; echo $draw->drawRect(0, 10, 100, 10); echo '<hr>'; echo $draw->drawCircle(10, 10, 50); // echo $draw::drawLine(0, 10, 100, 10); // echo '<hr>'; echo $draw::drawRect(0, 10, 100, 10); echo '<hr>'; echo $draw::drawCircle(10, 10, 50); ?> 运行实例 » 点击 "运行实例" 按钮查看在线实例
运行效果为:
实例 --- 【4】数据库连接调用在一个实例中演示 <?php namespace _1008; class Query { public $pdo = null; public $table; public $field = '*'; public $where; public $limit; public function __construct($pdo) { $this->pdo = $pdo; } public function table($tableName) { $this->table = $tableName; return $this; } public function field($fields = '*') { $this->field = empty($fields) ? '*' : $fields; return $this; } public function where($where = '') { $this->where = empty($where) ? $where : ' WHERE ' . $where; return $this; } public function limit($limit) { $this->limit = empty($limit) ? $limit : ' LIMIT ' . $limit; return $this; } public function select() { $sql = 'SELECT ' . $this->field . ' FROM ' . $this->table . $this->where . $this->limit; $stmt = $this->pdo->prepare($sql); $stmt->execute(); return $stmt->fetchAll(\PDO::FETCH_ASSOC); } } //-------------以下合并写DB class---------------// class DB { protected static $pdo = null; protected static $query = null; public static function connection() { try { self::$pdo = new \PDO('mysql:host=127.0.0.1;dbname=test', '******', '********'); } catch (PDOException $e) { die('连接数据库 失败:' . $e->getMessage()); } self::$query = new Query(self::$pdo); } public static function __callStatic($name, $argus) { return call_user_func_array([self::$query, $name], $argus); } } DB::connection(); $staffs = DB::table('staff') ->field('staff_id,name,position,mobile') ->where('staff_id>4') ->limit(6) ->select(); foreach ($staffs as $value) { print_r($value); echo '<br>'; } ?> 运行实例 » 点击 "运行实例" 按钮查看在线实例