PHP變數和函數的特異功能

動態變數 Variable variables

剛接觸PHP的人一定會覺得很奇怪,會什麼變數(variables)前面都要帶$為什麼不像 java 或者其他語言,變數名直接拿來用呢?
後來才知道 PHP 支援 Dynamic variables動態變數 i.e variable variables的功能。

例子:

<?php
$hello = 'world';
$world = 'hello';

echo $$world . "\n"; //output: world

PHP 會把 ${$world} 的值拿出來替換,因此變數成為 $hello,所以 output就是 'world' 字串。但太多的$...$轉換會造成代碼理解的困難。

請不要寫出下列的代碼:

https://gyazo.com/1d18148f050a9b03e7d62bc7577bb937

後面維護的人員應該會想罵人吧~~

何時使用動態變數

  • for-loop 中最常使用到動態變數,例如下面的例子
<?php
// price name list
$priceNameList = array('Original', 'VIP', 'Employee');

// price list
$priceList = array(300, 200, 100);
$total = count($priceList);
// dump priceList to meaningful variable name;
for ($i=0; $i < $total; $i++) {
    ${'price'.$priceNameList[$i]} = $priceList[$i];
}

echo 'oringial price: ' . $priceOriginal . "\n";

這樣就可以將變數的名稱做有意義的命名,當然也可以透過 array key value的方式做到。

$priceDictionary = array("Original" => 300,
                         "VIP" => 200,
                         "Employee" => 100);
foreach ($priceDictionary as $key => $value) {
    ${'price'.$key} = $value;
}
echo 'demo 2: oringial price: ' . $priceOriginal . "\n";

更進階的方法,PHP中提供了一個很特別的函式extract(),只要一行就可以做到我們的需求:

extract($priceDictionary, EXTR_PREFIX_ALL, "price");
echo 'demo 3: oringial price: ' . $price_Original . "\n";

這裡需要特別注意的地方是,extract()參數,預設值是 EXTR_OVERWRITE,會把既有變數的值覆蓋。另外 EXTR_PREFIX_ALL 變數會有 _ i.e $price_Original 而不是 $priceOriginal

有關extract()參數請參考 extract manual

動態函式 Variable functions

這也是PHP中神奇的功能,當變數後面接著parentheses(),PHP編譯程式會去試著執行這函式。

但PHP原生功能(language constructs) 像是 echo, print, unset(), isset(), empty(), include, require等等,動態函式不會生效。範例如下

<?php
namespace StudyGroup\LanguageFeatures\PHPClass;

class Foo
{
    public static $fun = 'static property';
    public static function fun()
    {
        echo 'Method fun called' . "\n";
    }
    public function hello()
    {
        echo 'Hello world!' . "\n";
    }
}

echo Foo::$fun . "\n"; // This prints 'static property'. It does need a $fun in this scope.
$fun = 'fun';
Foo::$fun();  // This calls $foo->fun() reading $fun in this scope.

Output: https://gyazo.com/13a6760ecec4b54a7b9e301dec724e0e

Namespaces 和 動態語言一起使用

如果變數後面接著parentheses(),前面也有 new 時,PHP 會嘗試去生成物件,如下面的程式碼

<?php
namespace StudyGroup\LanguageFeatures\PHPClass;

class Foo
{
    public static $fun = 'static property';
    public static function fun()
    {
        echo 'Method fun called' . "\n";
    }
    public function hello()
    {
        echo 'Hello world!' . "\n";
    }
}

$className = __NAMESPACE__ . '\\' . 'Foo'; // need to add name space
$methodName = 'hello';
$myFoo = new $className();
$myFoo->$methodName();

請注意:一定要指定 NAMESPACE 即使PHP Class宣告在同一個檔案內。不然會得到下面的Fatal Error錯誤訊息:

Fatal error: Uncaught Error: Class 'Foo' not found in /Users/user/Dev/PHP7StudyGroup/src/LanguageFeatures/PHPClass/DemoVariableFunctions.php:24

主要的原因是當使用動態變數Variable functions沒有加上Namespace時,PHP會找Global的class。請參考

https://gyazo.com/f45bfd40b54c92b03824ff470995495f

results matching ""

    No results matching ""