在開始之前,必須知道的事情

PHP Class 和 call by reference

  • PHP Class 泛指了類別(classes), 介面(interfaces), 函數(functions) 和常數(constants).
  • PHP "objects are passed by references by default". 請注意物件屬性的值會在你不注意的地方被更新到了。
  • PHP Class property 宣告沒有像 Objective-C 提供 immutale or mutale type. 或是像 Java 的 final property. 但你可以用 const 去保護你的物件屬性。
  • PHP7.1 之後,可以加上public or private 的可視性描述(visibily modifiers)針對物件的屬性。
  • 除非你很清楚你在做什麼,不然千萬不要直接對 function input的 variable做修改. Never change the input variables to a function directly.
  • 但是 PHP Array = (assign)要小心處理, 如果是存的內容為 scalar type,行為是 copy by value

一些常搞混的字詞和用法

require_once vs require

  • 盡量使用 require_once,尤其是靜態的設定檔,給PHP好的效率。

  • require vs include
    include找不到檔案只會有 warnning。 require 找不到檔案會 fatal error. 強烈建議使用require及早在開發階段發現錯誤。

字串 Single Quoted and Double

  • Single Quoted 的字串,PHP並不會去嘗試解義(evalute)變數和相關的跳脫符號Escaped characters例如: \n
  • 一般來說,如果不需要變數解義和跳脫,建議使用 Single Quoted。有文件指出這樣的效能比較好。
  • PHP String 有四種表示方法,建議閱讀PHP String官方文件

    • Single Quoted
    • Double Quoted
    • Heredoc
    • Nowdoc
  • Heredoc syntax 用 <<< 接著換行,結束一定要在 NewLine的最前面。

<?php
$str = <<<EOD
Example of string
spanning multiple lines
using heredoc syntax.
EOD;
  • 請參考範例有關 Single quoted和Double的差別:
<?php
echo 'single quote\n' . "\n";
echo "double quote\n";

$var1 = 'Hello';
$var2 = 'World!';

echo '$var1 $var2' . "\n";
echo "$var1 $var2" . "\n";

$var3 = 3;
$var4 = 4;

echo '$var3 + $var4 = ' . "$var3 + $var4 = " , $var3 + $var4, "\n";

Output:

https://gyazo.com/aa27cec95a616255c902833abbf5d8db

scalar types 值量型別

  • PHP scalar types : 整數(integer), 浮點數(float), 字串(string) and 布林(boolean).
  • Not scalar types : 陣列(array), 物件(object) 和 資源( resource).
  • is_scalar(mixed $var)可以幫忙判斷。
  • echo不能印出非scalar types內容,例如 array 會得到這樣的訊息:PHP Notice: Array to string conversion

  • 請參考範例

<?php
$var1 = 'This is a string'; // scalar: string
$var2 = 3.14; // scalar: float
$var3 = 5; // scalar: int
$var4 = false; // scalar: boolean
$var5 = array('aaa', 'bbb', 3, 3.14);

function customPrintVar($var)
{
    if (is_scalar($var)) {
        echo "\n === scalar type ===";
        echo $var;
    } else {
        echo "\n === not scalar type ===";
        var_dump($var);
    }
}

// Use {} input dynamic variables
for ($i=1; $i < 6; $i++) {
    customPrintVar(${'var'.$i});
};

echo() vs print() vs var_dump() vs print_r() vs var_export()

echo() and print()

  • echoprint 只支援字串的輸出,echo 和 print 並不是 function,他是PHP原生支援(language construct),所以可以不用()
  • echo 和 print 的差別在於 echo 支援多個 inputs 以及回傳型別 echo 回傳 void,print 永遠回傳 1。

  • 請參考範例

<?php
print("Hello World");

print "print() also works without parentheses.";

print "This spans
multiple lines. The newlines will be
output as well.";

echo "echo() also works
multiple lines. The newlines will be
output as well.";

