1、读取php对象的不可访问属性(private/protected)
class Person{
private $name;
private $age ;
public function __construct($name,$age)
{
$this->name = $name;
$this->age = $age;
}
}
$person = new Person('gofor',28);
echo $person->name;//直接报错
echo $person->age;//直接报错
上面代码运行将发生致命错误,Cannot access private property Person::$name
那如何访问类的私有或保护属性呢?
方法1:为每个private/protected属性定义公有方法
class Person{
private $name;
private $age ;
public function __construct($name,$age)
{
$this->name = $name;
$this->age = $age;
}
public function getName(){
return $this->name;
}
public function getAge(){
return $this->age;
}
}
$person = new Person('gofor',28);
echo $person->getName();
echo $person->getAge();
这时候代码正常运行
这种方法需要为每个private/protected属性定义对应getXXX方法,代码量比较大,且新增private/protected属性需要新增对应的方法
读取不可访问(private/protected)的属性值时自动调用__get方法
代码实现
class Person{
private $name;
private $age ;
public function __construct($name,$age)
{
$this->name = $name;
$this->age = $age;
}
//$name为类的属性名
public function __get($name)
{
//存在类属性
if(isset($this->$name)) {
return $this->$name;
}
return '属性'.$name.'不存在';
}
}
$person = new Person('gofor',28);
echo $person->name;//输出gofor
echo $person->age;//输出28
这样调用类私有(或保护)属性,通过__get一个魔术方法就搞定,比方法1更简单方便。
2、给访问受限属性(private/protected)赋值
同样,$person->name = 'Tom';给访问受限属性这样赋值会报错。
那如何给访问受限属性赋值呢?
同理,方法1:为每个访问受限属性添加对应的setXXX()共有方法
方法2:使用__set魔术方法
__set( $property, $value ) 给一个访问受限(private/protected)属性赋值时调用
代码实现如下:
class Person{
protected $name;
private $age ;
public function __construct($name,$age)
{
$this->name = $name;
$this->age = $age;
}
//$name为类的属性名
public function __get($name)
{
//存在类属性
if(isset($this->$name)) {
return $this->$name;
}
return '属性'.$name.'不存在';
}
//$name为类的属性名,$value为设置的值
public function __set($name, $value)
{
$this->$name = $value;
}
}
$person = new Person('gofor',28);
$person->name = 'Tom';
$person->age = 29;
echo $person->name;//输出Tom
echo $person->age;//输出29
3、魔术方法__construct
__construct 构造方法,当一个对象被创建时调用此方法,可以给类初始化数据,如属性赋值
代码如下:
class Person
{
protected $name;
private $age;
//当一个对象被创建时调用此方法
//即$person = new Person('gofor',28)调用____construct
public function __construct($name, $age)
{
//类初始化数据
$this->name = $name;
$this->age = $age;
}
}
4、魔术方法__call
如何防止调用类不存在的方法而报错呢?
使用__call魔术方法
__call( $method, $arg_array ) 当调用一个未定义(包括没有权限访问)的方法是调用此方法。其中$method是调用的方法名, $arg_array是参数数组,传给方法的参数。
代码如下
class Person{
protected $name;
private $age ;
public function __construct($name,$age)
{
$this->name = $name;
$this->age = $age;
}
}
$person = new Person('gofor',28);
$person->say(‘hello’);//Person类未定义say方法,这时程序会报错
如何防止调用类不存在的方法而报错呢?使用__call魔术方法可以实现。代码如下:
class Person{
protected $name;
private $age ;
public function __construct($name,$age)
{
$this->name = $name;
$this->age = $age;
}
public function __call($name, $arguments)
{
echo '方法:'.$name.'不存在';
dump($arguments);
}
}
$person = new Person('gofor',28);
$person->say(‘hello’);//Person类未定义say方法,这时会调用__call正常访问
上述代码运行结果为:
方法:say不存在
array (size=1)
0 => string 'hello' (length=5)
魔术方法__call其中一个比较熟悉的应用场景就是web开发的MVC模式中,假设控制器调用了一个不存在的方法,那么只要定义了__call魔术方法就可以友好处理这种情况。
5、魔术方法__callStatic
当调用类一个不存在的静态方法(就是带有static关键字的方法)会调用__callStatic的魔术方法
它的工作方式类似于 __call() 魔术方法,不做详细描述。
6、魔术方法__toString
__toString方法在将一个对象转化成字符串时自动调用,比如使用echo打印对象时,如果类没有实现此方法,则无法通过echo打印对象
$person = new Person('gofor',28);
echo $person;
在没有给Person定义__toString时,会报错# Object of class Person could not be converted to string
实现__toString方法之后,就可以按照我们设定的格式打印$person信息了
代码如下:
class Person{
protected $name;
private $age ;
public function __construct($name,$age)
{
$this->name = $name;
$this->age = $age;
}
public function __toString()
{
return 'name:'.$this->name.',age:'.$this->age;
}
}
$person = new Person('gofor',28);
echo $person;
运行结果如下:
name:gofor,age:28
7、魔术方法__clone
克隆对象时被调用,如下代码:
$person = new Person('gofor',28);//创建对象
$person2=clone $person;//这里克隆对象,会调用__clone魔术方法
完整代码如下:
class Person{
protected $name;
private $age ;
public function __construct($name,$age)
{
$this->name = $name;
$this->age = $age;
}
public function __toString()
{
return 'name:'.$this->name.',age:'.$this->age;
}
public function __call($name, $arguments)
{
echo '方法:'.$name.'不存在';
dump($arguments);
}
//$name为类的属性名
public function __get($name)
{
//存在类属性
if(isset($this->$name)) {
return $this->$name;
}
return '属性'.$name.'不存在';
}
//$name为类的属性名,$value为设置的值
public function __set($name, $value)
{
$this->$name = $value;
}
public function __clone()
{
echo '我被复制了';
}
}
$person = new Person('gofor',28);
$person2 = clone $person;//此处会调用__clone方法
运行上述代码结果如下:
我被复制了