PHP學習 Day 4 語言參考(下半篇)

函數

函數具備全局做用域,能夠定義在一個函數以內而在該函數以外調用。php


function foo() { function bar() { echo "I don't exist until foo() is called.\n"; } } /* 如今還不能調用bar()函數,由於它還不存在 */ foo(); /* 如今能夠調用bar()函數了,由於foo()函數 的執行使得bar()函數變爲已定義的函數 */ bar();

若是要保證定義在函數內部的函數外部不可用,須要使用匿名函數:segmentfault


function foo() { $bar = function() { echo "inside"; }; }

函數沒法重載,沒法取消和重定義。若是有此須要,一樣要使用匿名函數。數組

以上兩點能夠總結爲:函數對應於常量,匿名函數對應於變量。閉包

遞歸函數調用過百可能會使堆棧崩潰。ide

函數的默認參數只能用常量表達式定義,不能是變量、函數調用!函數

函數不能返回多個值。this

從函數返回引用時,必須在函數聲明和指派返回值時都使用引用運算符:編碼

function &returns_reference()
{
    return $someref;
}

$newref =& returns_reference();

匿名函數訪問閉包內的變量須要用use ($var)聲明,只讀訪問。spa

PHP也支持相似Perlsh的函數定義,在定義時不指定參數,經過func_num_args()func_get_arg()func_get_args()處理應用函數時傳入的參數。code

函數的參數能夠指定類型,例如對象(指定類的名字)、接口、數組、或者callable,可是不能是數字或字符串,Traits也不容許。(聽說SVN裏有支持數字、字符串的一個實現,可是最後PHP是否會支持這一特性仍然未定。)

匿名函數生成Closure類的實例:

boris> $lambda = function() { echo 'hi'; };
 → object(Closure)(

)

class聲明經過extends代表繼承關係,不支持多重繼承。

能夠經過parent::訪問被覆蓋的方法或屬性。

父類定義方法時聲明final,則不可覆蓋。(final還可用於聲明類,final類不能被繼承。)

覆蓋方法時,參數必須保持一致,不然會拋出E_STRICT警告。

使用ClassName::class能夠獲取類的徹底名稱,對使用了命名空間的類尤爲有用。

類的屬性只能初始化爲定值!

{
   // 錯誤的屬性聲明
   public $var1 = 'hello ' . 'world';
   public $var2 = <<<EOD
hello world
EOD;
   public $var3 = 1+2;
   public $var4 = self::myStaticMethod();
   public $var5 = $myVar;

   // 正確的屬性聲明
   public $var6 = myConstant;
   public $var7 = array(true, false);

   //在 PHP 5.3.0 及以後,下面的聲明也正確
   public $var8 = <<<'EOD'
hello world
EOD;
}

類中能夠定義__construct(),用於創建對象時的初始化工做。顯式地銷燬某個對象,或者對某個對象的全部引用都沒刪除時,會執行__destruct()

屬性必須被定義爲publicprotected(子類、父類可見)、private之一。

類中的方法同理,可是默認public

聲明屬性或方法爲static,就能夠不實例化而直接訪問,例如經過::。靜態屬性不能經過對象來訪問(但靜態方法能夠)。

abstract類不能被實例化。一旦有一個方法被聲明爲abstract,類就必須被聲明爲abstract。繼承抽象類的時候,子類必須定義父類中的全部抽象方法,而且這些方法的訪問控制不能比父類嚴格。

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

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

和抽象類類似的概念是接口,接口的特性是接口中定義的全部方法都必須是公有的。

interface a
{
    public function foo();
}

interface b extends a
{
    public function baz(Baz $baz);
}


class c implements b
{
    public function foo()
    {
    }

    public function baz(Baz $baz)
    {
    }
}

實現接口的類必須實現接口中定義的全部方法。

類能夠實現多個接口,用逗號來分隔多個接口的名稱。(實現多個接口時,接口中的方法不能有重名。)

