PHP延迟静态绑定

这段时间看项目后台的PHP代码,看到了类似于以下的一段代码,我把它抽出来:

<?php
    class DBHandler {
        function get() {}
    }

    class MySQLHandler extends DBHandler {
        // 这里一个create
        public static function create() {
            echo "MySQL";
            return new self();
        }

        public function get() {
            echo "MySQL get()";
        }
    }

    class MemcachedHandler extends DBHandler {
        // 这里又有一个create
        public static function create() {
            echo "Memcached";
            return new self();
        }

        public function get() {
            echo "Memcached get";
        }
    }

    function get(DBHandler $handler) {
        $handler->get();
    }

    $dbHandler = MySQLHandler::create();
    get($dbHandler);
?>

有没有嗅到坏代码的味道?可以看到,在MySQLHandler和MemcachedHandler类中,都有一个create函数,除掉我的输出语句,发现它们一模一样,这就是代码冗余。是的,需要进行代码重构。

进行代码重构
<?php
    class DBHandler {
        public static function create() {
            echo "create";
            return new self();
        }

        function get() {}
    }

    class MySQLHandler extends DBHandler {
        public function get() {
            echo "MySQL get()";
        }
    }

    class MemcachedHandler extends DBHandler {
        public function get() {
            echo "Memcached get";
        }
    }

    function get(DBHandler $handler) {
        $handler->get();
    }

    $dbHandler = MySQLHandler::create();
    get($dbHandler);
?>

将create函数移到DBHandler类中,看起来还不错,至少少了一坨那糟糕的代码。

貌似是错的

运行一下,却发现,并没有打印出我们期望的MySQL get()。什么情况?这说明,并没有调用MySQLHandler的get函数,但是代码明明调用了啊,这说明,new self()这句代码有问题。这有什么问题?这就需要说到今天总结的重点了————延迟静态绑定。

延迟静态绑定

在PHP5.3以后引入了延迟静态绑定。再看下面这段代码:

<?php
    class A {
        public static function who() {
            echo __CLASS__;
        }
        public static function test() {
            self::who();
        }
    }

    class B extends A {
        public static function who() {
            echo __CLASS__;
        }
    }

    B::test();
?>

上面的代码输出了A,但是我希望它输出B,这就是问题的所在。这也是self和CLASS的限制。使用self::或者 CLASS对当前类的静态引用,==取决于定义当前方法所在的类==。所以,这就很好的解释了为什么上面的代码输出了A。但是,如果我们需要输出B呢?可以这么干:

<?php
    class A {
        public static function who() {
            echo __CLASS__;
        }
        public static function test() {
            static::who(); // 这里有变化,后期静态绑定从这里开始
        }
    }

    class B extends A {
        public static function who() {
            echo __CLASS__;
        }
    }

    B::test();
?>

通过引入延迟静态绑定功能,可以使用static作用域关键字访问类的属性或者方法的==最终值==,通过使用静态作用域,可以强制PHP在最终的类中查找所有属性的值。除了这个延迟绑定行为,PHP还添加了get_called_class()函数,这允许检查继承的方法是从哪个派生类调用的。以下代码显示了使用get_called_class()函数获得当前的类调用场景的方法。

g<?php

class ParentBase {

  public static function render() {

    return get_called_class();

  }

}

class Decendant extends ParentBase {}

echo Descendant::render();

Descendant

这就是后期静态绑定的根本————static关键字的另类用法。对于文章一开始的例子,可以这么改:

return new static(); // 改变这里,后期静态绑定

这种使用后期静态绑定,在使用PHP实现23中设计模式的时候,你会感到很轻松的。

  • 总结

就是一个很简单的知识点,但是却非常有用,总结起来,还是查了一些资料,补充一下知识点。温故而知新。好了,希望对大家有帮助。如果大家有什么建议,让我的文章写的更好,尽管提出来,我需要大家的帮助。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值