// Strings can either be passed individually as multiple arguments or
// concatenated together and passed as a single argument
echo 'This ', 'string ', 'was ', 'made ', 'with multiple parameters.', chr(10);
echo 'This ' . 'string ' . 'was ' . 'made ' . 'with concatenation.' . "\n";
  • 注意: echo 支援多字串的輸入,和單一用點連字串。所以parentheses的使用要注意,例如下面的範例:
echo "======== multiple arguments vs parentheses with concatenated ===== \n";

echo "Sum: ", 1 + 2;
echo "Hello ", isset($name) ? $name : "John Doe", "!";

echo 'Sum: ' . (1 + 2);
echo 'Hello ' . (isset($name) ? $name : 'John Doe') . '!';
  • 注意: 如果 $stringA 和 $stringB 是非常大的字串echo $stringA, $stringB效能遠超過字串連接。因為用字串連接需要產生額外的記憶體( extra temp memory)。

  • 注意:因為 echo 和 print 並不是 function,所以並不支援 PHP variable functions的特性。

  • 注意:常用的原生支援(language construct)還包含 echo, print, unset(), isset(), empty(), include, require等等。

  • 注意:因為echo並不是 function,所以不能放在 ?: ternary operators內使用。但是 print 可以。請參考下面範例 DemoOutput

$some_var = 1;
// Because echo does not behave like a function, the following code is invalid.
($some_var) ? echo 'true' : echo 'false';

// However, the following examples will work:
($some_var) ? print 'true' : print 'false'; // print is also a construct, but
                                            // it behaves like a function, so
                                            // it may be used in this context.
echo $some_var ? 'true': 'false'; // changing the statement around

var_dump vs var_export and print_r

  • var_dump, print_r, 和 var_export 都是為了 debug 使用。

    • var_dump會顯示PHP的型別資訊
    • var_export只會顯示合法的 PHP code。
    • print_r 顯示容易閱讀的結果。
  • 注意: print_r的輸出結果,有時會造成空字串boolean的誤判,強烈建議使用 var_dump or var_export。可以參考下列的範例stackoverflow

$demoArray = array('', false, 42, array('42'));

// var_dump(array('', false, 42, array('42')));
echo "\n ==== var_dump ==== \n";
var_dump($demoArray);

echo "\n ==== var_export ==== \n";
var_export($demoArray);

echo "\n ==== print_r ==== \n";
print_r($demoArray);

https://gyazo.com/80036aa3e116f56aa04ac5a7e85eca92

  • var_dump可以多的變數輸出,其function 回傳值為 void
$var1 = 1;
$var2 = 2.0;
$var3 = array($var1, $var2, 3.14);

echo "\n ==== var_dump multi-arguments ==== \n";
var_dump($var1, $var2, $var3);

https://gyazo.com/0f3345d72f83754e683f409c8dd107f2

  • var_exportprint_r可以將輸出的結果用變數儲存,而不直接 output。var_export輸出為valid PHP code,這是意味著輸出可以之後給eval()執行。 請參考下列的範例 VarExport
<?php
namespace StudyGroup\LanguageFeatures\PHPClass;

class DemoVarExport
{
    public $var1;
    public $var2;

    public static function __set_state($an_array)
    {
        $obj = new DemoVarExport;
        $obj->var1 = $an_array['var1'];
        $obj->var2 = $an_array['var2'];
        return $obj;
    }
}

$a = new DemoVarExport;
$a->var1 = 5;
$a->var2 = 'TestingString';

echo "\n === var_export === \n";
var_export($a);

echo "\n ==== var_export to a string ==== \n";
$evalStringForClassA = var_export($a, true);

// generate $b use eval string
// Notes: must implement __set_state method in VarExportDemo class. Without that, got the error
// Fatal error: Uncaught Error: Call to undefined method StudyGroup\LanguageFeatures\PHPClass\VarExportDemo::__set_state()

eval('$b = ' . var_export($a, true) . ';');
echo "\n ==== var_dump evaled ClassB ==== \n";
var_dump($b);

//comparison operator (==), object variables are compared in a simple manner, namely: Two object instances are equal if they have the same attributes and values (values are compared with ==), and are instances of the same class.
// Notes: use single quote '' because we want to print $a=$b string.
echo "\n" . '$a==$b' . "\n";
echo $a == $b ? true : false; // output will be true
echo "\n";

