Heim >Backend-Entwicklung >PHP-Tutorial >Das Konzept von PHP-Klassen und -Objekten

Das Konzept von PHP-Klassen und -Objekten

怪我咯
怪我咯Original
2018-05-15 10:11:2319887Durchsuche

1. Klassen und Objekte

Objekt: Ein Individuum, das tatsächlich in jedem physischen Objekt dieses Typs existiert. $a =new User(); Die instanziierte $a
-Referenz: PHP-Alias, zwei verschiedene Variablennamen verweisen auf denselben Inhalt

Kapselung: Organisieren Sie die Eigenschaften und Methoden des Objekts in einem
Vererbung in einer Klasse (logische Einheit): Erstellen Sie eine neue Klasse basierend auf der ursprünglichen Klasse zum Zweck der Wiederverwendung von Code.
Polymorphismus: Ermöglichen Sie die Zuweisung des Zeigers des Unterklassentyps zum Typzeiger der übergeordneten Klasse.
----------------------------------------

2 . Automatisches Laden des Objekts:

Autoloading Durch die Definition einer speziellen Autoload-Funktion wird diese Funktion automatisch aufgerufen, wenn auf eine Klasse verwiesen wird, die nicht im Skript definiert ist.

function autoload($class){
  require_once("classes/$class.class.php");
}

Warum sollten wir Autoload für diese Datei verwenden?

3. Insbesondere wenn es viele Projektdateien gibt, ist es unmöglich, am Anfang jeder Datei eine lange Liste von Anforderungen zu schreiben...


ersetzt ein
require_once ("classes/ Books.class .php") ;

require_once ("classes/Employees.class.php" ) ;

require_once ("classes/Events.class.php") ;
require_once ("classes/Patrons. class.php ") ;

zend empfiehlt eine der beliebtesten Methoden, einschließlich des Pfads im Dateinamen. Zum Beispiel im folgenden Beispiel:

$temp = new Main_Super_Class();

view sourceprint?
// Main.class  

function autoload($class_name) {   
     $path = str_replace('_', DIRECTORY_SEPARATOR, $class_name);   
     require_once $path.'.php';   
 }
Alle Unterstriche werden im Pfad durch Trennzeichen ersetzt, Main/Super wird die Datei /Class.php sein.

Nachteile:

Im Codierungsprozess müssen Sie genau wissen, wo sich die Codedatei befinden soll.

Und da der Dateipfad im Klassennamen fest codiert ist, Wenn wir die Ordnerstruktur ändern müssen, müssen wir alle Klassennamen manuell ändern.

Wenn Sie sich in einer Entwicklungsumgebung befinden und nicht viel Wert auf Geschwindigkeit legen, ist es sehr praktisch, die Methode „Alle einschließen“ zu verwenden.

Indem Sie alle Klassendateien in einem oder mehreren bestimmten Ordnern ablegen und sie dann durch Durchlaufen finden und laden.

Zum Beispiel




Eine andere Methode besteht darin, eine zugehörige Konfigurationsdatei zwischen der Klassendatei und ihrem Speicherort einzurichten, zum Beispiel:

<?php   

