Blogger Information
Blog 42
fans 2
comment 0
visits 54259
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
静态成员与方法重载(对象成员访问限制,静态属性,静态方法,类常量,静态属性、静态方法的重载,案例连式操作)2019年3月4日22时
小明的博客
Original
1832 people have browsed it

今天,我们学习了静态成员与方法重载,具体内容由对象成员的访问限制,静态属性 方法的定义与访问,类常量与静态属性的区别与相同,静态属性方法的重载,还做了案例:仿Thinkphp的连式调用。

一、对象成员的访问限制

访问限定符规定了对象属性、方法的作用域,public在类内类外子类都可用,protected在类内 子类可用 ,private在类内可用,但是要在类外访问protected private的属性怎么办,通常是先用构造函数把各个属性初始化,然后在通过public的返回,外部就可以调用了。

实例

<?php
class Demo06
{
    public $name;           //姓名
    protected $position;    //职位
    private $salary;        //工资
    protected $department;  //部门
    //构造函数
    public function __construct($name, $position, $salary, $department)
    {
        $this->name = $name;
        $this->position = $position;
        $this->salary = $salary;
        $this->department = $department;
    }
//    获取职位的方法
    public function getPosition(){
        return $this->department === '培训部' ? $this->position : '无权查看';
    }
//    获取工资的方法
    public function getSalary(){
        return $this->department ==='财务部' ? $this->salary : '无权查看';
    }
    public function setSalary($salary){
        return $this->department ==='财务部' ? $this->salary = $salary : '无权更新';
    }
}

$obj = new Demo06('明仔', '程序员', 9999, '培训部');
//$obj = new Demo06('明仔', '程序员', 9999, '财务部');
echo $obj->name.'<br>';
//echo $obj->position.'<br>';
//echo $obj->salary.'<br>';
echo $obj->getPosition().'<br>';
echo $obj->getSalary().'<br>';
$obj->setSalary(1111);
echo $obj->getSalary().'<hr>';
/**************************************/
class sub extends Demo06
{

}
$obj = new sub('豆豆', '职员', 8888, '财务部');
echo $obj->getSalary().'<br>';
echo $obj->getPosition();

运行实例 »

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

二、静态成员的定义与访问

类一般作为实例化对象的模版,但是存在以下的情况,可以不实例化成对象,直接用类来访问属性 方法,这就是静态属性、静态方法,统称为静态成员。

情况一、有时一个类只实例化成一个对象,那么为何不用类直接访问属性和方法?

情况二、有时同一个类实例化的许多对象,都有共同的属性需要调用,这样为何不给类一个统一属性,让他们共同调用,而不是实例化一次调用一次

具体访问是是不需要实例化  直接类::属性名  或者类::方法()

ps实例化的对象不能访问静态属性 但是可以访问静态的方法

实例

<?php
//类一般作为实例化对象的模版,访问类中的属性 方法都是先实例化成对象然后调用,但是可不可以通过类直接访问?
//静态属性 静态方法可以不实例化访问,静态成员的引入可以解决两个问题
//1就是有的时候只需要一个对象  那么实例化和直接用类是一样的
//2有的时候实例化成许多的对象,如果需要共享的属性,还的一个个赋值给属性  麻烦

class Demo01
{
    public $product;
    public static $price;
//    构造函数舒适化
    public function __construct($product, $price)
    {
        $this->product = $product;
        self::$price = $price;
    }
//    对象方法
    public function getInfo1(){
        return $this->product.'价格是:  '.self::$price;
    }
//    静态方法
    public static function getInfo2($product){
        return $product."价格是:   ".self::$price;
    }
}
$obj = new Demo01('***', 5433);
echo $obj->product.'<br>';
echo Demo01::$price.'<br>';
echo $obj->getInfo1().'<br>';
echo Demo01::getInfo2($obj->product).'<br>';
//对象不能访问静态属性  但是可以访问静态方法
echo $obj->getInfo2($obj->product);

运行实例 »

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

三、类常量的定于与访问

