面向对象的学习之-----魔术六个方法

本文介绍了PHP面向对象编程的基础概念,包括构造方法、析构方法、__call()、__get()和__set()等方法的使用及注意事项。

一、

php中构造方法是对象创建完成后第一个被对象自动调用的方法。在每个类中都有一个构造方法,如果没有显示地声明它,那么类中都会默认存在一个没有参数且内容为空的构造方法。

 

构造方法的作用

通常构造方法被用来执行一些有用的初始化任务,如对成员属性在创建对象时赋予初始值。

 

构造方法的在类中的声明格式

function __constrct([参数列表]){

方法体//通常用来对成员属性进行初始化赋值

}

 

在类中声明构造方法需要注意的事项

1、在同一个类中只能声明一个构造方法,原因是,PHP不支持构造函数重载。

2、构造方法名称是以两个下画线开始的__construct()

 

现在就来看一个例子:

01<?php
02    class Person{
03                                                                                        
04            public $name;        
05            public $age;        
06            public $sex;        
07                                                                                                 
08        public function __construct($name="",$sex="男",$age=27){      //显示声明一个构造方法且带参数
09            $this->name=$name;
10            $this->sex=$sex;
11                        $this->age=$age;
12        }
13        public function say(){ 
14            echo "我叫:".$this->name.",性别:".$this->sex.",年龄:".$this->age;
15        }   
16                                                                                            
17    }
18?>

创建对象$Person1且不带任参数

1$Person1new Person();
2echo $Person1->say();//输出:我叫:,性别:男,年龄:27

创建对象$Person2且带参数"张三"

1$Person2new Person("张三");
2echo $Person2->say();//输出:我叫:张三,性别:男,年龄:27

创建对象$Person3且带三个参数

1$Person3new Person("李四","男",25);
2echo $Person3->say();//输出:我叫:李四,性别:男,年龄:25

 

2.子类可以重写父类的构造方法(子类也有自己的__construct)/子类可以调用父类的构造方法

   如果非要在子类中调用父类的构造方法  即用 paret::__construct()

 

<?php
class BaseClass {
   function __construct() {
       print "In BaseClass constructor\n";
   }
}

class SubClass extends BaseClass {
   function __construct() {
       parent::__construct();
       print "In SubClass constructor\n";
   }
}

$obj = new BaseClass();
$obj = new SubClass();
?>

 

PHP面向对象析构方法 __destruct()

我们知道,在实例化对象时,构造方法 __construct() 方法会被自动调用。

  PHP5还提供了一个对应的方法 __destruct(),它只在对象被垃圾收集器收集前(即对象从内存中删除之前)自动调用。我们可以利用这个方法进行最后必要的处理,或是保存、或是彻底清除等。
  例如,有一个类需要把其自身的信息写入数据库,这时就可以使用 __destruct() 方法在对象实例将被删除时确保把自己保存到数据库中:
PHP Code复制内容到剪贴板
  1. <?php  
  2.     header('Content-type:text/html;charset=utf-8');  
  3.     /**  PHP 5.1.0之后版本 */  
  4.     class Person{  
  5.         // 定义不可见属性(只有当前类可用)  
  6.         private $name;  
  7.         private $age;  
  8.         private $id;  
  9.         // 定义 __construct() 类的构造方法  
  10.         function __construct($name , $age){  
  11.             // 给属性赋值  
  12.             $this -> name = $name;  
  13.             $this -> age = $age;  
  14.         }  
  15.           
  16.         function setId($id){  
  17.             $this -> id = $id;  
  18.         }  
  19.           
  20.         // 注意:这个方法的处理方法多种多样,根据需求定义具体问题具体分析  
  21.         function __destruct(){  
  22.             // 判断 id 是否为空,确保要删的数据存在  
  23.             if(!emptyempty($this -> id)){  
  24.                 // 保存数据...  
  25.                 print "郭碗瓢盆提示您:数据保存成功!";  
  26.             }  
  27.         }  
  28.     }  
  29.     // 下面创建一个 Person 对象,然后再销毁它,可以看到 __destruct() 方法所其的作用。  
  30.     $p = new Person("郭碗瓢盆 - www.lifefrom.com",22);  
  31.     $p -> setId(2);  
  32.     unset($p);  
  33. ?>  
 
  
  这样无论对象何时从内存中删除,__destruct() 方法都会被调用。当对一个对象调用 unset() 函数时,或者进程中不再引用某个对象时,对象就被销毁了。这些情况下,只要定义了析构方法 __destruct() ,就不怕数据丢失了。
  
  这样的编程技巧很有趣,但在使用的时候要谨慎。__call() 和 __destruct() 这一系列方法有时被称为魔法方法,因为它们可能武断而出乎意料之外,它可能改变原则,并且导致隐形的代价。
   假设 Person 类在 __desctruct() 方法中执行了一次数据库写入操作,现在有一个开发新手漫不经心的使用 Person 类,他根本没有注意到析构方法,而是实例化了一组 Person 对象,并通过传值给类的构造方法,将私下给 CEO 起的外号传递给了 $name 属性,并且把 $age 设置为150。他执行了几次,并尝试各种有趣的姓名与年龄的组合。

  第二天,经理把他叫到办公室,问他数据库哪里来的这些无理数据.

 