$arr = array (   
     &#39;Project/Classes&#39;,   
    &#39;Project/Classes/Children&#39;,   
    &#39;Project/Interfaces&#39;  
 );  

 foreach($arr as $dir) {   

    $dir_list = opendir($dir);  

    while ($file = readdir($dir_list)) {   
         $path = $dir.DIRECTORY_SEPARATOR.$file;   
         if(in_array($file, array(&#39;.&#39;, &#39;..&#39;)) || is_dir($path))   
             continue;  
         if (strpos($file, ".class.php"))   
             require_once $path;   
     }   
}   

 ?>

Datei genannt

view sourceprint?
// configuration.php   

array_of_associations = array(   
    &#39;MainSuperClass&#39; = &#39;C:/Main/Super/Class.php&#39;,   
    &#39;MainPoorClass&#39; = &#39;C:/blablabla/gy.php&#39;  
 );

----------------------------- -- ------

<?php   
    require &#39;autoload_generated.php&#39;;  
    function autoload($className) {   
       global $autoload_list;   
       require_once $autoload_list[$className];   
    }  
      $x = new A();   
?>
3. Konstruktoren und Destruktoren

Der PHP-Konstruktor „construct()“ ermöglicht die Ausführung des Konstruktors vor der Instanziierung einer Klasse.

Der Konstruktor ist eine spezielle Methode in einer Klasse. Wenn eine Instanz einer Klasse mit dem neuen Operator erstellt wird, wird die Konstruktormethode automatisch aufgerufen und ihr Name muss construction() sein.

(In einer Klasse kann nur ein Konstruktor deklariert werden, aber der Konstruktor wird bei jeder Objekterstellung nur einmal aufgerufen. Diese Methode kann nicht aktiv aufgerufen werden,

daher wird sie normalerweise zur Ausführung verwendet Einige Nützliche Initialisierungsaufgaben. Diese Methode hat keinen Rückgabewert. Funktion: Wird zum Initialisieren des Objekts verwendet. Definition: Eine spezielle interne Mitgliedsfunktion ohne Rückgabetyp, ohne Parameter, die nicht nach Belieben aufgerufen werden kann und nicht überlastet ist. Sie wird vom System nur automatisch freigegeben, wenn die Lebensdauer des Klassenobjekts endet Konstrukteur.

Der Konstruktormethode entspricht die Destruktormethode. Mit der Destruktormethode können Sie einige Vorgänge ausführen oder einige Funktionen ausführen, bevor Sie eine Klasse zerstören, z. B. das Schließen von Dateien, das Freigeben von Ergebnismengen usw.
Der Destruktor kann keine Parameter annehmen und sein Name muss destruct() sein.

Funktion: Bereinigen Sie die Nacharbeit, verwenden Sie beispielsweise new, um beim Erstellen eines Objekts einen Speicherplatz zu öffnen, und verwenden Sie den Destruktor, um die im Konstruktor zugewiesenen Ressourcen vor dem Beenden freizugeben.


Beispiel:


----------------------------- - ---------------------------------


4. Zugangskontrolle

Ja Die Zugriffskontrolle von Attributen oder Methoden wird durch das Hinzufügen der Schlüsselwörter public, protected oder private vor ihnen erreicht.

Auf die durch public definierten Klassenmitglieder kann von überall aus zugegriffen werden. Auf die durch
protected definierten Klassenmitglieder kann von überall aus zugegriffen werden Unterklassen und übergeordnete Klassen der Klasse, in der es sich befindet, können darauf zugreifen (natürlich kann auch auf die Klasse zugegriffen werden, in der sich das Mitglied befindet).

Auf privat definierte Klassenmitglieder kann nur die Klasse zugreifen, in der sie sich befinden gelegen.
class Person {
    public $name;
    public $age;

    //定义一个构造方法初始化赋值
    public function construct($name,$age) {
        $this->name=$name;
        $this->age=$age;
    }
    public function say() {
        echo "my name is :".$this->name."<br />";
        echo "my age is :".$this->age;
    }
    //析构函数
    function destruct()
    {
        echo "goodbye :".$this->name;
    }
}

$p1=new Person("ren", 25);
$p1->say();
Zugriffskontrolle für Klassenmitglieder

Klassenmitglieder müssen mit den Schlüsselwörtern public, protected oder private definiert werden

Zugriffskontrolle für Methoden

Methoden in der Klasse müssen das Schlüsselwort public, protected oder private verwenden zu definieren. Wenn diese Schlüsselwörter nicht festgelegt sind, wird die Methode auf die Standard-Öffentlichkeit festgelegt.


Beispiel:



------------------------------ -----------------------------------

5. Objektvererbung

Vererbungsdefinition: Erstellen Sie eine neue Klasse basierend auf der ursprünglichen Klasse zum Zweck der Code-Wiederverwendung; -----------

Überschreiben wird beim Erben von Objekten verwendet
Überladen ist eine Methode mit demselben Methodennamen, aber unterschiedlichen Parametern in einem einzelnen Objekt

-------- ----------------------------------
class MyClass
{
    public $public = &#39;Public&#39;;
    protected $protected = &#39;Protected&#39;;
    private $private = &#39;Private&#39;;

    function printHello()
    {
        echo $this->public;
        echo $this->protected;
        echo $this->private;
    }
}

$obj = new MyClass();
echo $obj->public; // 这行能被正常执行
echo $obj->protected; // 这行会产生一个致命错误
echo $obj->private; // 这行也会产生一个致命错误
$obj->printHello(); // 输出 Public、Protected 和 Private

继承已为大家所熟知的一个程序设计特性,PHP 的对象模型也使用了继承。继承将会影响到类与类,对象与对象之间的关系。

比如,当扩展一个类,子类就会继承父类的所有公有和保护方法。但是子类的方法会覆盖父类的方法。

继承对于功能的设计和抽象是非常有用的,而且对于类似的对象增加新功能就无须重新再写这些公用的功能。

class Person {
    public $name;
    public $age;

    function say() {
        echo "my name is:".$this->name."<br />";
    echo "my age is:".$this->age;
    }
}

// 类的继承
class Student extends Person {
    var $school;    //学生所在学校的属性
    
    function study() {
        echo "my name is:".$this->name."<br />";
        echo "my shool is:".$this->school;
    }       
}

$t1 = new Student();
$t1->name = "zhangsan";
$t1->school = "beijindaxue";
$t1->study();

-------  ---------  ------   ---------  --------   -----

6 .范围解析操作符(::)

范围解析操作符(也可称作 Paamayim Nekudotayim)或者更简单地说是一对冒号,可以用于访问静态成员、方法和常量,还可以用于覆盖类中的成员和方法。
当在类的外部访问这些静态成员、方法和常量时,必须使用类的名字。

self 和 parent 这两个特殊的关键字是用于在类的内部对成员或方法进行访问的。
注意:
当一个子类覆盖其父类中的方法时,PHP 不会再执行父类中已被覆盖的方法,直到子类中调用这些方法为止

例子:

<?php
class OtherClass extends MyClass
{
    public static $my_static = &#39;static var&#39;;

    public static function doubleColon() {
        echo parent::CONST_VALUE . "\n";
        echo self::$my_static . "\n";
    }
}

OtherClass::doubleColon();
?>

---------------------------------------------------

7.Static关键字

声明类成员或方法为static,就可以不实例化类而直接访问。不能通过一个对象来访问其中的静态成员(静态方法除外)。

静态成员属于类,不属于任何对象实例,但类的对象实例都能共享。
小结:

在类内部访问静态成员属性或者方法,使用 self::(没有 $ 符号),如:
 self:: $country  //类内部访问静态成员属性
 self:: myCountry()
在子类访问父类静态成员属性或方法,使用 parent::(没有 $ 符号),如:
 parent:: $country
 parent:: myCountry()
外部访问静态成员属性和方法为 类名/子类名:: ,如:
 Person::$country
 Person::myCountry()
 Student::$country
但静态方法也可以通过普通对象的方式访问

<?php

Class Person{
    // 定义静态成员属性
    public static $country = "中国";
    // 定义静态成员方法
    public static function myCountry() {
        // 内部访问静态成员属性
        echo "我是".self::$country."人<br />";
    }
}
class Student extends Person {
    function study() {
        echo "我是". parent::$country."人<br />";
    }
}
// 输出成员属性值
echo Person::$country."<br />";     // 输出:中国
$p1 = new Person();
//echo $p1->country;            // 错误写法
// 访问静态成员方法
Person::myCountry();            // 输出:我是中国人
// 静态方法也可通过对象访问:
$p1->myCountry();

// 子类中输出成员属性值
echo Student::$country."<br />";    // 输出:中国
$t1 = new Student();
$t1->study();           // 输出:我是中国人

?>

---------------------------------------------------

8.抽象类    PHP5支持抽象类和抽象方法。

      抽象类不能直接被实例化,你必须先继承该抽象类,然后再实例化子类。
      抽象类中 至少要包含一个抽象方法。如果类方法被声明为抽象的,那么其中就不能包括具体的功能实现。
      继承一个抽象类的时候,子类必须实现抽象类中的所有抽象方法;
      另外,这些方法的可见性 必须和抽象类中一样(或者更为宽松)。
      如果抽象类中某个抽象方法被声明为protected,那么子类中实现的方法就应该声明为protected或者public,而不 能定义为private。
      //抽象方法:abstract protected function getValue();
例子1

abstract class AbstractClass{
    // 定义抽象方法
    abstract protected function getValue();
    // 普通方法
    public function printOut(){
        print $this->getValue()."<br />";
    }
}
class ConcreteClass extends AbstractClass{
    protected function getValue(){
        return "abstract ";//抽象方法的实现
    }
}

$class1 = new ConcreteClass;
$class1->printOut();

例子2

abstract class AbstractClass
{
 // 强制要求子类定义这些方法
    abstract protected function getValue();
    abstract protected function prefixValue($prefix);

    // 普通方法(非抽象方法)
    public function printOut() {
        print $this->getValue() . "\n";
    }
}

class ConcreteClass1 extends AbstractClass
{
    protected function getValue() {
        return "ConcreteClass1";
    }

    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass1";
    }
}

class ConcreteClass2 extends AbstractClass
{
    public function getValue() {
        return "ConcreteClass2";
    }

    public function prefixValue($prefix) {
        return "{$prefix}ConcreteClass2";
    }
}

$class1 = new ConcreteClass1;
$class1->printOut();
echo $class1->prefixValue(&#39;FOO_&#39;) ."\n";

$class2 = new ConcreteClass2;
$class2->printOut();
echo $class2->prefixValue(&#39;FOO_&#39;) ."\n";

/*
 * 抽象类不能直接被实例化,你必须先继承该抽象类,然后再实例化子类。
      抽象类中 至少要包含一个抽象方法。如果类方法被声明为抽象的,那么其中就不能包括具体的功能实现。
      继承一个抽象类的时候,子类必须实现抽象类中的所有抽象方法;
      另外,这些方法的可见性 必须和抽象类中一样(或者更为宽松)。
      如果抽象类中某个抽象方法被声明为protected,那么子类中实现的方法就应该声明为protected或者public,而不 能定义为private。
 *
 */

class Person {
    public $name;
    public $age;

    function say() {
        echo "my name is:".$this->name."<br />";
    echo "my age is:".$this->age;
    }
}

// 类的继承

class Student extends Person {
    var $school;    //学生所在学校的属性
    
    function study() {
        echo "my name is:".$this->name."<br />";
        echo "my shool is:".$this->school;
    }       
}

$t1 = new Student();
$t1->name = "zhangsan";
$t1->school = "beijindaxue";
$t1->study();

---------------------------------------------------------------------

9.接口

 接口定义:方法和常量值定义的集合
              通过interface来定义一个接口,就像定义一个标准的类一样,但其中定义所有的方法都是空的。
   
 接口的特性:接口中定义的所有方法都必须是public
 
 接口的实现:一个接口可以使用implements操作符,类中必须实现接口中的所有方法,否则会报fatal错误,如果要实现多个接口,可以使用逗号来分隔多个接口的名称。

抽象类和接口的区别

接口是特殊的抽象类,也可以看做是一个模型的规范。接口与抽象类大致区别如下:

1.一个子类如果 implements 一个接口,就必须实现接口中的所有方法(不管是否需要);如果是继承一个抽象类,只需要实现需要的方法即可。
2.如果一个接口中定义的方法名改变了,那么所有实现此接口的子类需要同步更新方法名;而抽象类中如果方法名改变了,其子类对应的方法名将不受影响,只是变成了一个新的方法而已(相对老的方法实现)。
3.抽象类只能单继承,当一个子类需要实现的功能需要继承自多个父类时,就必须使用接口。
实例1:
// 声明一个'iTemplate'接口

interface iTemplate
{
    public function setVariable($name, $var);
    public function getHtml($template);
}

// 实现接口
// 下面的写法是正确的

class Template implements iTemplate
{
    private $vars = array();
  
    public function setVariable($name, $var)
    {
        $this->vars[$name] = $var;
    }
  
    public function getHtml($template)
    {
        foreach($this->vars as $name => $value) {
            $template = str_replace(&#39;{&#39; . $name . &#39;}&#39;, $value, $template);
        }
 
        return $template;
    }
}

实例2:
//定义接口

interface User{
     function getDiscount();
     function getUserType();
 }

//VIP用户 接口实现

 class VipUser implements User{
     // VIP 用户折扣系数
     private $discount = 0.8;
     function getDiscount() {
         return $this->discount;
     }
     function getUserType() {
         return "VIP user";
     }
 }
 class Goods{
     var $price = 100;
     var $vc;
     //定义 User 接口类型参数,这时并不知道是什么用户
     function run(User $vc){
         $this->vc = $vc;
         $discount = $this->vc->getDiscount();
         $usertype = $this->vc->getUserType();
         echo $usertype."goods Price:".$this->price*$discount;
     }
 }

$display ->run(new VipUser);    //可以是更多其他用户类型

-------------------------------------------------------------

10.重载

   定义:一个类中的方法与另一个方法名称相同,但参数不同
   什么情况下执行重载?  当调用当前的环境下未被定义的属性或者方法时,或者当调用当前环境下不可见的属性或方法。
  
提示:
 如果父类定义方法时使用了 final 关键字,则不允许被子类方法覆盖。

 访问父类被覆盖的方法
 可以通过parent:: 符号来访问父类被覆盖的方法或成员属性:
 //PHP 重载方法 call()

 call()(Method overloading)
为了避免当调用的方法不存在时产生错误,可以使用 call() 方法来避免。该方法在调用的方法不存在时会自动调用,程序仍会继续执行下去。

语法:
// call()方法重载

class Test{
    public function call($name,$args){
     if($name== &#39;null&#39; && count($args)==2 ){
      $type=&#39;num&#39;;
   foreach($args as $key => $val){
       if(!(is_int($val) || is_float($val))){
        $type= &#39;string&#39;;
    }
   }
   $method=$name.ucfirst($type);
   if(method_exists($this,$method),$args){
       call_user_func_array(array($this,$method),$args);
   }
  }
 }
 public addNum($i,$j){
     echo $i+$j;
 }
 
 public addString($i,$j){
     echo $i.$j;
 }
}
$test =new Test();
$test->add(3,4);
$test->add(3,&#39;4&#39;);

案例:

class MemberTest {
      
    private $data = array();//被重载的数据保存在此  
    public $declared = 1;/**  重载不能被用在已经定义的属性  */
    private $hidden = 2; /**  只有从类外部访问这个属性时,重载才会发生 */

    public function set($name, $value) {
        echo "Setting &#39;$name&#39; to &#39;$value&#39;\n";
        $this->data[$name] = $value;
    }

    public function get($name) {
        echo "Getting &#39;$name&#39;\n";
        if (array_key_exists($name, $this->data)) {
            return $this->data[$name];
        }

        $trace = debug_backtrace();
        trigger_error(
            &#39;Undefined property via get(): &#39; . $name .
            &#39; in &#39; . $trace[0][&#39;file&#39;] .
            &#39; on line &#39; . $trace[0][&#39;line&#39;],
            E_USER_NOTICE);
        return null;
    }

    /**  PHP 5.1.0之后版本 */
    public function isset($name) {
        echo "Is &#39;$name&#39; set?\n";
        return isset($this->data[$name]);
    }

    /**  PHP 5.1.0之后版本 */
    public function unset($name) {
        echo "Unsetting &#39;$name&#39;\n";
        unset($this->data[$name]);
    }

    /**  非魔术方法  */
    public function getHidden() {
        return $this->hidden;
    }
}


echo "<pre class="brush:php;toolbar:false">\n";

$obj = new MemberTest;

$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&#39;s experiment with the private property named &#39;hidden&#39;:\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";

//属性重载:set(),get(),isset(),unset()

class Person{
    private $data =array();
    function set($name,$value){
     $this->data[$name]=$value;
 }
 function get($name){
     return $this->data[$name];
 }
}

-----------------------------------------------------------------------------------

11.对象迭代

       PHP5提供了一种迭代(iteration)对象的功能,就像使用数组那样,可以通过foreach 来遍历对象中的属性       

class MyClass
{
    public $var1 = &#39;value 1&#39;;
    public $var2 = &#39;value 2&#39;;
    public $var3 = &#39;value 3&#39;;

    protected $protected = &#39;protected var&#39;;
    private   $private   = &#39;private var&#39;;

    function iterateVisible() {
       echo "MyClass::iterateVisible:\n";
       foreach($this as $key => $value) {
           print "$key => $value\n";
       }
    }
}

$class = new MyClass();

foreach($class as $key => $value) {
    print "$key => $value\n";
}
echo "\n";


$class->iterateVisible();

---------------------------------------------------------------------------

12.设计模式: 工厂模式和 单例模式,    观察者模式,命令链模式和策略模式

 命令链 模式以松散耦合主题为基础,发送消息、命令和请求,或通过一组处理程序发送任意内容。每个处理程序都会自行判断自己能否处理请求。
如果可以,该请求被处理,进程停止。您可以为系统添加或移除处理程序,而不影响其他处理程序。

工厂模式
    定义:工厂模式(Factory)允许你在代码执行时实例化对象。它之所以被称为工厂模式是因为它负责“生产”对象。工厂方法的参数是你要生成的对象对应的类名称。
 
工厂模式语法:

<?php
class Example
{
    public static function factory($type)
    {
        if (include_once &#39;Drivers/&#39; . $type . &#39;.php&#39;) {
            $classname = &#39;Driver_&#39; . $type;
            return new $classname;
        } else {
            throw new Exception (&#39;Driver not found&#39;);
        }
    }
}
?>

   工厂模式案例:

<?php
interface IUser{
 function getName();
}
class User implements IUser{
 public function construct($id){}
 public function getName(){
     return "haha";
 }
}
class UserFactory{
    public static function Create($id){
  return new User($id);
 }
}
$uo =UserFactory::Create(1);
echo $uo->getName();

?>

单例
   定义三要素:1,某个类只能有一个实例  2,必须自行创建这个实例  3,必须自行向系统提供这个实例
  
   作用: 1,如果系统中需要有一个类来全局控制某些配置信息,那么使用单例模式可以很方便的实现。
          2,使用单例模式,可以避免大量的new操作消耗资源()
          3在一个页面请求中,便于调试,因为所有的代码都集中在一个类中(如数据库操作类) 可以在类中设置钩子,输出日志,从而避免到处都是var_dump
    
单例模式(Singleton)用于为一个类生成一个唯一的对象。最常用的地方是数据库连接。 使用单例模式生成一个对象后,该对象可以被其它众多对象所使用。
单件模式是我们在开发中经常用到的一种设计模式,利用PHP5面向对象的特性,我们可以很容易的构建单件模式的应用,下面是单件模式在PHP中的几种实现方法:

class Stat{
    static $instance = NULL;
    
    static function getInstance(){
        if(self::$instance == NULL){
            self::$instance = new Stat();
        }
        
        return self::$instance;
    }    
    private function construct(){
    }    
    private function clone(){
    }    
    
    function sayHi(){
        return "The Class is saying hi to u ";
    }
}


echo Stat::getInstance()->sayHi();

这是一种最通常的方式,在一个getInstance方法中返回唯一的类实例。

对这里例子稍加修改,便可以产生一个通用的方法,只要叫道任何你想用到单件的类里,就可以了。

class Teacher{
    function sayHi(){
        return "The teacher smiling and said &#39;Hello &#39;";
    }
    
    static function getInstance(){
        static $instance;
        
        if(!isset($instance)){
            $c = CLASS;
            $instance = new $c;
        }        
        return $instance;
    }
}

echo Teacher::getInstance()->sayHi();

最后一种是提供一个singleton类,然后通过调用getInstance方法,可以为任何一个类生产出一个实例来。

class singleton{
    function getInstance($class){
        static $instances = array();
        if(!array_key_exists($class,$instances)){
            $instances[$class] = &new $class;
        }
        $instance = $instances[$class];
        
        return $instance;
    }
}

class People{
    function sayHi(){
        return &#39;Hello i am a people?&#39;;
    }
}

echo "<br />";
echo singleton::getInstance(&#39;People&#39;)->sayHi();

通过这三种方法,我们可以很容易的应用单件模式,如果能够结合工厂模式,将使我们的编程变得更有条理和效率。
---------------------------------------------------------------------------------------

13.魔术方法

  定义:PHP把所有以(两个下划线)开头的类方法当成魔术方法
  construct, destruct (参看 构造方法和析构方法),
  call, callStatic, get, set, isset, unset (参看 重载),
  sleep, wakeup, toString, set_state 和 clone 等方法在PHP中被称为“魔术方法”(Magic methods)。
  你在命名自己的类方法时不能使用这些方法名。  
  serialize()
  作用: 第一. 在序列化之前,关闭对象可能具有的任何数据库连接等.
        第二. 指定对象中需要被序列化的成员属性,如果某个属性比较大而不需要储存下来,可以不把它写进sleep要返回的数组中,这样该属性就不会被序列化
  在用serialize序列化对象时,会自动调用sleep方法,sleep方法必须返回一个数组,包含需要串行化的属性。
       PHP会抛弃其它属性的值, 如果没有sleep方法,PHP将保存所有属性,包括private属性。

  unserialize()  从字节流中创建了一个对象之后,马上检查是否具有wakeup 的函数的存在。
  如果存在,wakeup 立刻被调用。使用 wakeup 的目的是重建在序列化中可能丢失的任何数据库连接以及处理其它重新初始化的任务。

下面给出一个序列化的代码:共serialize.php和unserialize.php两个文件。

<?php
   class User 
   { 
       public $name; 
       public $id;

       function construct() 
       { 
           $this->id = uniqid();          //give user a unique ID 赋予一个不同的ID 
       }

       function sleep() 
       {    
           return(array("name"));        //do not serialize this->id 不串行化id
       }

       function wakeup() 
       { 
           $this->id = uniqid();         //give user a unique ID 
       } 
   }

   $u = new User; 
   $u->name = "HAHA";

   $s = serialize($u);                   //serialize it 串行化 注意不串行化id属性,id的值被抛弃

   $u2 = unserialize($s);                //unserialize it 反串行化 id被重新赋值

   
   //$u and $u2 have different IDs $u和$u2有不同的ID 
   var_dump($u);                         
   var_dump($u2); 
?>

---------- PHP debug ----------
object(User)#1 (2) {
["name"]=>
string(4) "HAHA"
["id"]=>
string(13) "47fa045529f69"
}
object(User)#2 (2) {
["name"]=>
string(4) "HAHA"
["id"]=>
string(13) "47fa04552a49a"
}

---序列化--------反序列化--------------------

class ClassA {
    var $int;
    var $str;
    var $bool;
    var $obj;
    var $pr;
}
 
$a = new ClassA();
$a->int = 1;
$a->str = "Hello";
$a->bool = false;
$a->obj = $a;
$a->pr = &$a->str;
 
echo serialize($a);
//O:6:"ClassA":5:{s:3:"int";i:1;s:3:"str";s:5:"Hello";s:4:"bool";b:0;s:3:"obj";r:1;s:2:"pr";R:3;}

  在这个例子中,首先序列化的对象是 ClassA 的一个对象,那么给它编号为 1,接下来要序列化的是这个对象的几个成员,第一个被序列化的成员是 int 字段,那它的编号就为 2,接下来被序列化的成员是 str,那它的编号就是 3,依此类推,到了 obj 成员时,它发现该成员已经被序列化了,并且编号为 1,因此它被序列化时,就被序列化成了 r:1; ,在接下来被序列化的是 pr 成员,它发现该成员实际上是指向 str 成员的一个引用,而 str 成员的编号为 3,因此,pr 就被序列化为 R:3; 了。
===============

//下面举个简单的例子,来说明 Serializable 接口的使用:序列化--------反序列化-

class MyClass implements Serializable
{
    public $member;
 
    function MyClass()
    {
        $this->member = &#39;member value&#39;;
    }
 
    public function serialize()
    {
        return wddx_serialize_value($this->member);
    }
 
    public function unserialize($data)
    {
        $this->member = wddx_deserialize($data);
    }
}
$a = new MyClass();
echo serialize($a);
echo "\n";
print_r(unserialize(serialize($a)));

/*
输出结果为(浏览器中的源代码):

C:7:"MyClass":90:{509d97f1a3b48a3135526503e2c1e9e89b7bea787ff04bc9fc99a05cdeb147f61d029f6197b5a3eb8a3fdf0a088ddf5598c455a79ddfebb79781bff588e7b37emember valuedba3c644993c36696c11b074e67a407807b4fdd0136efc154b4b9d48cfcbbb9d82cc18cf5509084bb7cfe456cea76b26}
MyClass Object
(
    [member] => member value
)
因此如果想用其它语言来实现 PHP 序列化中的 C 标示的话,也需要提供一种这样的机制,让用户自定义类时,
能够自己在反序列化时处理 1d029f6197b5a3eb8a3fdf0a088ddf55 内容,否则,这些内容就无法被反序列化了。

*/
、、、、
  sleep 和 wakeup
serialize() 函数会检查是否存在一个魔术方法 sleep.如果存在,sleep()方法会先被调用, 然后才执行序列化操作。这个功能可以用于清理对象,并返回一个包含对象中所有变量名称的数组。如果该方法不返回任何内容,则NULL被序列化,导致 一个E_NOTICE错误。

sleep方法常用于提交未提交的数据,或类似的操作。同时,如果你有一些很大的对象,不需要保存,这个功能就很好用。

与之相反,unserialize()会检查是否存在一个wakeup方法。如果存在,则会先调用 wakeup方法,预先准备对象数据。

wakeup经常用在反序列化操作中,否则是字符串;例如重新建立数据库连接,或执行其它初始化操作

------------------------------------------------------------------------------------------------

14. Final关键字

  如果父类中的方法被声明为final,则子类无法覆盖该方法; 如果一个类被声明为final,则不能被继承。
  语法:
 类使用 final 关键字的例子:

final class Person
 {
  ......
 }
  
  class BaseClass {
    public function test() {
     echo "BaseClass::test() called\n";
    }
    
    final public function moreTesting() {
     echo "BaseClass::moreTesting() called\n";
    }
 }

class ChildClass extends BaseClass {
    public function moreTesting() {
       echo "ChildClass::moreTesting() called\n";
   }
}

---------------------------------------------

15.对象复制

对象复制可以通过clone关键字来完成(如果对象中存在clone()方法,会先被调用)。对象中的 clone()方法不能直接调用。
 $copy_of_object = clone $object;
clone 关键字用于克隆一个完全一样的对象,

clone() 
 clone() 方法来重写原本的属性和方法。是深复制
如果想在克隆后改变原对象的内容,需要在类中添加一个特殊的 clone() 方法来重写原本的属性和方法。
 clone() 方法只会在对象被克隆的时候自动调用。

clone 关键字用于克隆一个完全一样的对象,clone() 方法来重写原本的属性和方法。

对象克隆
有的时候我们需要在一个项目里面使用两个或多个一样的对象,如果使用 new 关键字重新创建对象,再赋值上相同的属性,这样做比较烦琐而且也容易出错。
PHP 提供了对象克隆功能,可以根据一个对象完全克隆出一个一模一样的对象,而且克隆以后,两个对象互不干扰。

使用关键字 clone 来克隆对象。语法: $object2 = clone $object;
例子1:
2,
clone()
如果想在克隆后改变原对象的内容,需要在类中添加一个特殊的 clone() 方法来重写原本的属性和方法。
clone() 方法只会在对象被克隆的时候自动调用。

//例子1:

/*
class Person {
    private $name;
    private $age;

    public function construct($name, $age) {
        $this->name=$name;
        $this->age=$age;
    }

    public function say() {
        echo "my name is :".$this->name."<br />";
        echo "my age is :".$this->age;
    }
   
}

$p1 = new Person("haha", 20);
$p2 = clone $p1;
$p2->say();
*/
class Person {
    private $name;
    private $age;

    function construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
    }

    function say() {
        echo "my name is :".$this->name."<br/>";
        echo " my age is :".$this->age."<br />";
    }
    function clone() {
        $this->name = "my is error ".$this->name;
        $this->age = 30;
    }
}

$p1 = new Person("haha", 20);
$p1->say();
$p2 = clone $p1;
$p2->say();

------------------------------------------------------------------

16.对象比较 

(==)  如果两个对象的属性和属性值 都相等,而且两个对象是同一个类的实例,那么这两个对象变量相等。

(===),这两个对象变量一定要指向某个类的同一个实例(即同一个对象)。
实例1

class A{

  $a=new A;
  $b=new A; 
   if($a==$b){
      echo "true";
   }else{
      echo "false";
   }
  $c=new A;
  $d=&$c;
      if($c===$d){
      echo "true";
   }else{
      echo "false";
   }

}

实例2
function bool2str($bool)
{
    if ($bool === false) {
        return &#39;FALSE&#39;;
    } else {
        return &#39;TRUE&#39;;
    }
}

function compareObjects(&$o1, &$o2)
{
    echo &#39;o1 == o2 : &#39; . bool2str($o1 == $o2) . "\n";
    echo &#39;o1 != o2 : &#39; . bool2str($o1 != $o2) . "\n";
    echo &#39;o1 === o2 : &#39; . bool2str($o1 === $o2) . "\n";
    echo &#39;o1 !== o2 : &#39; . bool2str($o1 !== $o2) . "\n";
}

class Flag
{
    public $flag;

    function Flag($flag = true) {
        $this->flag = $flag;
    }
}

class OtherFlag
{
    public $flag;

    function OtherFlag($flag = true) {
        $this->flag = $flag;
    }
}

$o = new Flag();
$p = new Flag();
$q = $o;
$r = new OtherFlag();

echo "Two instances of the same class\n";
compareObjects($o, $p);

echo "\nTwo references to the same instance\n";
compareObjects($o, $q);

echo "\nInstances of two different classes\n";
compareObjects($o, $r);

-----------------------------------------

17.对象和引用

  引用:php的引用是别名,就是两个不同的变量名字指向相同的内容

class A {
    public $foo = 1;
}  

$a = new A;
$b = $a;     // $a ,$b都是同一个标识符的拷贝
             // ($a) = ($b) = <id>    
$b->foo = 2;
echo $a->foo."\n";


$c = new A;
$d = &$c;    // $c ,$d是引用
             // ($c,$d) = <id>

$d->foo = 2;
echo $c->foo."\n";


$e = new A;

function foo($obj) {
    // ($obj) = ($e) = <id>
    $obj->foo = 2;
}

foo($e);
echo $e->foo."\n";

-------------------------------------------------------------------------------

对象序列化
序列化对象 - 在会话中存放对象
所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。
unserialize()函数能够重新把字符串变回php原来的值。

序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。
为了能够unserialize()一个对象,这个对象的类必须已经定义过。
如果序列化类A的一个对象,将会返回一个跟类A相关,而且包含了对象所有变量值的字符串。
如果要想在另外一个文件中解序列化一个对象,这个对象的类必须在解序列化之前定义,可以通过包含一个定义该类的文件或使用函数spl_autoload_register()来实现

实例1:

class A {
      public $one = 1;
    
      public function show_one() {
          echo $this->one;
      }
  }
  
// page1.php:

  include("classa.inc");
  
  $a = new A;
  $s = serialize($a);

  // 把变量$s保存起来以便文件page2.php能够读到
  file_put_contents('store', $s);

// page2.php:
  // 要正确了解序列化,必须包含下面一个文件
  include("classa.inc");

  $s = file_get_contents('store');
  $a = unserialize($s);

  // 现在可以使用对象$a里面的函数 show_one()
  $a->show_one();
------------------------------------
后期静态绑定
     后期绑定“的意思是说,static::不再被解析为定义当前方法所在的类,而是在实际运行时计算的。也可以称之为”静态绑定“,因为它可以用于(但不限于)静态方法的调用
     后期静态绑定的功能:用于在继承范围内引用静态调用的类。

self:: 的限制
使用self:: 或者 CLASS对当前类的静态引用,取决于定义当前方法所在的类:

实例1:

<?php
class A {
    public static function who() {
        echo CLASS;
    }
    public static function test() {
        self::who();
    }
}

class B extends A {
    public static function who() {
        echo CLASS;
    }
}

B::test();
?>

------------------------------------------------------------------------------------------

18.$this关键字

          $this 的含义是表示 实例化后的 具体对象!   
    this的用法:

    1,this是指向对象实例的一个指针,self是对类本身的一个引用,parent是对父类的引用。

    1,类的内部使用:如果从类的内部访问不为常量const或者static变量或者方法,那么就必须使用自引用的$this
    2,在构造函数中 指该构造函数创建新对象
    3,引用$this,代表当前的类,解决变量命名冲突和不确定性问题\
    --------------------------------

class Test{
 function call($name,$args){
  if($name==&#39;add&#39; && count($args)==2){
   $type=&#39;num&#39;;
  }
  foreach ($args as $key=>$val){
   if(!is_int($val) || is_float($val)){
    $type=&#39;string&#39;;
   }
  }
  $method=$name.ucfirst($type);
  
  if(method_exists($this,$method)){
   call_user_func_array(array($this,$method),$args);
  }
 }
 function addNum(){
  echo $i+$j;
 }
 function addString(){
  echo $i.$j;
 }
}
$test = new Test();
$test->add(3,5);
$test->add(4,&#39;4&#39;);

----------------------------------------------
/*
 * 常量 const
在类里面定义常量用 const 关键字,而不是通常的 define() 函数。
语法: const constant = "value";
例子:
运行该例子输出:
 中国
 我是中国人
 *
 */

Class Person{
    // 定义常量
    const COUNTRY = "china";
    public function myCountry() {
        //内部访问常量
        echo "my is ".self::COUNTRY." person<br />";
    }
}
// 输出常量
echo Person::COUNTRY."<br />";
// 访问方法
$p1 = new Person();
$p1 -> myCountry();
Person::myCountry();

--------------------
/*
 * PHP 对象的存储与传输(序列化 serialize 对象)
对象的存储与传输
在实际项目应用中,有些任务在一两个页面是无法完成的,由于变量到脚本执行完毕就释放,我们本页所生成的对象想在其它页面使用时便碰到了麻烦。

如果需要将对象及其方法传递到我们想使用对象的页面,比较简单可行的办法是将对象序列化后存储起来或直接传输给需要的页面,另一种办法是将对象注册为 session 变量。

序列化对象
对象序列化,就是将对象转换成可以存储的字节流。当我们需要把一个对象在网络中传输时或者要把对象写入文件或是数据库时,就需要将对象进行序列化。

序列化完整过程包括两个步骤:一个是序列化,就是把对象转化为二进制的字符串,serialize() 函数用于序列化一个对象;另一个是反序列化,就是把对象被序列转化的二进制字符串再转化为对象,unserialize() 函数来反序列化一个被序列化的对象。这样整个过程下来,对象内的类型结构及数据都是完整的。

语法:

string serialize( mixed value )
mixed unserialize( string str [, string callback] )
 *
 */

class Person {
    private $name;
    private $age;

    function construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
    }

    function say() {
    echo "my name is ".$this->name."<br />";
    echo " my age is ".$this->age;
    }
}

$p1 = new Person("haha", 20);
$p1_string = serialize($p1);

//将对象序列化后写入文件
$fh = fopen("p1.text", "w");
fwrite($fh, $p1_string);
fclose($fh);

--------------
1724fcbc3110d867b32cb33b3e08d576取值。方法内的局部变量,不属于对象,不使用$this关键字取值。

局部变量和全局变量与 $this 关键字
4,使用当前对象的属性必须使用$this关键字。

局部变量的只在当前对象的方法内有效,所以直接使用。

注意:局部变量和属性可以同名,但用法不一样。在使用中,要尽量避免这样使用,以免混淆。

1234567891011121314 43ab8c3da78ddbc4b158320c00644d7f

<?php 
class A{     
    private $a = 99;     //这里写一个打印参数的方法.     
    public function printInt($a){         
        echo "这里的 \$a 是传递的参数 $a ";         
        echo "<br>";         
        echo "这里的 \$this->a 是属性 $this->a";     
    } 
} 
 $a = new A(); // 这里的$a 可不是类中的任何一个变量了. 
 $a->printInt(88);
?>

运行结果:

12 这里的 $a 是传递的参数 88 这里的 $this->a 是属性 99

用$this调用对象中的其它方法
1234567891011121314151617 b7b4fc3c970b56f49931a69793b921f0

<?php 
class Math{     //两个数值比较大小.     
    public function Max($a,$b){         
        return $a>$b?$a:$b;     
    }     //三个数值比较大小.     
    public function Max3($a,$b,$c){         //调用类中的其它方法.        
         $a = $this->Max($a,$b);         
        return $this->Max($a,$c);     
    }
} 
$math = new Math(); 
echo "最大值是 ".$math->Max3(99,100,88); 
?>

运行结果:

1 最大值是 100

使用$this调用构造函数
调用构造函数和析构函数的方法一致。

12345678910111213141516

<? class A{     
private $a = 0;     
public function construct(){         
$this->a = $this->a + 1 ;     
}       
public function doSomeThing(){         
$this->construct();         
return $this->a;     
}      
} 
$a = new A(); 
// 这里的$a 可不是类中的任何一个变量了. 
echo "现在 \$a 的值是" . $a->doSomeThing(); 
?>

运行结果:

1 现在 $a 的值是2

$this 到底指的什么?
$this 就是指当前对象,我们甚至可以返回这个对象使用 $this

12345678910111213

 <?php class A{     
 public function  getASelf(){         
 return $this;     
 }     
 public function toString(){         
 return "这是类A的实例.";     
 } 
 } 
 $a = new A(); 
 // 创建A的实例; 
 $b = $a->getASelf(); 
 //调用方法返回当前实例. 
 echo $a; 
 //打印对象会调用它的toString方法. 
 ?>

程序运行结果:

1 这是类A的实例.

通过 $this 传递对象
在这个例子中,我们写一个根据不同的年龄发不同工资的类.
我们设置处理年龄和工资的业务模型为一个独立的类.

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455

<?php 
class User{     
private $age ;     
private $sal ;     
private $payoff ; 
//声明全局属性.       
//构造函数,中创建Payoff的对象.     
public function construct(){         
$this->payoff = new Payoff();     
}     
public function getAge(){         
return $this->age;     
}     
public function setAge($age){         
$this->age = $age;     
}     
// 获得工资.     
public  function getSal(){         
$this->sal =  
$this->payoff->figure($this);         
return $this->sal;     
} 
} 
//这是对应工资与年龄关系的类. 
class Payoff{     
public function figure($a){         
$sal =0;         
$age = $a->getAge();         
if($age >80 || $age <16 ){             
$sal = 0;         
}elseif ($age > 50){             
$sal = 1000;         
}else{             
$sal = 800;         
}         
return $sal;     
} } 
//实例化User 
$user = new User();   
$user->setAge(55); 
echo $user->getAge()."age ,his sal is " . $user->getSal(); echo "<br>";   
$user->setAge(20); 
echo $user->getAge()."age , his sal is " . $user->getSal(); echo "<br>";   
$user->setAge(-20); echo $user->getAge()."age , his sal is " . $user->getSal(); echo "<br>";  
$user->setAge(150); echo $user->getAge()."age , his sal is " . $user->getSal(); 
?>

运行结果:

1234 55age ,his sal is 1000 20age , his sal is 800 -20age , his sal is 0 150age , his sal is 0.
**/

Das obige ist der detaillierte Inhalt vonDas Konzept von PHP-Klassen und -Objekten. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn