[PHP] 02 - Namespace & Class

兩個比較大的話題,獨立成本篇。php

 

面向對象編程


1、命名空間

PHP 命名空間能夠解決如下兩類問題:html

    1. 用戶編寫的代碼與PHP內部的類/函數/常量或第三方類/函數/常量之間的名字衝突。
    2. 爲很長的標識符名稱 (一般是爲了緩解第一類問題而定義的) 建立一個別名(或簡短)的名稱,提升源代碼的可讀性。

 

  • 模塊化寫法

[1] 能夠在同一個文件中定義不一樣的命名空間代碼,如:編程

<?php  
namespace MyProject; const    CONNECT_OK = 1;
class    Connection { /* ... */ }
function connect() { /* ... */  }

namespace AnotherProject; const    CONNECT_OK = 1;
class    Connection { /* ... */ }
function connect() { /* ... */  }
?>  

 

[2] 其實,加個大括號會更好些session

<?php
namespace MyProject {
    const    CONNECT_OK = 1;
    class    Connection { /* ... */ }
    function connect() { /* ... */  }
}

namespace AnotherProject {
    const    CONNECT_OK = 1;
    class    Connection { /* ... */ }
    function connect() { /* ... */  }
}
?>

  

  • 全局代碼
<?php
namespace MyProject {

  const    CONNECT_OK = 1;
  class    Connection { /* ... */ }
  function connect()  { /* ... */  }
}

namespace { // 全局代碼
  session_start();
  $a = MyProject\connect();
  echo MyProject\Connection::start();
}
?>

 

  • declare 語句
<?php
declare(encoding='UTF-8'); // 定義多個命名空間和不包含在命名空間中的代碼

namespace MyProject {   const CONNECT_OK = 1;   class Connection { /* ... */ }   function connect() { /* ... */ } } namespace { // 全局代碼   session_start();   $a = MyProject\connect();   echo MyProject\Connection::start(); } ?>

  

  • 子命名空間
<?php
namespace MyProject\Sub\Level;  // 聲明分層次的單個命名空間

const CONNECT_OK = 1;
class Connection { /* ... */ }
function Connect() { /* ... */  }

?>

 

上面的例子建立了:ide

  1. 常量  MyProject\Sub\Level\CONNECT_OK
  2. 類  MyProject\Sub\Level\Connection
  3. 函數 MyProject\Sub\Level\Connect

 

 

2、命名空間使用

 /* implement */模塊化

 

 

 

3、面向對象

列舉概念類,對象,成員變量,成員函數,繼承,父類,子類,多態,重載,抽象性,封裝,構造函數,析構函數。函數

[1] 一個綜合性的例子:post

<?php
class Site {
/* 成員變量 */ var $url; var $title;
---------------------------------------------------------
function __construct( $par1, $par2 ) { $this->url = $par1; $this->title = $par2; }

---------------------------------------------------------
/* 成員函數 */ function setUrl($par){ $this->url = $par; } function getUrl(){ echo $this->url . PHP_EOL; } function setTitle($par){ $this->title = $par; } function getTitle(){ echo $this->title . PHP_EOL; } }
---------------------------------------------------------
$runoob = new Site('www.runoob.com', '菜鳥教程'); $taobao = new Site('www.taobao.com', '淘寶'); $google = new Site('www.google.com', 'Google 搜索');
---------------------------------------------------------
// 調用成員函數,獲取標題和URL $runoob->getTitle(); $taobao->getTitle(); $google->getTitle(); $runoob->getUrl(); $taobao->getUrl(); $google->getUrl(); ?>

 

[2] 析構函數this

<?php
class MyDestructableClass {
   function__construct() {
       print "構造函數\n";
       $this->name = "MyDestructableClass";
   }

   function__destruct() {
       print "銷燬 " . $this->name . "\n";
   }
}

$obj = new MyDestructableClass();
?>

 

php中對應的malloc是什麼? - ref: php 內存分配google

php內核中的內存分配 使用的函數有 emalloc(), erealloc() ,這兩個函數分別是malloc(),realloc()函數的封裝

 

[3] extends 繼承

<?php 
// 子類擴展站點類別
class Child_Site extends Site {
   var $category;

    function setCate($par){
        $this->category = $par;
    }
  
    function getCate(){
        echo $this->category . PHP_EOL;
    }
}

 

[4] override 重寫

[5] 訪問控制

  • 【屬性】的訪問控制
<?php
/**
 * Define MyClass
 */
class MyClass
{
    public    $public    = 'Public';
    protected $protected = 'Protected';
    private   $private   = 'Private';

    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 /** * Define MyClass2 */ class MyClass2 extends MyClass { // 能夠對 public 和 protected 進行重定義,但 private 而不能 protected $protected = 'Protected2'; function printHello() { echo $this->public; echo $this->protected; echo $this->private; } }
-------------------------------------------------------------
$obj2 = new MyClass2(); echo $obj2->public; // 這行能被正常執行 echo $obj2->private; // <-- 未定義 private echo $obj2->protected; // <-- 這行會產生一個致命錯誤 $obj2->printHello(); // 輸出 Public、Protected2 和 Undefined ?>
  • 【方法】的訪問控制
<?php
/**
 * Define MyClass
 */
class MyClass
{
    public function __construct() { }

---------------------------------------------------------------
public function MyPublic() { } protected function MyProtected() { } private function MyPrivate() { } // 此方法爲公有 function Foo() { $this->MyPublic(); $this->MyProtected(); $this->MyPrivate(); } }
---------------------------------------------------------------
$myclass = new MyClass; $myclass->MyPublic(); // 這行能被正常執行 $myclass->MyProtected(); // 這行會產生一個致命錯誤 $myclass->MyPrivate(); // 這行會產生一個致命錯誤 $myclass->Foo(); // 公有,受保護,私有均可以執行 /** * Define MyClass2 */ class MyClass2 extends MyClass { // 此方法默認爲公有 function Foo2() { $this->MyPublic(); $this->MyProtected(); $this->MyPrivate(); // 這行會產生一個致命錯誤 } }

---------------------------------------------------------------
$myclass2 = new MyClass2; $myclass2->MyPublic(); // 這行能被正常執行 $myclass2->Foo2(); // 公有的和受保護的均可執行,但私有的不行 class Bar { public function test() { $this->testPrivate(); $this->testPublic(); } public function testPublic() { echo "Bar::testPublic\n"; } private function testPrivate() { echo "Bar::testPrivate\n"; } } class Foo extends Bar { public function testPublic() { echo "Foo::testPublic\n"; } private function testPrivate() { echo "Foo::testPrivate\n"; } } $myFoo = new foo(); $myFoo->test(); // Bar::testPrivate // Foo::testPublic ?>

 

[6] 接口的實現

<?php

// 聲明一個'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('{' . $name . '}', $value, $template);
        }
 
        return $template;
    }
}

 

[7] 抽象類

<?php
abstract class AbstractClass
{
 // 強制要求子類定義這些方法
    abstract protected function getValue();
    abstract protected function prefixValue($prefix);

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

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('FOO_') . PHP_EOL;

$class2 = new ConcreteClass2;
$class2->printOut();
echo $class2->prefixValue('FOO_') . PHP_EOL;
?> 

考點

此外,子類方法能夠包含父類抽象方法中不存在的可選參數。

例如,子類定義了一個可選參數,而父類抽象方法的聲明裏沒有,則也是能夠正常運行的。

 

[8] const 常量

類中的常量,自帶static屬性。

 

[9] Static 關鍵字

考點

因爲靜態方法不須要經過對象便可調用,因此僞變量 $this 在靜態方法中不可用

<?php
class Foo {
  public static $my_static = 'foo';
  
  public function staticValue() {
     return self::$my_static;
  }
}

print Foo::$my_static . PHP_EOL;
$foo = new Foo();

print $foo->staticValue() . PHP_EOL;
?>  

 

[10] Final 關鍵字

若是父類中的方法被聲明爲 final,則子類沒法覆蓋該方法。

若是一個被聲明爲 final,則不能被繼承。 

 

[11] 調用父類構造方法

須要本身去手動調用

<?php
class BaseClass {
   function __construct() {
       print "BaseClass 類中構造方法" . PHP_EOL;
   }
}
class SubClass extends BaseClass { function __construct() { parent::__construct(); // 子類構造方法不能自動調用父類的構造方法 print "SubClass 類中構造方法" . PHP_EOL; } }
class OtherSubClass extends BaseClass { // 繼承 BaseClass 的構造方法 } // 調用 BaseClass 構造方法 $obj = new BaseClass(); // 調用 BaseClass、SubClass 構造方法 $obj = new SubClass(); // 調用 BaseClass 構造方法 $obj = new OtherSubClass(); ?>

 

 

 

考點


1、繼承中的 Static關鍵字 

Ref: PHP static關鍵字的用法及注意點

  • static變量

  a). 能夠不賦初值
  b). 不會存儲引用。

 

  • 延遲靜態綁定
class A {
    public static function foo() {
        static::who();     // Jeff: 再也不爲定義當前方法所在的類,而是實際運行時所在的類的who()
    }
 
    public static function who() {
        echo __CLASS__."\n";
    }
}
 
class B extends A {
    public static function test() {
        A::foo();      // 是在A的運行時環境中
        parent::foo();     // 使用了運行時調用類
        self::foo();
    }
 
    public static function who() {
        echo __CLASS__."\n";
    }
}

class C extends B {
    public static function who() {
        echo __CLASS__."\n";
    }
}

C::test();

----------------------------------
結果:
  A
  C
  C

同理,也是要注意」運行時「這個概念!

class A { 
  protected static $var1 = null; 
  protected static $var2 = null; 
public static function test(){ if(!static::$var2){ static::$var2 = static::$var1; } echo get_called_class().' '.static::$var2.' '; } }
class B extends A { protected static $var1 = 'b'; }
class C extends A { protected static $var1 = 'c'; }
B
::test();   // 第一次調用test, var2還未賦值. C::test();   // 第二次調用test, var2已賦值.
相關文章
相關標籤/搜索