三、

PHP 的__call()

PHP5 的对象新增了一个专用方法 __call(),这个方法用来监视一个对象中的其它方法。如果你试着调用一个对象中不存在或被权限控制中的方法,__call 方法将会被自动调用

例七:__call

[html] view plain copy
  1. <?php  
  2. class foo {  
  3.   function __call($name,$arguments) {  
  4.     print("Did you call me? I'm $name!");  
  5.   }  
  6. } $x = new foo();  
  7. $x->doStuff();  
  8. $x->fancy_stuff();  
  9. ?>  




这个特殊的方法可以被用来实现类似JAVA中的“过载(overloading)”的作用(php中不可以重载),这样你就可以检查你的参数并且通过调用一个私有的方法来传递参数。

例八:使用 __call 实现“过载”动作

[html] view plain copy
  1. <?php  
  2. class Magic {  
  3.   function __call($name,$arguments) {  
  4.     if($name=='foo') {  
  5.   if(is_int($arguments[0])) $this->foo_for_int($arguments[0]);  
  6.   if(is_string($arguments[0])) $this->foo_for_string($arguments[0]);  
  7.     }  
  8.   }   private function foo_for_int($x) {  
  9.     print("oh an int!");  
  10.   }   private function foo_for_string($x) {  
  11.     print("oh a string!");  
  12.   }  
  13. } $x = new Magic();  
  14. $x->foo(3);  
  15. $x->foo("3");  
  16. ?>  




引自:

_call和___callStatic这两个函数是php类 的默认函数,

__call() 在一个对象的上下文中,如果调用的方法不能访问,它将被触发

__callStatic() 在一个静态的上下文中,如果调用的方法不能访问,它将被触发

 

php面向对象_get(),_set()的用法
一般来说,总是把类的属性定义为private,这更符合 现实的逻辑。但是,对属性的读取和赋值操作是非常频繁的,因此在PHP5中,预定义了两个函数“__get()”和“__set()”来获取和赋值其属 性。类似于java中的javabean的操作,使用的方法也类似,只是不需要像javabean中那样,对每个字段进行set和get的操作。只需要加 上两个魔术方法即可。即私有成员的设值和取值的操作。在PHP5中给我们提供了专门为属性设置值和获取值的方法,“__set()”和“__get()” 这两个方法,这两个方法不是默认存在的,而是我们手工添加到类里面去的,像构造方法(__construct())一样,类里面添加了才会存在,可以按下 面的方式来添加这两个方法,当然也可以按个人的风格来添加:

复制代码 代码如下:

//__set()方法用来设置私有属性
public function __set($name,$value){
$this->$name = $value;
}
//__get()方法用来获取私有属性
public function __get($name){
return $this->$name;
}


__get() 方法:这个方法用来获取私有成员属性值的,有一个参数,参数传入你要获取的成员属性的名称,返回获取的属性值,这个方法不用我们手工的去调用,因为我们也 可以把这个方法做成私有的方法,是在直接获取私有属性的时候对象自动调用的。因为私有属性已经被封装上了,是不能直接获取值的,但是如果你在类里面加上了 这个方法,在使用“echo$p1->name”这样的语句直接获取值的时候就会自动调用__get($name)方法,将属性name传给参 数$name,通过这个方法的内部执行,返回我们传入的私有属性的值。如果成员属性不封装成私有的,对象本身就不会去自动调用这个方法。