接口中定義的常量不能被子類或子接口所覆蓋。

使用trait能夠水平組合功能:

trait Hello {
    public function sayHello() {
        echo 'Hello ';
    }
}

trait World {
    public function sayWorld() {
        echo 'World';
    }
}

class MyHelloWorld {
    use Hello, World;
    public function sayExclamationMark() {
        echo '!';
    }
}

trait不能實例化,優先級比類當前成員低,但比繼承的成員高。

多個trait衝突時,使用insteadof指明使用哪個方法,as將方法以其餘名稱引入。

class Aliased_Talker {
    use A, B {
        B::smallTalk insteadof A;
        A::bigTalk insteadof B;
        B::bigTalk as talk;
    }
}

as還可用於修改訪問控制:

class MyClass1 {
    use HelloWorld { sayHello as protected; }
}
class MyClass2 {
    use HelloWorld { sayHello as private myPrivateHello; }
}

trait能夠互相引用:

trait HelloWorld {
    use Hello, World;
}

trait一樣支持抽象方法:

trait Hello {
    public function sayHelloWorld() {
        echo 'Hello'.$this->getWorld();
    }
    abstract public function getWorld();
}

trait不能定義static 變量,trait定義的靜態方法,使用trait的類能夠用。

trait定義了屬性以後,類不能定義一樣名稱的屬性。

PHP的重載和別的語言不同,它指動態地建立屬性和方法。

屬性:

  • 在給不可訪問屬性賦值時,__set()會被調用。
  • 讀取不可訪問屬性的值時,__get()會被調用。
  • 當對不可訪問屬性調用 isset()empty() 時,__isset()會被調用。
  • 當對不可訪問屬性調用 unset() 時,__unset() 會被調用。

方法:

  • 在對象中調用一個不可訪問方法時,__call() 會被調用。
  • 用靜態方式中調用一個不可訪問方法時,__callStatic() 會被調用。

foreach能夠遍歷對象的全部可見屬性。能夠經過實現IteratorIteratorAggregate接口來指明如何遍歷。

Traversable是一個抽象接口,能夠用來檢查是否能夠被foreach遍歷:

if( !is_array( $items ) && !$items instanceof Traversable )
        //Throw exception here

使用clone關鍵字能夠複製一個對象,對象的全部屬性是淺複製。若是定義了__clone()方法,那麼複製完成會調用該方法,可用於修改屬性的值。

==屬性、屬性值、類均同。===同一對象。

PHP 5.3.0 起支持了 late static bindings,綁定的方法會調用運行時(late)首先調用該方法的類,複用了static關鍵字。

class A {
    public static function who() {
        echo __CLASS__;
    }
    public static function test() {
        static::who(); // Here comes Late Static Bindings
    }
}

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

B::test(); //  B

對象變量保存一個標識符來訪問真正的對象內容,當對象做爲參數傳遞,做爲結果返回,或者賦值給另一個變量,另一個變量跟原來的不是引用的關係,只是他們都保存着同一個標識符的拷貝,這個標識符指向同一個對象的真正內容。

全部php裏面的值均可以使用函數serialize()來返回一個字符串表示。 unserialize()函數可以從新把字符串變回php原來的值。序列化一個對象將會保存對象的全部變量,可是不會保存對象的方法,只會保存類的名字。

魔術方法以__開頭,除了上面提到的之外,還有:

  • __sleep()__wakeup(),分別對應於serialize()unserialize(),一個經常使用於提交未提交的數據,一個經常使用於執行初始化操做。
  • __toString() 方法用於一個類被當成字符串時應怎樣迴應。
  • __invoke() 當嘗試以調用函數的方式調用一個對象時調用此方法。
  • __set_state(),用於 var_export() 導出類時。

若是類實現了Serializable接口,那麼這個類就再也不支持__sleep()__wakeup()

命名空間

類、函數、常量受命名空間的影響。