类常量与静态属性基本一致,不同的是类常量的值不允许改变,静态属性可以被修改

实例

<?php
//类常量
class Demo02
{
    //类常量同类属性一样,不需要实例化调用,而是直接由类调用
    //区别是类常量不能改变,类属性可以改变
    const NATION = '中国';
    public static $sex = '男';
    private $name;
    public function __construct($name)
    {
        $this->name = $name;
    }
    public function getInfo()
    {
        //类常量和类属性一样在类内调用的话用self
        return $this->name.'性别是: '.self::$sex.',国籍是:'.self::NATION.'<br>';
    }
}
$obj = new Demo02('明仔');
echo $obj->getInfo();
//修改类属性
Demo02::$sex = '保密';
//修改类常量出错
//Demo02::NATION = 'riben';
echo $obj->getInfo();

运行实例 »

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

四、属性重载

但在类外访问protected  private属性是统称被限制,针对上述情况,由魔术方法来解决问题。

__get($name)  出现不能访问的情况,就自动调用此方法,然后将属性名作为参数穿进去,然后该方法在进行处理

__set($name, $value) 这方法是设置器

__isset($name) 这是判断是否由该属性

__unset($name)是销毁属性

实例

<?php
//属性重载
class Demo11
{
    //设置私有属性
    private $name;
    private $salary;
    protected $secret = '我有一个小秘密';
    public function __construct($name, $salary)
    {
        $this->name = $name;
        $this->salary = $salary;
    }
    //用__get 出现不能显示的类属性自动调用该方法作为获取器
    public function __get($name)
    {
        //对用户进行判断 如果要查看secret 那么必须是admin的用户才能查看 否则无权查看
        //  其他的类属性就可以直接查看
        if ($name === 'secret') {
            return $this->name === 'admin' ? $this->$name : '无权查看';
        }
        return $this->$name;
    }
    //__set 出现不能显示的类属性后 对该属性进行设置

    public function __set($name, $value)
    {
        // 直接返回, 极少这样做
//        $this->$name = $value;

        // 添加过滤机制
        if ($name === 'salary') {
            return $this->name === 'admin' ? $this->$name = $value : '无权修改';
        }
        return $this->$name = $value;
    }

    public function __isset($name)
    {
        if ($this->name === 'admin') {
            if (isset($this->$name)) {
                echo '属性存在';
            } else{
                echo '属性不存在';
            }
        } else{
            echo '无权检测';
        }
    }

    public function __unset($name)
    {
        if ($this->name === 'admin') {
            unset($this->$name);
        } else {
                echo '无权删除';
        }
    }

}

$obj = new Demo11('明仔', 1111);

echo $obj->name.'<br>';
$obj = new Demo11('admin', 9999);
echo $obj->secret.'<br>';
$obj->salary = 8888;
echo $obj->salary;
echo "<hr>";
isset($obj->salary);
echo '<br>';
unset($obj->salary);
isset($obj->salary);

运行实例 »

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

五、方法重载

针对在类外不能访问的方法由__call  今天方法__callStatic()

还有两个方法  call_user_func()  call_user_func_array()  他们将函数名作为参数,函数里的参数作为参数的两个方法,后者是吧参数用数组的形式穿进去

实例

<?php
//方法重载
class Demo12
{
    //出现没有的类方法是自动调用__call  $name是方法名,$arguments 是所有参数
    public function __call($name, $arguments)
    {
        return '方法名是  '. $name . '<br> 参数列表是' .'<pre>'.print_r($arguments, true);
    }
    //也适用于静态方法
    public static function __callStatic($name, $arguments)
    {
        return '方法名是  '. $name . '<br> 参数列表是' .'<pre>'.print_r($arguments, true);
    }

}
$obj = new Demo12();
echo $obj->getInfo('jj', 'kk', 123);
echo '<hr>';
echo Demo12::getInfo11(10, 20, 30);
echo '<hr>';