Output Screen:
https://gyazo.com/cefa82ac302e80efcb4ff82cd43c4087

  • 注意:上面的例子比較好的方式用 serialize()unserialize() 去保存和還原 Objects,更複雜的情況可以搭配 magic methods: __sleep()__wakeup()

  • 注意: eval() 會有安全性的問題,尤其是執行使用者所輸入的資料。記住下面PHP之父的話:

If eval() is the answer, you're almost certainly asking the
wrong question. -- Rasmus Lerdorf, BDFL of PHP

define() vs const 常數定義

如果你嘗試在 class 內 function scope 外使用 define() 你會得到 PHP Parse error: syntax error, unexpected 'define' (T_STRING), expecting function (T_FUNCTION) 的錯誤訊息。
也就是,你不能寫這樣的代碼

<?php
namespace StudyGroup\LanguageFeatures\PHPClass;

class DemoImmutable
{
    define('ANIMALS', array('dog', 'cat', 'bird'));
    function myFunction() {
    }
}

最主要的原因是底層的不同

  • define() 是 run-time constants 而 const 是 compile-time constants.
  • define() 是 global scope 或者在某個 namespace,所以不能用來定義 class-scope 的常數。
  • define()可以用在 if() 但 const不能用在 if()

PHP7 array const 可以用 define() or const 來定義。但array的內容只能 scalar data (boolean, integer, float and string)。
可以參考下列的程式碼

<?php
namespace StudyGroup\LanguageFeatures\PHPClass;

const TAIPEI_ID = 1;
define('StudyGroup\LanguageFeatures\PHPClass\TAIWAN_ID', 2);

echo \StudyGroup\LanguageFeatures\PHPClass\TAIPEI_ID . "\n";  // 1
echo \StudyGroup\LanguageFeatures\PHPClass\TAIWAN_ID . "\n";  // 2; note that we used define(), but the namespace is still recognized

// define a constant as a scalar expression
define('TRANSPORT_METHOD_SNEAKING', 1 << 0); // OK!
const TRANSPORT_METHOD_WALKING = 1 << 1; // OK!
// Next, conditional constants.
define('HOBBITS_FRODO_ID', 1);

if (HOBBITS_FRODO_ID==1) {
    define('TRANSPORT_METHOD', TRANSPORT_METHOD_SNEAKING); // OK!
    echo TRANSPORT_METHOD . "\n"; // 1
    // const PARTY_LEADER_ID = HOBBITS_FRODO_ID // Compile error: const can't be used in an if block
}

// Final, Class constant
class DemoImmutable
{
    const ANIMALS = array('dog', 'cat', 'bird');
    //define('VEHICELS', array('moto', 'bus')); // Error. define can't use in class scope
}

var_dump(DemoImmutable::ANIMALS);

可以參考這篇stackoverflow

  • 注意:define宣告不能用 hyphens -,當需要echo這變數時,會變成字串的減法。請參考範例
<?php
define('VERSION-DESC', 'Version 1.0');
define('VERSION_DESC', 'Version 1.0');

echo "=== define use hyphens ===\n";
echo VERSION-DESC, "\n";
echo "=== define with under score ===\n";
echo VERSION_DESC, "\n";

output

0
Version 1.0

https://gyazo.com/c9d9158025b1802f8b81b55201ae7cd3

Variable variables 和 Variable functions

final, static, and const

  • 作用範圍
Scope final static const
Class X
Methods X X
Properties X X
Variables X

PHP Operators

這邊列出PHP特有的 Operators,是在其他語言比較少見到的:

  • arrow operator ->
  • Scope Resolution Operator or double colon ::
  • Spaceship <=>
  • Type operator instanceof

一個好的 if (To be if free)

  • 不要回傳 null,應該要回傳一個空的 list object []

    Never return a null, instead return a Null Object, i.e an empty list.

  • 不要傳 error codes,應該要用 Exception。

    Don't return error codes, instead throw an Exception (Runtime please!)

results matching ""

    No results matching ""