[TOC]
* * * * *
## 1 魔术方法的意义
php引擎将**类的相关接口**以魔术方法的形式暴露给用户,
用户可以通过**自定义相关接口**,实现灵活的功能组织
参考官方手册分为**三类 **
>[info] 1 构造函数与析构函数
`__construct() __destruct()`
>[info] 2 重载
~~~
__set() __get() __isset() __unset()
__call() __callStatic()
~~~
>[info] 3 其他
~~~
__sleep() __wakeup() __invoke()
__toString() __set_state() __debugInfo
~~~
* * * * *
## 2 构造函数与析构函数
>[info] 1 构造函数 __construct()
在类中定义一个方法作为构造函数,
在每次创建新对象优先调用此方法,
通常完成对象的属性设置等初始化工作
为了调用父类的构造函数,
需要在子类构造函数中调用parent::__construct()
子类没有定义构造函数的会继承父类的非private类构造函数
~~~
<?php
class BaseClass {
function __construct () {
print "In BaseClass constructor\n" ;
}
}
class SubClass extends BaseClass {
function __construct () {
parent :: __construct ();
print "In SubClass constructor\n" ;
}
}
class OtherSubClass extends BaseClass {
// inherits BaseClass's constructor
}
// In BaseClass constructor
$obj = new BaseClass ();
// In BaseClass constructor
// In SubClass constructor
$obj = new SubClass ();
// In BaseClass constructor
$obj = new OtherSubClass ();
?>
~~~
php4中使用与类名相同的方法名作为构造函数,
为了向后兼容,php5中查找__consrtuct()构造函数失败时,会查找类同名构造函数,
命名空间中,与类名同名的方法不再作为构造函数
>[info] 2 析构函数__destruct()
类的对象的引用都被删除或者对象被显示销毁时,
调用析构函数,进行清理工作
~~~
<?php
class MyDestructableClass {
function __construct () {
print "In constructor\n" ;
$this -> name = "MyDestructableClass" ;
}
function __destruct () {
print "Destroying " . $this -> name . "\n" ;
}
}
$obj = new MyDestructableClass ();
?>
~~~
调用父类的析构函数,
需要在子类的析构函数中显示调用parent::__destruct()
子类如果自己没有定义析构函数则会继承父类的
析构函数在使用exit()终止脚本运行时也会被调用。
## 3 重载
传统语言的重载是提供**同名的类方法的不同参数实现**,
而**php的重载是对不可访问属性和方法的动态实现**
PHP的重载指的是动态地设置类的属性和方法,
与其他语言不通,php使用魔术方法实现重载
当调用未定义或不可见的类属性或方法时,重载方法会被调用
大部分重载方法**只能在对象中进行**,(除__callStatic)必须声明为public,
(除__callStatic)不可声明为static,**参数不能使用引用传递**
>[info] 属性重载
~~~
public void __set ( string $name , mixed $value )
public mixed __get ( string $name )
public bool __isset ( string $name )
public void __unset ( string $name )
~~~
给不可访问属性赋值时 `__set()`会被调用
读取不可访问属性的值时,`__get()`会被调用
当对不可访问属性使用isset() empty()时,`__isset()`会被调用
当对不可访问属性调用unset()时,`__unset()`会被调用
~~~
<?php
class PropertyTest {
/** 被重载的数据保存在此 */
private $data = array();
/** 重载不能被用在已经定义的属性 */
public $declared = 1 ;
/** 只有从类外部访问这个属性时,重载才会发生 */
private $hidden = 2 ;
public function __set ( $name , $value )
{
echo "Setting ' $name ' to ' $value '\n" ;
$this -> data [ $name ] = $value ;
}
public function __get ( $name )
{
echo "Getting ' $name '\n" ;
if ( array_key_exists ( $name , $this -> data )) {
return $this -> data [ $name ];
}
$trace = debug_backtrace ();
trigger_error (
'Undefined property via __get(): ' . $name .
' in ' . $trace [ 0 ][ 'file' ] .
' on line ' . $trace [ 0 ][ 'line' ],
E_USER_NOTICE );
return null ;
}
/** PHP 5.1.0之后版本 */
public function __isset ( $name )
{
echo "Is ' $name ' set?\n" ;
return isset( $this -> data [ $name ]);
}
/** PHP 5.1.0之后版本 */
public function __unset ( $name )
{
echo "Unsetting ' $name '\n" ;
unset( $this -> data [ $name ]);
}
/** 非魔术方法 */
public function getHidden ()
{
return $this -> hidden ;
}
}
echo "<pre>\n" ;
$obj = new PropertyTest ;
$obj -> a = 1 ;
echo $obj -> a . "\n\n" ;
var_dump (isset( $obj -> a ));
unset( $obj -> a );
var_dump (isset( $obj -> a ));
echo "\n" ;
echo $obj -> declared . "\n\n" ;
echo "Let's experiment with the private property named 'hidden':\n" ;
echo "Privates are visible inside the class, so __get() not used...\n" ;
echo $obj -> getHidden () . "\n" ;
echo "Privates not visible outside of class, so __get() is used...\n" ;
echo $obj -> hidden . "\n" ;
?>
~~~
输出:
Setting 'a' to '1'
Getting 'a'
1Is 'a' set?
bool(true)
Unsetting 'a'
Is 'a' set?
bool(false)1Let's experiment with the private property named 'hidden':
Privates are visible inside the class, so __get() not used...
2
Privates not visible outside of class, so __get() is used...
Getting 'hidden'Notice: Undefined property via __get(): hidden in <file> on line 70 in <file> on line 29
* * * * *
>[info] 方法重载
~~~
public mixed __call ( string $name , array $arguments )
public static mixed __callStatic ( string $name , array $arguments )
~~~
在对象中调用一个不可访问方法是 __call()会被调用
用静态方式调用一个不可访问方法__callStatic()会被调用
~~~
<?php
class MethodTest
{
public function __call ( $name , $arguments )
{
// 注意: $name 的值区分大小写
echo "Calling object method ' $name ' "
. implode ( ', ' , $arguments ). "\n" ;
}
/** PHP 5.3.0之后版本 */
public static function __callStatic ( $name , $arguments )
{
// 注意: $name 的值区分大小写
echo "Calling static method ' $name ' "
. implode ( ', ' , $arguments ). "\n" ;
}
}
$obj = new MethodTest ;
$obj -> runTest ( 'in object context' );
MethodTest :: runTest ( 'in static context' ); // PHP 5.3.0之后版本
?>
~~~
输出:
Calling object method 'runTest' in object context
Calling static method 'runTest' in static context
## 4 其他
>[info] 1 __slepp() __wakeup()
~~~
public array __sleep ( void )
void __wakeup ( void )
~~~
`__sleep() `
serialize()序列化对象时,
会优先回调__sleep()方法
然后执行序列化
通常用于返回包含对象中所有应被序列化的变量名称的数组。
如果该方法未返回内容,则NULL被序列化。
`__wakeup()`
unserialize()解序列化时,
会优先回调__wakeup()方法
然后执行解序列化
通常用来准备对象需要的资源
~~~
<?php
class Connection
{
protected $link ;
private $server , $username , $password , $db ;
public function __construct ( $server , $username , $password , $db )
{
$this -> server = $server ;
$this -> username = $username ;
$this -> password = $password ;
$this -> db = $db ;
$this -> connect ();
}
private function connect ()
{
$this -> link = mysql_connect ( $this -> server , $this -> username , $this -> password );
mysql_select_db ( $this -> db , $this -> link );
}
public function __sleep ()
{
return array( 'server' , 'username' , 'password' , 'db' );
}
public function __wakeup ()
{
$this -> connect ();
}
}
?>
~~~
>[info] 2 __invoke()
`mixed __invoke ([ $... ] )`
当以函数的方式调用一个对象时,
__invoke会被自动调用
~~~
<?php
class CallableClass
{
function __invoke ( $x ) {
var_dump ( $x );
}
}
$obj = new CallableClass ;
$obj ( 5 );
var_dump ( is_callable ( $obj ));
?>
~~~
输出:
int(5)
bool(true)
* * * * *
>[info]3 __toString
`public string __toString ( void )`
echo $obj,输出对象时的回调方法
必须返回一个字符串,否则发出致命错误
~~~
<?php
class TestClass
{
public $foo ;
public function __construct ( $foo )
{
$this -> foo = $foo ;
}
public function __toString () {
return $this -> foo ;
}
}
$class = new TestClass ( 'Hello' );
echo $class ;
?>
~~~
输出:Hello
* * * * *
>[info] 4 __set_state()
`static object __set_state()`
使用var_export()导出类时,
此类静态方法会被调用
~~~
<?php
class A
{
public $var1 ;
public $var2 ;
public static function __set_state ( $an_array ) // As of PHP 5.1.0
{
$obj = new A ;
$obj -> var1 = $an_array [ 'var1' ];
$obj -> var2 = $an_array [ 'var2' ];
return $obj ;
}
}
$a = new A ;
$a -> var1 = 5 ;
$a -> var2 = 'foo' ;
eval( '$b = ' . var_export ( $a , true ) . ';' );
// $b = A::__set_state(array(
// 'var1' => 5,
// 'var2' => 'foo',
// ));
var_dump ( $b );
?>
~~~
>[info] 5 __debuginfo()
`array __debugInfo ( void )`
使用var_dump()输出对象的信息是时回调。
未定义的的输出所有public protected属性,
private属性不会输出
~~~
<?php
class C {
private $prop ;
public function __construct ( $val ) {
$this -> prop = $val ;
}
public function __debugInfo () {
return [
'propSquared' => $this -> prop ** 2 ,
];
}
}
var_dump (new C ( 42 ));
?>
~~~
输出:
object(C)#1 (1) {
["propSquared"]=>
int(1764)
}
## 5 tp5中的魔术方法使用
- 更新记录
- 概述
- 文件索引
- 函数索引
- 章节格式
- 框架流程
- 前:章节说明
- 主:(index.php)入口
- 主:(start.php)框架引导
- 主:(App.php)应用启动
- 主:(App.php)应用调度
- C:(Controller.php)应用控制器
- M:(Model.php)数据模型
- V:(View.php)视图对象
- 附:(App.php)应用启动
- 附:(base.php)全局变量
- 附:(common.php)模式配置
- 附:(convention.php)全局配置
- 附:(Loader.php)自动加载器
- 附:(Build.php)自动生成
- 附:(Hook.php)监听回调
- 附:(Route.php)全局路由
- 附:(Response.php)数据输出
- 附:(Log.php)日志记录
- 附:(Exception.php)异常处理
- 框架工具
- 另:(helper.php)辅助函数
- 另:(Cache.php)数据缓存
- 另:(Cookie.php)cookie操作
- 另:(Console.php)控制台
- 另:(Debug.php)开发调试
- 另:(Error.php)错误处理
- 另:(Url.php)Url操作文件
- 另:(Loader.php)加载器实例化
- 另:(Input.php)数据输入
- 另:(Lang.php)语言包管理
- 另:(ORM.php)ORM基类
- 另:(Process.php)进程管理
- 另:(Session.php)session操作
- 另:(Template.php)模板解析
- 框架驱动
- D:(\config)配置解析
- D:(\controller)控制器扩展
- D:(\model)模型扩展
- D:(\db)数据库驱动
- D:(\view)模板解析
- D:(\template)模板标签库
- D:(\session)session驱动
- D:(\cache)缓存驱动
- D:(\console)控制台
- D:(\process)进程扩展
- T:(\traits)Trait目录
- D:(\exception)异常实现
- D:(\log)日志驱动
- 使用范例
- 服务器与框架的安装
- 控制器操作
- 数据模型操作
- 视图渲染控制
- MVC开发初探
- 模块开发
- 入口文件定义全局变量
- 运行模式开发
- 框架配置
- 自动生成应用
- 事件与插件注册
- 路由规则注册
- 输出控制
- 多种应用组织
- 综合应用
- tp框架整合后台auto架构快速开发
- 基础原理
- php默认全局变量
- php的魔术方法
- php命名空间
- php的自动加载
- php的composer
- php的反射
- php的trait机制
- php设计模式
- php的系统时区
- php的异常错误
- php的输出控制
- php的正则表达式
- php的闭包函数
- php的会话控制
- php的接口
- php的PDO
- php的字符串操作
- php的curl
- 框架心得
- 心:整体结构
- 心:配置详解
- 心:加载器详解
- 心:输入输出详解
- 心:url路由详解
- 心:模板详解
- 心:模型详解
- 心:日志详解
- 心:缓存详解
- 心:控制台详解
- 框架更新
- 4.20(验证类,助手函数)
- 4.27(新模型Model功能)
- 5.4(新数据库驱动)
- 7.28(自动加载)