自定义__clone()复制对象
class Person{
public $name;
public function __construct($name) {
$this->name = $name;
}
}
$first = new Person("zhangsan");
$second = $first;
如上例,PHP4时代$second和$first是两个完全不同的对象,php5之后$second和$first指向同一个对象。但对于基本数据类型显然不是引用复制。
//PHP 5.2.17 (cli) (built: May 26 2015 16:23:47)
$second->name = "lisi";
var_dump($first === $second); //true
var_dump($second->name); //lisi
var_dump($first->name); //lisi
$third = array(
"hello" => "world",
); //分配数组的空间0x0001,分配变量$third内存,并指向0x0001
$fourth = $third; //分配变量$fourth内存,并指向同一地址0x0001,引用计数加1
var_dump($fourth === $third); //true,内容相同,内容地址也相同
$fourth['hello'] = "fuck"; //变量改变,重新copy一份出来,给$fourth指向,并修改引用计数
var_dump($fourth === $third); //false,已经是不同的内容,不同的地址
这就很尴尬了,虽然引用复制较为节省空间,但有时我们希望对象的复制是值copy,各自保留各自的副本。php提供的clone关键字能够解决该问题。
$first = new Person("zhangsan");
$second = clone $first; //各自有一份TestPHP的副本
var_dump($first === $second); //false,地址不同
$second->name = "lisi"; //修改的是自己的TestPHP对象内容
var_dump($second->name); //lisi
var_dump($first->name); //zhangsan
尴尬的事又出现了,一个clone把事都办了,那还有啥高级特性?我们如果要自定义对象的copy呢?比如我希望在复制Person的时候,除id以外的信息,而id要初始化成0。那就需要自定义对象的clone了。
class Person{
public $id;
public $name;
function __construct($id,$name) {
$this->id = $id;
$this->name = $name;
}
public function __clone() {
$this->id = 0;
}
}
$first = new Person("1", "zhangsan");
$second = clone $first;
var_dump($second->id . " | " . $second->name); //0 | zhangsan
var_dump( $first->id . " | " . $first->name ); //1 | zhangsan
这时Account加入了战斗,问题又出现了。
class Account {
public $balance;
function __construct($balance) {
$this->balance = $balance;
}
}
class Person {
public $id;
public $name;
public $account;
function __construct($id, $name, Account $account) {
$this->id = $id;
$this->name = $name;
$this->account = $account;
}
public function __clone() {
$this->id = 0;
}
}
$first = new Person("1", "zhangsan", new Account(100));
$second = clone $first;
$first->account->balance += 10000;
var_dump($first->account->balance); // 10100
var_dump($second->account->balance); //10100
$first、$second初始化账户上应该又100元,现在给$first充了10000,结果$second的账户上也被加了10000,,因为在clone Person对象时,account变量的复制仍然是引用复制,导致问题,需修改__clone方法
function __clone() {
$this->id = 0;
$this->account = clone $this->account;
}
__autoload()与spl_autoload_register()实现自动加载
PHP5引入了__autoload()拦截器方法实现类文件的自动加载,需要自定义加载函数,其实就是说清楚在php执行过程中,遇到未定义的类,到哪儿取找该类的实现文件。
$testLoad = new TestLoad(); //Fatal error: Class 'TestLoad' not found in XXXXX
$testLoad->say();
但是如果自定义实现了__autoload()方法,方法需要传递className作为参数名,然后找到TestLoad类的实现,加载类,实例化,调用say()方法就ok。
function __autoload($className) {
require_once "$className.php"; //自己定义,想加载什么文件、想到哪儿加载文件都是自己定义
}
$testLoad = new TestLoad();
$testLoad->say(); //hello,world
TestLoad类的实现
class TestLoad {
public function say() {
echo "hello,world" . PHP_EOL;
}
}
spl_autoload_register()方法又是干啥的呢? 这么理解,__autoload()方法是正规军,系统是认识它的,你只要敢定义它,就能实现类的自动加载。但是如果地方军呢?比如我想起个名字叫XX()的加载函数,就需要使用spl_autoload_register()去登记注册告诉系统这是自己人,以后遇到未定义类的时候,找XX就行了。
function myLoad($className) {
require_once "$className.php";
}
spl_autoload_register("myLoad");
$testLoad = new TestLoad();
$testLoad->say();
网友评论