//  做个案例
//先了解两个函数
//call_user_func()  就是将一个函数作为参数  这个函数的参数做为他的参数 进行回调执行
//call_user_func_array()  和上面基本一致  只不过第二个参数是回调函数的参数组成的数组
function sum ($a, $b) {
    return $a . '+' . $b .'='.($a+$b);
}

echo sum(10, 20);
echo '<br>';
//回调的方式为
echo call_user_func('sum', 10, 20);
echo '<br>';
echo call_user_func_array('sum', [10, 20]);
echo '<br>';
//那么把方法放在函数里 也可以调用
class Test1
{
     public function sum ($a, $b) {
         return $a . '+' . $b .'='.($a+$b);
     }
}
$obj = new Test1();

echo call_user_func([$obj, 'sum'], 20, 40);
echo '<br>';
echo call_user_func([new Test1(), 'sum'], 20, 40);
echo '<br>';

//类的静态方法也适用
class Test2
{
    public static function mul ($a, $b) {
        return $a . '*' . $b .'='.($a*$b);
    }
}

echo call_user_func('Test2::mul', 20, 40);
echo '<br>';
//也可以
echo call_user_func_array(['Test2', 'mul'], [20, 40]);
echo '<br>';
echo Test2::class;    //可以输出类的字符串
echo '<br>';
//也可以
echo call_user_func_array([Test2::class, 'mul'], [20, 40]);

运行实例 »

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

六、案例:连式调用

实例

<?php
//模拟ThinkPhp 连式操作 查询数据库
//引用外部类
require 'Query1.php';
class Db1
{
    //数据库连接对象初始化
    protected static $pdo = null;
    //数据库连接方法 实现惰性连接 每次用时在连接  节省资源
    public static function connection () {
        self::$pdo = new PDO('mysql:dbname=php', 'root', 'root');
    }
    //  查询类的入口  通过用__callStatic  方法实现跨类调用
    public static function __callStatic($name, $arguments)
    {
        //创建pdo对象连接数据库
        self::connection();
        //实例化查询类 将连接对象作为参数
        $query = new Query1(self::$pdo);
        return call_user_func_array([$query, $name], [$arguments[0]]);
    }
}


$staffs = Db1::table('staff')
    ->field('id,name,position,mobile')
    ->where('id > 5')
    ->limit(5)
    ->select();
foreach ($staffs as $staff) {
    echo '<pre>'.print_r($staff, true);
}

运行实例 »

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

Query.php

实例

<?php
//模拟ThinkPhp 连式操作 查询数据库
//引用外部类
require 'Query1.php';
class Db1
{
    //数据库连接对象初始化
    protected static $pdo = null;
    //数据库连接方法 实现惰性连接 每次用时在连接  节省资源
    public static function connection () {
        self::$pdo = new PDO('mysql:dbname=php', 'root', 'root');
    }
    //  查询类的入口  通过用__callStatic  方法实现跨类调用
    public static function __callStatic($name, $arguments)
    {
        //创建pdo对象连接数据库
        self::connection();
        //实例化查询类 将连接对象作为参数
        $query = new Query1(self::$pdo);
        return call_user_func_array([$query, $name], [$arguments[0]]);
    }
}


$staffs = Db1::table('staff')
    ->field('id,name,position,mobile')
    ->where('id > 5')
    ->limit(5)
    ->select();
foreach ($staffs as $staff) {
    echo '<pre>'.print_r($staff, true);
}

运行实例 »

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

总结

1、静态成员可以不用实例化不需要对象调用,有时比较简便

2、类常量是不能修改的

3、属性重载可以不用每个访问不到的属性单独设置获取的方法,只需要一个获取去 根据属性名来获取属性值

4、方法 重载同属性重载的意义一样,这里需要注意call_user_func call_user_func_array  这俩个回调函数的妙用,在后面的案例中,他作为跨类访问的入口,可以现在另外的类中定义好各种方法 然后根据情况在调用

5、连式调用的核心在与每个方法最后都返回$this 对象本身,这样才能让下一个方法由对象看调用  实现连式调用

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