php __call()方法是什么,怎么用的?

PHP / 870人浏览 / 0人评论

__call()是一个魔术方法,可以处理类内未定义的方法,让浏览器友好输出,对用户友好输出。__call()有两个参数,使用的时候需要传入两个参数,第一个参数是方法名称,第二个参数是包含传递给该方法的参数的所有值。

PHP5中的特殊方法

在php中内置了一些特书的方法,这些特殊方法被称之为魔术方法,其也有特殊的命名规则,以“__”双下划线开头的方法和函数名,所以我们自定义的函数不应该用双下划下开头,目的是为了区分魔术方法。

PHP魔术方法有哪些呢?

__construct()__autoload()__destruct()__call()__callStatic()__get()
__set()__isset()__unset()__sleep()__wakeup()__toString()__invoke()__set_state()__clone()__debugInfo() 等方法在 PHP 中被称为魔术方法(Magic methods)。在命名自己的类方法时不能使用这些方法名,除非是想使用其魔术功能。

php__call()概述

__call()是一个魔术方法,可以处理类内未定义的方法,让浏览器友好输出,对用户友好输出。__call()有两个参数,使用的时候需要传入两个参数,第一个参数是方法名称,第二个参数是包含传递给该方法的参数的所有值。

public mixed __call ( string $methord , array $arguments )

PHP的魔术方法都是成对出现,所以和__call()成对出现的是__callStatic()方法,在静态上下文中调用一个不可用的方法时会执行这个方法。(PHP 5.3.0 版本以上)

public static mixed __callStatic ( string $methord , array $arguments )

参数解释:

参数描述
string $methord是要调用的方法名。
array $arguments参数是一个枚举数组,包含着要传递给 $methord 的参数。

php__call()演示示例

在这个示例中我们随便构建一个Person类,然后当我们先实例化一个对象然后通过对象调用一个它并不包含的getUser()方法时,就会自动调用类中__call()方法。当我们调用一个这个类中并不存在的静态方法getUser()时,则会自动调用类中__callStatic()方法。

<?php
class Person
{
public function __call($methord, $arguments)
{
// 注意:$methord的值区分大小写
echo "Calling object method '$methord' " . implode(', ', $arguments) . "\n";
}
// PHP 5.3.0之后的版本
public static function __callStatic($methord, $arguments)
{
echo "Calling static method '$methord' " . implode(', ', $arguments) . "\n";
}
}
//实例化类
$obj = new Person;
$obj -> getUser('in object context');
echo "<br/>";
// PHP 5.3.0 版本以后
//使用类名调用静态方法
Person::getUser('in static context');

运行结果为:

Calling object method 'getUser' in object context
Calling static method 'getUser' in static context

使用场景

一个使用场景就是,如果调用一个对象中不存在或被权限控制的方法,不希望给我们处理报错提醒,__call()方法将会被自动调用。比如ThinkPHP3.2 Model.class.php 基类模型中的__call()方法,利用__call方法实现一些特殊的Model方法。
在下面这个示例中,连贯操作的实现、统计查询的实现、根据某个字段获取记录、根据某个字段获取记录的某个值、命名范围的单独调用支持,使用__call()方法,我们就可以实现链式操作。

    /**
     * 利用__call方法实现一些特殊的Model方法
     * @access public
     * @param string $method 方法名称
     * @param array $args 调用参数
     * @return mixed
     */
    public function __call($method, $args)
    {
        if (in_array(strtolower($method), $this->methods, true)) {
            // 连贯操作的实现
            $this->options[strtolower($method)] = $args[0];
            return $this;
        } elseif (in_array(strtolower($method), array('count', 'sum', 'min', 'max', 'avg'), true)) {
            // 统计查询的实现
            $field = isset($args[0]) ? $args[0] : '*';
            return $this->getField(strtoupper($method) . '(' . $this->db->parseKey($field, true) . ') AS tp_' . $method);
        } elseif (strtolower(substr($method, 0, 5)) == 'getby') {
            // 根据某个字段获取记录
            $field         = parse_name(substr($method, 5));
            $where[$field] = $args[0];
            var_dump($where);
            return $this->where($where)->find();
        } elseif (strtolower(substr($method, 0, 10)) == 'getfieldby') {
            // 根据某个字段获取记录的某个值
            $name         = parse_name(substr($method, 10));
            $where[$name] = $args[0];
            return $this->where($where)->getField($args[1]);
        } elseif (isset($this->_scope[$method])) {
            // 命名范围的单独调用支持
            return $this->scope($method, $args[0]);
        } else {
            E(__CLASS__ . ':' . $method . L('_METHOD_NOT_EXIST_'));
            return;
        }
    }

