Blogger Information
Blog 38
fans 0
comment 0
visits 23402
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
方法重载与静态继承---2018-9-9
晓明的博客
Original
766 people have browsed it

一.方法的重载

  * 重载: 动态的"创建"出类的属性和方法
 * 重载都是借助: 魔术方法来实现的,用双下划线开头的特殊方法
 * 重载方法必须声明为: public
 * 重载分为: 属性重载和方法重载
 * 属性重载: __get(),__set(),__isset(),__unset()
 * 方法重载: __call(), __callStatic()
 * 1. __call($method, $arguments): 当用户访问一个不存在或无权限的方法时调用
 * 2.__callStatic($method, $arguments):当用户访问一个不存在或无权限的静态方法时调用

 

实例

<?php

class Test
{
    // 普通方法的重载
    public function __call($method, $arguments)
    {
//        return $method;  // 方法名称
//        return $arguments;
        $args = implode(',',$arguments);
        return '方法名: '. $method. '<br>参数: '. $args;
    }

    //创建一个私有方法
    private function select()
    {
        return __METHOD__;
    }

    // 静态方法的重载
    public static function __callStatic($name, $arguments)
    {
        $args = implode(',',$arguments);
        return '方法名: '. $name. '<br>参数: '. $args;
    }
}

$test = new Test();
//访问一个不存在的非静态/普通/动态方法
//echo $test->show(), '<br>';
//print_r($test->show('合肥','杭州','上海'));
//echo $test->show('合肥','杭州','上海'), '<br>';

echo $test->select('staff','id,name,age'),'<br>';
echo '<hr>';
// 我从类外部访问一个不存在的静态方法
echo Test::assign('html','css','javascript');

// 方法重载的作用绝不是这么简单

运行实例 »

点击 "运行实例" 按钮查看在线实例

二.call_user_func_array()的使用方法

    call_user_func_array():执行方法或回调函数
  call_user_func_array(函数/方法[, 参数数组])

  

实例

<?php
/**
 * call_user_func_array():执行方法或回调函数
 * call_user_func_array(函数/方法[, 参数数组])
 */

//call_user_func_array()的使用场景:
//场景一: 执行回调函数
// 计算二个整数之和
echo call_user_func_array(function($m,$n){return $m+$n;},[10,20]),'<hr>';

//场景二: 执行对象方法
class Hello1
{
    public function add($m, $n)
    {
        return $m + $n;
    }
}
//call_user_func_array([对象, '方法'],[参数数组])
//$obj = new Hello1();
//$method = 'add';
//$args = [30, 50];
//echo call_user_func_array([$obj, $method],$args), '<hr>';
//可以简写:
echo call_user_func_array([(new Hello1()), 'add'],[35,50]),'<hr>';

//场景三: 执行类中的静态方法
class Hello2
{
    public static function add($m, $n)
    {
        return $m + $n;
    }
}

//Hello2::add()
echo call_user_func_array(['Hello2','add'],[40,60]),'<hr>';//这个必须是静态的,不然不可以访问

运行实例 »

点击 "运行实例" 按钮查看在线实例

三.使用___callStaic 和call_user_func_array函数

    模拟ThinkPHP5.1中的数据库链式操作

     1.操作访问类

        

实例

<?php
/**
 * 方法重载的实战案例: 模拟ThinkPHP5.1中的数据库链式操作
 * 用方法重载实现方法跨类调用
 */

// Db::table()->fields()->where()->select();
require 'Query.php';
// 数据库操作的入口类
class Db
{
    public static function __callStatic($name, $arguments)
    {
        //call_user_func_array([类名, 方法],[])
        //call_user_func_array([对象, 方法],[])
        return call_user_func_array([(new Query()),$name],$arguments);
    }
}

$result = Db::table('staff')
            ->fields('id,name,age,salary')
            ->where('salary > 2000')
            ->select();
//print_r($result);
// 用表格将查询结果格式化输出
$table = '<table border="1" cellpadding="5" cellspacing="0" width="60%" align="center">';
$table .= '<caption style="font-size: 1.5rem;margin:15px;">员工信息表</caption>';
$table .= '<tr bgcolor="#90ee90"><th>ID</th><th>姓名</th><th>年龄</th><th>工资</th></tr>';