__set() 方法:这个方法用来为私有成员属性设置值的,有两个参数,第一个参数为你要为设置值的属性名,第二个参数是要给属性设置的值,没有返回值。这个方法同样不 用我们手工去调用,它也可以做成私有的,是在直接设置私有属性值的时候自动调用的,同样属性私有的已经被封装上
了,如果没有__set()这个 方法,是不允许的,比如:$this->name=‘zhangsan',这样会出错,但是如果你在类里面加上了 __set($property_name, $value)这个方法,在直接给私有属性赋值的时候,就会自动调用它,把属性比如name传给$property_name,把要赋的值 “zhangsan”传给$value,通过这个方法的执行,达到赋值的目的。如果成员属性不封装成私有的,对象本身就不会去自动调用这个方法。为了不传 入非法的值,还可以在这个方法给做一下判断。代码如下:

复制代码 代码如下:

<?php
class Person
{
//下面是人的成员属性,都是封装的私有成员
private $name; //人的名子
private $sex; //人的性别
private $age; //人的年龄
//__get()方法用来获取私有属性
private function __get($property_name)
{
echo "在直接获取私有属性值的时候,自动调用了这个__get()方法<br>";
if(isset($this->$property_name))
{
return($this->$property_name);
}
else
{
return(NULL);
}
}
//__set()方法用来设置私有属性
private function __set($property_name, $value)
{
echo "在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值<br>";
$this->$property_name = $value;
}
}
$p1=newPerson();
//直接为私有属性赋值的操作,会自动调用__set()方法进行赋值
$p1->name="张三";
$p1->sex="男";
$p1->age=20;
//直接获取私有属性的值,会自动调用__get()方法,返回成员属性的值
echo "姓名:".$p1->name."<br>";
echo "性别:".$p1->sex."<br>";
echo "年龄:".$p1->age."<br>";
?>


程序执行结果:
在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值
在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值
在直接设置私有属性值的时候,自动调用了这个__set()方法为私有属性赋值
在直接获取私有属性值的时候,自动调用了这个__get()方法
姓名:张三
在直接获取私有属性值的时候,自动调用了这个__get()方法
性别:男
在直接获取私有属性值的时候,自动调用了这个__get()方法
年龄:20
以上代码如果不加上__get()和__set()方法,程序就会出错,因为不能在类的外部操作私有成员,而上面的代码是通过自动调用__get()和__set()方法来帮助我们直接存取封装的私有成员的。

 

五、__set()\__get()\__isset()\__unset();

在给不可访问属性赋值时,__set() 会被调用。

读取不可访问属性的值时,__get() 会被调用。

当对不可访问属性调用 isset()empty() 时,__isset() 会被调用。

当对不可访问属性调用 unset() 时,__unset() 会被调用。

参数 $name 是指要操作的变量名称。__set() 方法的 $value 参数指定了 $name 变量的值。

属性重载只能在对象中进行。在静态方法中,这些魔术方法将不会被调用。所以这些方法都不能被 声明为 static。从 PHP 5.3.0 起, 将这些魔术方法定义为 static 会产生一个警告。

Note:

因为 PHP 处理赋值运算的方式,__set() 的返回值将被忽略。类似的, 在下面这样的链式赋值中,__get() 不会被调用:

 $a = $obj->b = 8; 

Note:

在除 isset() 外的其它语言结构中无法使用重载的属性,这意味着当对一个重载的属性使用 empty() 时,重载魔术方法将不会被调用。

为避开此限制,必须将重载属性赋值到本地变量再使用 empty()

Example #1 使用 __get()__set()__isset()__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->1;
echo $obj->"\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'
1

Is 'a' set?
bool(true)
Unsetting 'a'
Is 'a' set?
bool(false)

1

Let'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

 

转载于:https://www.cnblogs.com/aipiaoborensheng/p/4904677.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值