• 面向对象魔术常量


    1. __construct: 

         内置构造函数,在对象被创建时自动调用。见如下代码:

    复制代码
    <?php
    class ConstructTest {
        private $arg1;
        private $arg2;
    
        public function __construct($arg1, $arg2) {
            $this->arg1 = $arg1;
            $this->arg2 = $arg2;
            print "__construct is called...
    ";
        }
        public function printAttributes() {
            print '$arg1 = '.$this->arg1.' $arg2 = '.$this->arg2."
    ";
        }
    }
    $testObject = new ConstructTest("arg1","arg2"); 
    $testObject->printAttributes();
    复制代码

         运行结果如下:

    Stephens-Air:Desktop$ php Test.php 
    __construct is called...
    $arg1 = arg1 $arg2 = arg2

    2. parent: 

         用于在子类中直接调用父类中的方法,功能等同于Java中的super。 

    复制代码
    <?php
    class BaseClass {
        protected $arg1;
        protected $arg2;
    
        function __construct($arg1, $arg2) {
            $this->arg1 = $arg1;
            $this->arg2 = $arg2;
            print "__construct is called...
    ";
        }
        function getAttributes() {
            return '$arg1 = '.$this->arg1.' $arg2 = '.$this->arg2;
        }
    }
    
    class SubClass extends BaseClass {
        protected $arg3;
    
        function __construct($baseArg1, $baseArg2, $subArg3) {
            parent::__construct($baseArg1, $baseArg2);
            $this->arg3 = $subArg3;
        }
        function getAttributes() {
            return parent::getAttributes().' $arg3 = '.$this->arg3;
        }
    }
    $testObject = new SubClass("arg1","arg2","arg3"); 
    print $testObject->getAttributes()."
    ";
    复制代码

         运行结果如下:

    Stephens-Air:Desktop$ php Test.php 
    __construct is called...
    $arg1 = arg1 $arg2 = arg2 $arg3 = arg3

    3. self:

         在类内调用该类静态成员和静态方法的前缀修饰,对于非静态成员变量和函数则使用this。 

    复制代码
    <?php
    class StaticExample {
        static public $arg1 = "Hello, This is static field.
    ";
        static public function sayHello() {
            print self::$arg1;
        }
    }
    
    print StaticExample::$arg1;
    StaticExample::sayHello();
    复制代码

         运行结果如下:

    Stephens-Air:Desktop$ php Test.php 
    Hello, This is static field.
    Hello, This is static field.

    4. static:

         这里介绍的static关键字主要用于PHP 5.3以上版本新增的延迟静态绑定功能。请看一下代码和关键性注释。

    复制代码
    <?php
    abstract class Base {
        public static function getInstance() {
            //这里的new static()实例化的是调用该静态方法的当前类。
            return new static();
        }
        abstract public function printSelf(); 
    }
    
    class SubA extends Base {
        public function printSelf() {
            print "This is SubA::printSelf.
    ";
        }
    }
    
    class SubB extends Base {
        public function printSelf() {
            print "This is SubB::printSelf.
    ";
        }
    }
    
    SubA::getInstance()->printSelf();
    SubB::getInstance()->printSelf();
    复制代码

         运行结果如下:

    Stephens-Air:Desktop$ php Test.php 
    This is SubA::printSelf.
    This is SubB::printSelf.

         static关键字不仅仅可以用于实例化。和self和parent一样,static还可以作为静态方法调用的标识符,甚至是从非静态上下文中调用。在该场景下,self仍然表示的是当前方法所在的类。见如下代码: 

    复制代码
    <?php
    abstract class Base {
        private $ownedGroup;
        public function __construct() {
            //这里的static和上面的例子一样,表示当前调用该方法的实际类。
            //需要另外说明的是,这里的getGroup方法即便不是静态方法,也会得到相同的结果。然而倘若
            //getGroup真的只是普通类方法,那么这里还是建议使用$this。
            $this->ownedGroup = static::getGroup();
        }
        public function printGroup() {
            print "My Group is ".$this->ownedGroup."
    ";
        }
        public static function getInstance() {
            return new static();
        }
        public static function getGroup() {
            return "default";
        }
    }
    
    class SubA extends Base {
    }
    
    class SubB extends Base {
        public static function getGroup() {
            return "SubB";
        }
    }
    
    SubA::getInstance()->printGroup();
    SubB::getInstance()->printGroup(); 
    复制代码

         运行结果如下:

    Stephens-Air:Desktop$ php Test.php 
    My Group is default
    My Group is SubB

    5. __destruct:

         析构方法的作用和构造方法__construct刚好相反,它只是在对象被垃圾收集器收集之前自动调用,我们可以利用该方法做一些必要的清理工作。

    复制代码
    <?php
    class TestClass {
        function __destruct() {
            print "TestClass destructor is called.
    ";
        }
    }
    
    $testObj = new TestClass();
    unset($testObj);
    print "Application will exit.
    ";
    复制代码

         运行结果如下:

    Stephens-Air:Desktop$ php Test.php 
    TestClass destructor is called.
    Application will exit.

    6. __clone:

         在PHP 5之后的版本中,对象之间的赋值为引用赋值,即赋值后的两个对象将指向同一地址空间,如果想基于对象赋值,可以使用PHP提供的clone方法。该方法将当前对象浅拷贝之后的副本返回,如果想在clone的过程中完成一些特殊的操作,如深拷贝,则需要在当前类的声明中实现__clone方法,该方法在执行clone的过程中会被隐式调用。另外需要格外注意的是,__clone方法是作用再被拷贝的对象上,即赋值后的对象上执行。

    复制代码
    <?php
    class InnerClass {
        public $id = 10;
        public function printSelf() {
            print '$id = '.$this->id."
    ";
        }
    }
    
    class OuterClass {
        public $innerClass;
        public function __construct() {
            $this->innerClass = new InnerClass();
        }
        public function __clone() {
            $this->innerClass = clone $this->innerClass;
            print "__clone is called.
    ";
        }
    }
    
    $outerA = new OuterClass();
    print "Before calling to clone.
    ";
    $outerB = clone $outerA;
    print "After calling to clone.
    ";
    $outerA->innerClass->id = 20;
    print "In outerA: ";
    $outerA->innerClass->printSelf();
    print "In outerB: ";
    $outerB->innerClass->printSelf();
    复制代码

         运行结果如下:

    Stephens-Air:Desktop$ php Test.php 
    Before calling to clone.
    __clone is called.
    After calling to clone.
    In outerA: $id = 20
    In outerB: $id = 10

    7. const:

        PHP5可以在类中定义常量属性。和全局常量一样,一旦定义就不能改变。常量属性不需要像普通属性那样以$开头,按照惯例,只能用大写字母来命名常量。另外和静态属性一样,只能通过类而不能通过类的实例访问常量属性,引用常量时同样也不需要以$符号作为前导符。另外常量只能被赋值为基础类型,如整型,而不能指向任何对象类型。

    <?php
    class TestClass {
        const AVAILABLE = 0;
    }
    
    print "TestClass::AVAILABLE = ".TestClass::AVAILABLE."
    ";

        运行结果如下:

    0Stephens-Air:Desktop$ php Test.php 
    TestClass::AVAILABLE = 0

    注:该Blog中记录的知识点,是在我学习PHP的过程中,遇到的一些PHP和其他面向对象语言相比比较特殊的地方,或者是对我本人而言确实需要簿记下来以备后查的知识点。虽然谈不上什么深度,但还是希望能与大家分享。

    1. __toString:

        当对象被打印时,如果该类定义了该方法,则打印该方法的返回值,否则将按照PHP的缺省行为输出打印结果。该方法类似于Java中的toString()。

    复制代码
    <?php
    class TestClass {
        public function __toString() {
            return "This is TestClass::__toString.
    ";
        }
    }
    
    $testObj = new TestClass();
    print $testObj;
    复制代码

        运行结果如下:

    Stephens-Air:Desktop$ php Test.php 
    This is TestClass::__toString.

    2. __get和__set:

        这两个方法用于处理类中未声明的属性访问。当对象使用者试图访问未声明的对象属性时,__get()会被调用,并带有一个包含要访问的属性名称字符串作为参数。无论从__get()方法返回什么,都会直接返回给调用者,就如同带有该值的属性存在一样。另外需要注意的是,如果属性存在,但是其访问可见性为private或protected,那么这两个拦截方法同样会被调用,反之,如果属性存在切可访问,那么直接访问属性即可,这两个方法将不再会被调用。以下为__get()拦截方法的示例代码:

    复制代码
    <?php
    class TestClass {
        private $privateField;
        public $publicField;
        public function __construct() {
            $this->privateField = "This is a private Field.
    ";
            $this->publicField = "This is a public Field.
    ";
        }
    
        public function __get($property) {
            print "__get() is called.
    ";
            $method = "get${property}";
            if (method_exists($this, $method)) {
                return $this->$method();
            }
            return "This is undefined field.
    ";
        }
        public function getPrivateField() {
            return $this->privateField;
        }
    }
    
    $testObj = new TestClass();
    print $testObj->privateField;
    print $testObj->undefinedField;
    print $testObj->publicField;
    复制代码

        运行结果如下:

    Stephens-Air:Desktop$ php Test.php 
    __get() is called.
    This is a private Field.
    __get() is called.
    This is undefined field.
    This is a public Field.

        __set()方法被调用的规则和__get()基本相同,差别是用于拦截未定义或不可见类属性的赋值操作。另外,该方法接收两个参数,分别是属性名称和要设定的值。见如下代码示例:

    复制代码
    <?php
    class TestClass {
        private $privateField;
        public $publicField;
        public function __construct() {
            $this->privateField = "This is a private Field.
    ";
            $this->publicField = "This is a public Field.
    ";
        }
        public function __get($property) {
            print "__get() is called.
    ";
            $method = "get${property}";
            if (method_exists($this, $method)) {
                return $this->$method();
            }
            return "This is an undefined field.
    ";
        }
        public function __set($property, $value) {
            print "__set is called.
    ";
            $method = "set${property}";
            if (method_exists($this, $method)) {
                $this->$method($value);
            } else {
                print "This is an undefined field.
    ";
            }
        }
        public function getPrivateField() {
            return $this->privateField;
        }
        public function setPrivateField($value) {
            $this->privateField = $value;
        }
    }
    
    $testObj = new TestClass();
    $testObj->privateField = "This is a private Field after set.
    ";
    $testObj->undefinedField = "This is a undefined Field after set.
    ";
    $testObj->publicField = "This is a public Field after set.
    ";
    
    print $testObj->privateField;
    print $testObj->undefinedField;
    print $testObj->publicField;
    复制代码

        运行结果如下:

    复制代码
    Stephens-Air:Desktop$ php Test.php 
    __set is called.
    __set is called.
    This is an undefined field.
    __get() is called.
    This is a private Field after set.
    __get() is called.
    This is an undefined field.
    This is a public Field after set.
    复制代码

    3. __isset和__unset:

        这两个拦截方法被调用的规则和__get()和__set()非常类似,只是用于类中不存在或不可见属性被isset()和unset()两个全局方法应用时才会被分别触发。 

    复制代码
    <?php
    class TestClass {
        private $privateField;
        public $publicField;
        public function __construct() {
            $this->privateField = "Defined private field";
            $this->publicField = "Defined public field";
        }
        public function __isset($property) {
            print "__isset is called.
    ";
            return isset($this->$property);
        }
        public function __unset($property) {
            print "__unset is called.
    ";
            if (isset($this->$property)) {
                unset($this->$property);
            }
        }
    }
    
    $testObj = new TestClass();
    print 'isset($testObj->privateField) is '.(isset($testObj->privateField) ? "true" : "false")."
    ";
    print 'isset($testObj->undefinedField) is '.(isset($testObj->undefinedField) ? "true" : "false")."
    ";
    print 'isset($testObj->publicField) is '.(isset($testObj->publicField) ? "true" : "false")."
    ";
    
    print "After unset......
    ";
    //下面两个函数调用后,$testObj的两个对象属性均会变为不可用。
    //另外从输出结果来看,__unset方法仅仅被调用一次,因为publicField为可见属性,所以__unset不会因该属性而被调用。
    unset($testObj->privateField);
    unset($testObj->publicField);
    
    print 'isset($testObj->privateField) is '.(isset($testObj->privateField) ? "true" : "false")."
    ";
    print 'isset($testObj->publicField) is '.(isset($testObj->publicField) ? "true" : "false")."
    ";
    复制代码

        运行结果如下:

    复制代码
    Stephens-Air:Desktop$ php Test.php 
    __isset is called.
    isset($testObj->privateField) is true
    __isset is called.
    isset($testObj->undefinedField) is false
    isset($testObj->publicField) is true
    After unset......
    __unset is called.
    __isset is called.
    isset($testObj->privateField) is false
    __isset is called.
    isset($testObj->publicField) is false
    复制代码

    4. __call:

        __call()方法是一个非常有用但又非常容易被滥用的拦截方法。当对象使用者试图访问当前对象未定义的成员函数时,__call()会被自动调用,同时传递两个参数,分别为函数名称和传递给调用函数的所有参数(数组)。__call方法返回的任何值都会返回给函数调用者,就如同该成员函数真实存在一样。下面给出一个非常有用的委托示例。 

    复制代码
    <?php
    class DelegateClass {
        function printMessage($arg1, $arg2) {
            print "DelegateClass:delegatedMethod is called.
    ";
            print '$arg1 = '.$arg1.'and $arg2 = '.$arg2."
    ";
        }
    }
    class TestClass {
        private $delegateObj;
        public function __construct() {
            $this->delegateObj = new DelegateClass();
        }
        public function __call($method, $args) {
            $this->delegateObj->$method($args[0],$args[1]);
        }
    }
    
    $testObj = new TestClass();
    $testObj->printMessage("hello","world");
    复制代码

        运行结果如下:

    Stephens-Air:Desktop$ php Test.php 
    DelegateClass:delegatedMethod is called.
    $arg1 = helloand $arg2 = world

        从以上示例可以看出,TestClass并未声明printMessage成员方法,但是通过__call()方法的巧妙桥接直接传递给了委托对象。个人认为该技巧为双刃剑,切勿过度使用。

    5. 回调函数: 

        回调函数的应用场景无须多述,在C/C++中充斥着无数的回调函数典型用例。 这里只是简单给出PHP中回调函数的使用规则。见如下示例代码和关键性注释: 

    复制代码
    <?php
    class Product {
        public $name;
        public $price;
        public function __construct($name, $price) {
            $this->name = $name;
            $this->price = $price;
        }
    }
    
    class ProcessSale {
        private $callbacks;
        function registerCallback($cb) {
            if (!is_callable($cb)) {
                throw new Exception("callback not callable.");
            }
            $this->callbacks[] = $cb;
        }
        function sale($product) {
            print "{$product->name}: processing 
    ";
            foreach ($this->callbacks as $cb) {
                //以下两种调用方式均可。
                call_user_func($cb, $product);
                $cb($product);
            }
        }
    }
    
    $logger = function($product) {
        print "    logging ({$product->name})
    ";
    };
    
    $processor = new ProcessSale();
    $processor->registerCallback($logger);
    $processor->sale(new Product("shoes",6));
    print "
    ";
    $processor->sale(new Product("coffee",6));
    复制代码

        运行结果如下:

    复制代码
    Stephens-Air:Desktop$ php Test.php 
    shoes: processing 
        logging (shoes)
        logging (shoes)
    
    coffee: processing 
        logging (coffee)
        logging (coffee)
    复制代码

    6. use(闭包):

        在Javascript中存在大量的闭包应用,PHP中的闭包则是通过use关键字来完成的。对于闭包这个概念本身而言,简要的说就是函数内的代码可以访问其父作用域中的变量。见如下示例代码和关键性注释:

    复制代码
    <?php
    class Product {
        public $name;
        public $price;
        public function __construct($name, $price) {
            $this->name = $name;
            $this->price = $price;
        }
    }
    
    class ProcessSale {
        private $callbacks;
        function registerCallback($cb) {
            if (!is_callable($cb)) {
                throw new Exception("callback not callable.");
            }
            $this->callbacks[] = $cb;
        }
        function sale($product) {
            print "{$product->name}: processing 
    ";
            foreach ($this->callbacks as $cb) {
                $cb($product);
            }
        }
    }
    
    class Totalizer {
        static function warnAmount($amt) {
            $count = 0;
            //注意这里的$amt和$count均为闭包变量,其中&$count是以引用的形式传递的,即一旦函数内部修改了该变量的值,
            //那么下次再访问该闭包变量时,$count将为之前调用中修改后的值。
            return function($product) use($amt, &$count) {
                $count += $product->price;
                print "     count: $count
    ";
                if ($count > $amt) {
                    print "     high price reached: {$count}
    ";
                }
            };
        }
    }
    
    $processor = new ProcessSale();
    $processor->registerCallback(Totalizer::warnAmount(8));
    $processor->sale(new Product("shoes",6));
    $processor->sale(new Product("coffee",6));
    复制代码

        运行结果如下:

    shoes: processing 
         count: 6
    coffee: processing 
         count: 12
         high price reached: 12

    注:该Blog中记录的知识点,是在我学习PHP的过程中,遇到的一些PHP和其他面向对象语言相比比较独特的地方,或者是对我本人而言确实需要簿记下来以备后查的知识点。虽然谈不上什么深度,但是还是希望能与大家分享。

  • 相关阅读:
    oracle 如何用触发器实现更新刚插入的数据
    数据库好论坛
    不同的用户导入数据库
    用函数式编程技术编写优美的 JavaScript
    使用GridView自带的ToolTip隐藏过长的数据
    含有dropdownlist的gridview增删改查
    数据分析
    数据分析
    xshell链接vbox 上 nat 方式链接虚拟机
    测试开发方法概述
  • 原文地址:https://www.cnblogs.com/chenduzizhong/p/7953936.html
Copyright © 2020-2023  润新知