foreach ($result as $staff) {
    $table .= '<tr align="center">';
    $table .= '<td>'.$staff['id'].'</td>';
    $table .= '<td>'.$staff['name'].'</td>';
    $table .= '<td>'.$staff['age'].'</td>';
    $table .= '<td>'.$staff['salary'].'</td>';
    $table .= '</tr>';
}

$table .= '</table>';
$num = '<p style="text-align: center"> 共计:  <span style="color:red">'.count($result).'</span>   条记录</p>';
echo $table, $num;

运行实例 »

点击 "运行实例" 按钮查看在线实例

    2.具体调用的类 Query.php

    

实例

<?php
/**
 * 数据库查询类
 */

class Query
{
    // 保存sql语句中的各个组成部分
    // SELECT 字段列表 FROM 表名 WHERE 条件
    private $sql = [];

    // 数据库的连接对象
    private $pdo = null;

    //构造方法: 连接数据库
    public function __construct()
    {
        // 连接数据库并返回pdo对象
        $this->pdo = new PDO('mysql:host=127.0.0.1;dbname=php','root','root');
    }
    // table()获取sql语句的表名
    public function table($table)
    {
        $this->sql['table'] = $table;
        return $this;  //返回当前类实例对象,便于链式调用该对象的其它方法
    }

    // fields()获取sql语句的字段列表
    public function fields($fields)
    {
        $this->sql['fields'] = $fields;
        return $this;
    }

    // where()获取sql语句的查询条件
    public function where($where)
    {
        $this->sql['where'] = $where;
        return $this;
    }

    //执行查询,是一个终级方法,这里是终极方法,不可return $this
    public function select()
    {
        //拼装SELECT查询语句
        $sql = "SELECT {$this->sql['fields']} FROM {$this->sql['table']} WHERE {$this->sql['where']}";
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute();
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

}

运行实例 »

点击 "运行实例" 按钮查看在线实例


   四.后静态访问

    将 static 想像成一个变量: 始终指向静态方法的调用者

   

实例

<?php
/**
 * static 关键字的用途:
 * 1. 定义静态成员;
 * 2. 后期静态绑定
 *
 * 后期静态绑定:静态继承的上下文环境,用于动态设置静态方法的调用者
 */
class One
{
    public static function hello()
    {
        return __METHOD__;  // 返回当前方法名
    }

    public static function world()
    {
//        return self::hello();//子类调用哪怕子类有重写方法也访问父类的
        return static::hello();
    }
}

class Two extends One
{
    public static function hello()
    {
        return __METHOD__;  // 返回当前方法名
    }
}
// 静态继承上下文执行环境: 静态继承
echo Two::hello();
echo '<hr>';

echo Two::world(); //One::hello
//代码结果看上去似乎是正确的,但是业务逻辑说不通
//在子类Two中将父类中的hello()进行重写,在调用world()时,本意是想调用子类中已重写的方法hello()
// 并不想调用父类的,在父类中却不能正确识别出当前的调用者是哪个?

// 代码执行分二种个阶段: 前期:编译阶段, 后期:运行阶段
// 这种在运行阶段才确定方法的调用者的技术: 后期[运行阶段]静态绑定, 延迟静态绑定

//将 static 想像成一个变量: 始终指向静态方法的调用者

运行实例 »

点击 "运行实例" 按钮查看在线实例


   2.后静态绑定的具体实例

   

实例

<?php
/**
 * 后期静态绑定的小案例
 *
 */
class Db1
{
    public static $pdo = null;
    //连接数据库
    public static function connect()
    {
        self::$pdo = new PDO('mysql:host=127.0.0.1;dbname=phpch','root','root');
    }

    public static function query()
    {
        $stmt = self::$pdo->prepare("SELECT `name`,`salary` FROM `staff` LIMIT 3");
        $stmt->execute();
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }

    public static function select()
    {
        self::connect();
//        return self::query();
        return static::query();
    }

}

class Db2 extends Db1
{
    public static function query()
    {
        $stmt = self::$pdo->prepare("SELECT `name` AS `姓名`,`email` AS `邮箱` FROM `user` LIMIT 3");
        $stmt->execute();
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
}
echo '<pre>';
//print_r(Db1::select());
print_r(Db2::select());

运行实例 »

点击 "运行实例" 按钮查看在线实例


Correction status:Uncorrected

Teacher's comments:
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post