链式操作例:

下载ThinkPHP3.2,在Home模块中直接使用M()方法查询数据,使用链式调用,Mode.class.php中不存在的方法,将直接调用__call()方法;
首先进行数据库配置:

<?php
return array(
 //'配置项'=>'配置值'
 'DB_TYPE'               =>  'mysql',     // 数据库类型
 'DB_HOST'               =>  'localhost', // 服务器地址
 'DB_NAME'               =>  'test',          // 数据库名
 'DB_USER'               =>  'root',      // 用户名
 'DB_PWD'                =>  'root',          // 密码
 'DB_PORT'               =>  '3306',        // 端口
 'DB_PREFIX'             =>  '',    // 数据库表前缀    
);

我们已经有了数据库test,其中存在一个表:demo,直接在Home模块Index控制器中使用M方法链式查询demo表;

<?php
namespace Home\Controller;
use Think\Controller;
class IndexController extends Controller
{
    public function index()
    {
    $list_name = M('demo')->getByName('小明');//查询name为小明的记录
    print_r($list_name);
    echo "<br>";
    $id_avg = M('demo')->avg('id');//查询id的平均值
    print_r($id_avg);
        $this->show('<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} body{ background: #fff; font-family: "微软雅黑"; color: #333;font-size:24px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.8em; font-size: 36px } a,a:hover{color:blue;}</style><div style="padding: 24px 48px;"> <h1>:)</h1><p>欢迎使用 <b>ThinkPHP</b>!</p><br/>版本 V{$Think.version}</div><script type="text/javascript" src="http://ad.topthink.com/Public/static/client.js"></script><thinkad id="ad_55e75dfae343f5a1"></thinkad><script type="text/javascript" src="http://tajs.qq.com/stats?sId=9347272" charset="UTF-8"></script>','utf-8');
    }
}

演示结果:

ThinkPHP3.2链式操作

数据库表:

/*
Navicat MySQL Data Transfer

Source Server         : localhost
Source Server Version : 50553
Source Host           : localhost:3306
Source Database       : test

Target Server Type    : MYSQL
Target Server Version : 50553
File Encoding         : 65001

Date: 2020-09-30 00:53:05
*/

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for demo
-- ----------------------------
DROP TABLE IF EXISTS `demo`;
CREATE TABLE `demo` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID',
  `title` varchar(30) NOT NULL COMMENT '标题',
  `name` varchar(20) NOT NULL COMMENT '名称',
  `message` mediumtext NOT NULL COMMENT '描述',
  `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '日期',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='注释';

-- ----------------------------
-- Records of demo
-- ----------------------------
INSERT INTO `demo` VALUES ('1', '设计师', '小明', '小明讲课', '2020-09-30 00:08:24');
INSERT INTO `demo` VALUES ('2', '客服', '上飞燕', '飞燕客服', '2020-09-30 00:20:44');
INSERT INTO `demo` VALUES ('3', '前台', '农章霞', '前台小思', '2020-09-30 00:21:42');
INSERT INTO `demo` VALUES ('4', '经理', '胡适', '设计经理', '2020-09-30 00:21:42');
INSERT INTO `demo` VALUES ('5', '研发部门经理', '曹丽', '项目经理', '2020-09-30 00:23:35');

转载注明:

0 条评论

还没有人发表评论

发表评论 取消回复

记住我的信息,方便下次评论
有人回复时邮件通知我