經過namespace聲明,必須在全部代碼(除declare編碼語句)以前(包括非PHP代碼)。

同一個命名空間的內容能夠分割存放在不一樣文件中。

命名空間能夠分層定義:

namespace MyProject\Sub\Level;

能夠在同一文件中定義多個命名空間,可是不推薦。若是實在要這麼作,建議用大括號括起不一樣的命名空間。將全局的非命名空間代碼和命名空間的代碼組合時,必須加大括號。全局代碼用不帶名稱的namespace語句聲明。

常量__NAMESPACE__的值是包含當前命名空間名稱的字符串。關鍵字namespace可用來顯式訪問當前命名空間或子命名空間中的元素。它等價於類中的 self 操做符。

命名空間名稱或類名稱可使用別名:

namespace foo;
use My\Full\Classname as Another;

命名空間內部,用 \ 表示該名稱是全局空間中的名稱。

異常處理

使用throwcatchtry語句。

function inverse($x) {
    if (!$x) {
        throw new Exception('Division by zero.');
    }
    else return 1/$x;
}

try {
    echo inverse(5) . "\n";
    echo inverse(0) . "\n";
} catch (Exception $e) {
    echo 'Caught exception: ',  $e->getMessage(), "\n";
}

// Continue execution
echo 'Hello World';

Exception 類

Exception {
  /* 屬性 */
  protected string $message ;
  protected int $code ;
  protected string $file ;
  protected int $line ;
  /* 方法 */
  public __construct ([ string $message = "" [, int $code = 0 [, Exception $previous = NULL ]]] )
  final public string getMessage ( void )
  final public Exception getPrevious ( void )
  final public int getCode ( void )
  final public string getFile ( void )
  final public int getLine ( void )
  final public array getTrace ( void )
  final public string getTraceAsString ( void )
  public string __toString ( void )
  final private void __clone ( void )

生成器

一般只需用yield取代return

例如,用生成器從新實現低內存佔用的range()函數:

function xrange($start, $limit, $step = 1) {
    if ($start < $limit) {
        if ($step <= 0) {
            throw new LogicException('Step must be +ve');
        }

        for ($i = $start; $i <= $limit; $i += $step) {
            yield $i;
        }
    } else {
        if ($step >= 0) {
            throw new LogicException('Step must be -ve');
        }

        for ($i = $start; $i >= $limit; $i += $step) {
            yield $i;
        }
    }
}

yield能夠返回鍵值對:

function input_parser($input) {
    foreach (explode("\n", $input) as $line) {
        $fields = explode(';', $line);
        $id = array_shift($fields);

        yield $id => $fields;
    }
}

生成器函數第一次調用時,會返回一個內部的Generator類(沒法使用new實例化的類)的對象。相似於Iterator接口,可是多了一個send()方法。

Generator::send()容許迭代的時候插入值。插入的值會被yield語句返回,而且能夠在生成器函數中使用。

相比實現一個Iterator類,生成器要簡單地多,每每能提高代碼可讀性。

超全局變量

在一個腳本的所有做用域中均可用。

  • $GLOBALS
  • $_SERVER
  • $_GET
  • $_POST
  • $_FILES
  • $_COOKIE
  • $_SESSION
  • $_SESSION
  • $_REQUEST
  • $_ENV

其餘預約義變量

  • $php_errormsg (僅在 php.ini 文件中的 track_errors 配置項開啓的狀況下可用。默認關閉。)
  • $argc
  • $argv

ArrayAccess接口

實現了這一接口的類能夠當數組用。

ArrayAccess {
  /* Methods */
  abstract public boolean offsetExists ( mixed $offset )
  abstract public mixed offsetGet ( mixed $offset )
  abstract public void offsetSet ( mixed $offset , mixed $value )
  abstract public void offsetUnset ( mixed $offset )
}

Day 0 - 5 列表

相關文章
相關標籤/搜索