PHP类的秘密(八) 对象的秘密

这是我参与更文挑战的第12天,活动详情查看: 更文挑战

对象的秘密

本文讲解了PHP类中, 关于各种对象的创建方法, 对象比较, 对象赋值的内在逻辑, 对象复制, 对象类型, 对象间的互相调用, instanceof类运算符, 其中还会介绍一些在使用中的小技巧. 使用好对象, 能让我们的程序更简洁.

创建对象的N种方式

new

$obj= new MyClass{}; //新建普通类MyClass{}的对象;

$obj1= new stdClass(); //新建内置类对象;

$ob2=new class{}; //新建匿名类对象;

以上三种new的创建方式, 可以用在类外, 也可以直接用在类内成员方法中, 这样的例子我们看过不少, 我这里举一个匿名类+链式调用的例子:

class Outer
{
    private $attr = 1;
    protected $attr2 = 2;

    protected function func1()
    {
        return 3;
    }

    public function func2()
    {   //新建匿名子类, 并将父类属性传给子类构造函数
        return new class($this->attr) extends Outer {   
            private $attr3;

            public function __construct($attr)
            {
                $this->attr3 = $attr;
            }

            public function func3()
            {
                return $this->attr2 + $this->attr3 + $this->func1();
            }
        };
    }
}

echo (new Outer)->func2()->func3();  //6
复制代码

简单讲解一下这个例子的关键点:

  1. 链式调用是由左至右执行; 创建父类对象, 并调用func2();

  2. func2()方法建立新的匿名子类对象, 并初始化了$attr3. 这时$this指代的不再是父类对象, 而是子类对象, 这一点很重要.

  3. 通过子类对象调用, 可以正常调用父类func3(), 完成链式调用, 并执行方法体.

new与代词搭配, 达到实例化指定类的目的, 看下面这个例子:

class ParentClass
{
    function creatObjParent()
    {
        echo ' new self:';
        return new self;         //返回本类ParentClass的对象
    }
}

class Son extends ParentClass
{
    function creatObjSon()
    {
        echo ' new parent:';
        return new parent;      //返回父类ParentClass的对象
    }
}
class Grandson extends Son
{
    function creatObjGrandson()
    {
        echo ' new static:';
        return new static;      //返回调用者所在类的对象
    }
}
$aaa= new Grandson();
echo get_class($aaa->creatObjGrandson());  //new static:Grandson
echo get_class($aaa->creatObjSon());       //new parent:ParentClass
echo get_class($aaa->creatObjParent());    //new self:ParentClass
复制代码

static静态方法创建对象

静态方法可以被类名和对象进行调用, 创建新的对象:

class Store {
    static function creatobj()
    {
        return new static;
    }
}

$b=Store::creatobj();  
var_dump($b);  //object(Store)#8 (0) { }
复制代码

new的一些其他用法

与对象搭配, 创建新的对象;

class NewClass{};
$a= new NewClass();
$b= new $a;        //与对象搭配, 创建新的对象;
var_dump($a==$b);  //true, 同一类的实例相等
var_dump($a===$b); //false, 指代不同实例, 不全等
复制代码

通过字符串指代类名:

class NewClass{};
$a= 'NewClass';
$b= new $a;
var_dump($b);
复制代码

这里补充一下对象间的比较原则:

当使用比较运算符(==)比较两个对象变量时,比较的原则是:如果两个对象的属性和属性值 都相等,而且两个对象是同一个类的实例,那么这两个对象变量相等。

而如果使用全等运算符(===),这两个对象变量一定要指向某个类的同一个实例(即同一个对象)。

4. 对象类型转换(object)

我们还可以将其他类型的数据, 比如字符串, 数字或数组转换成对象. 只需要在被转换对象前面加(object)即可.

字符串转化为对象:

$a= 'NewClass';
$ob=(object)$a;
var_dump($ob);   //object(stdClass)#6 (1) {["scalar"]=>string(8) "NewClass"}
复制代码

可以看到它创建了一个内置类stdClass, 并将字符串作为’scalar’的属性值; 这种处理方式同样应用于数字型, 大家可以在本地测试一下.

数组转化为对象:

$a= [1,2,3,[1,2,3],'one'=>123,'two'=>321];
$ob=(object)$a;
print_r($ob);
//output:
stdClass Object
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => Array
    (
        [0] => 1
        [1] => 2
        [2] => 3
    )
    [one] => 123
    [two] => 321
)
复制代码

可以看到, 同样创建了一个内置类stdClass, 并将key作为了属性名, value作为了属性值, 如果是多维数组, 则第二维数组会作为一个属性的值. 你还可以通过指定key值来指定属性名. 可见将数组转化为对象, 是一个很快捷的创建对象的方式;

但是在转化数组型的时候注意一点: 属性名的命名规则, 由字母或者下划线开头,后面跟上任意数量的字母,数字,或者下划线。如果是不符合规则的属性名, 会导致无法访问属性.

2. 对象的赋值和引用

我们可以通过一个对象给另一个变量赋值, 或建立两个对象间的引用关系, 来创建另一个对象:

class Myclass{};
$a=new MyClass;
$b=$a;
$c=&$a;
$d=new MyClass;

echo (int)($b===$a);  //1, $b, $a两者全等, 指向相同对象
echo (int)($c===$a);  //1, $c,$a两者全等, 指向相同对象
print_r($c===$b);     //1, $c, $b全等;
var_dump($d==$a);     //true, 两者都是同一个类的对象
var_dump($d===$a);    //False, 两者指向不同对象

$a->{'test'}=5;       //创建新属性并赋值
print_r($b);          //Myclass Object ( [test] => 5 )
Print_r($c);          //Myclass Object ( [test] => 5 )

$a=5;
var_dump($c);             //int(5)
var_dump($b);             //object(Myclass)#11 (1) { ["test"]=> int(5) }
复制代码

从上例可以看出关于引用和赋值的几点原理:

  1. 无论是直接赋值, 还是引用, 等号两边指向的都是同一个实例. 当其中一个对象属性发生变化时, 另外两个对象同步变化

  2. 同属于一个类的两个对象相等, 但不全等, 只有指向同一对象的两个变量才是全等的.

  3. 当存在引用关系的其中一个变量a发生变化时,另一个变量a发生变化时, 另一个变量c也同步变化, 但不会影响到普通赋值的变量$b.

关于PHP中对象的存储方式, 类似于指针:

一个对象变量不是保存整个对象的值, 而是保存一个标识符来访问真正的对象内容。 当对象作为参数传递/作为结果返回/或者赋值给另外一个变量,另外一个变量跟原来的不是引用的关系,只是他们都保存着同一个标识符的拷贝,这个标识符指向同一个对象的真正内容。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享