2017年4月10日 星期一

public vs protected vs private比較

        這是在php裡,最常看到三種宣告function的方式。

        下面用code做個簡單解說:

class Test
{
    public function public_function()
    {
        echo 'I am public function!';
    }

    protected function protected_function()
    {
        echo 'I am protected function!';
    }

    private function private_function()
    {
        echo 'I am private function!';
    }
}

$test = new Test();

$test->public_function();


       這三個宣告方式,如果要在class外面使用的話,只有public可以,因為public意思就是公眾化的,開放的,大家都可以任意取用的。

       而protected則是要透過parent class的用法,也就是extends就能調用了:

class Test
{
    public function public_function()
    {
        echo 'I am public function!';
    }

    protected function protected_function()
    {
        echo 'I am protected function!';
    }

    private function private_function()
    {
        echo 'I am private function!';
    }
}

class Test2 extends Test
{
    public function call_parents_function_protected()
    {
        $this->protected_function();
    }
}


$test = new Test();

$test->public_function();

$test2 = new Test2();

$test2->call_parents_function_protected();


        像這樣的方式,就能成功調用了!

        至於private在所處的class裡面才能調用:

class Test
{
    public function public_function()
    {
        echo 'I am public function!';
    }

    protected function protected_function()
    {
        echo 'I am protected function!';
    }

    private function private_function()
    {
        echo 'I am private function!';
    }

    public function call_in_same_class()
    {
        $this->private_function();
    }

}

$test = new Test();

$test->call_in_same_class();

        這樣就行了!

        總結來說,public大家都能取用,protected則是父類別才能使用,private則是只能在宣告function的class裡面使用。



        參考資料:

http://stackoverflow.com/questions/4361553/what-is-the-difference-between-public-private-and-protected


2017年3月29日 星期三

__call()的妙用

        php有個magic method叫__call(),寫法是這樣的:

class Demo
{
    public function __call($function , $args)
    {
        echo 'function: *' . $function . '* don\'t exist!';
    }
}

(new Demo)->target();



        __call的兩個參數可以任意取名,只要確定是兩個就好。

        當呼叫的target不存在,class Demo就會轉為呼叫__call(),讓開發者可以去設定如果function呼叫不到的時候做的事情,以上面的code執行下來,結果會是:

function: *target* don't exist!

        當沒有建立__call()的時候,會出現報錯:

Fatal error: Call to undefined method Demo::target() in /Users/Hong/php/test/test.php on line 11

        這裡有個今天讀code剛學到的小技巧:

class Animal
{
    public function __call($function , $args)
    {
        if ($function == 'dog') {
            $this->bark();
        } elseif ($function == 'cat') {
            $this->meow();
        }
    }

    private function bark()
    {
        echo 'bark!';
    }

    private function meow()
    {
        echo 'meow!';
    }
}

(new Animal)->dog();



        假設今天不確定動物的叫聲,這裡只需要呼叫動物的種類當作function name,然後因為Animal class找不到該function name,所以會呼叫__call(),__call()拿到之後就可以根據該function name去做對應的動作。

        注意到了嗎?本來應該是找不到function name做的預防措施,這邊卻反過來利用了這個特性,故意讓class找不到該function name,然後做統一分發。

        所以如果運用到API的溝通部分就是,先看看$_SERVER['REQUEST_METHOD']進來的是什麼,GET,POST,PUT?接著再從__call()統一分發到對應的function去呼叫後端API,達到整合的作用。

        寫code真的是一門永遠無法精通的學問,就算把單一語言的特性跟用法用得滾瓜爛熟,但永遠都會有更出其不意,或是更聰明的方式去完成任務,這次的__call()反其道而行的用法著實讓我大開了眼界。


參考資料:

http://php.net/manual/en/language.oop5.overloading.php#object.call





2017年3月28日 星期二

error_reporting 與 display_errors 區別

        當安裝好php,並開始coding的時候,有時候會看到頁面報錯:


        或是看到有warning,但頁面依然正常執行:


        身為開發人員,看著報錯上的提示去debug是很重要的,但有時候已經到了demo階段,頁面上有的報錯還來不及解決,在漂亮的UI上如果出現幾行Notice,會嚴重影響美觀以及客戶對系統的第一印象,這時候便需要對報錯的機制做一些調適。

        在mac安裝好php之後,會有一個php.ini的參數配置檔,php在server上運行就是靠這個配置檔,我是用brew安裝的,php.ini路徑在/usr/local/etc/php/x.x/php.ini,根據版本的不同再去更改x.x就好。

        預設的配置為:



        可以看到,php.ini在不同的環境下有不同的建議配置。

        display_errors在開發的時候,建議用On,但是正在線上運行的專案則是Off,開發的時候秀出錯誤,盡可能方便掌握系統的狀況,而在線上環境的時候,保持頁面的整潔,不出現抱錯or程式碼。

        error_reporting有很多種配置方式,在php.ini裡都有很好的說明,而~則是代表不包含,例如E_ALL & ~E_DEPRECATED & ~E_STRICT就是秀出所有error,但除了E_DEPRECATED以及E_STRICT,這點在php.ini裡也有解釋。

        但error_reporting以及display_errors到底差在哪?

        display_errors意思是要不要秀到頁面上,也就是一開始的兩張圖片,Notice和Parse error。

        error_reporting則是決定要秀什麼到頁面上,全秀?還是把一些訊息先排除?


        display_errors:要不要秀?

        error_reporting:要秀什麼?




2017年2月5日 星期日

laravel 1071 Specified key was too long; max key length is 767 bytes 解決方法

        laravel new 一個新專案之後,在.env用好資料庫設定,接著執行php artisan migrate的時候,拋出了兩個例外:

  [Illuminate\Database\QueryException]                                                                                                                                                 
  SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes (SQL: alter table `users` add unique `users_email_unique`(`email`))  
                                                                                                                 
  [PDOException]                                                                                                   
  SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes  

        可以看到共通點就是Specified key was too long; max key length is 767 bytes。

        因為laravel5.4用的是utf8mb4編碼,這種編碼跟默認的uft8編碼差別就在於utf8編碼最多支援到3個字節,而utf8mb4可以支援到四個字節,所以utf8mb4可以支援四個字節的emojis儲存進資料庫,mb4指的就是「most bytes 4」,而utf8mb4同時也支援許多的漢語難字。

        但在5.7.7之前的Mysql版本,以及10.2.2之前的MariaDB版本必須要手動調整預設的字串長度讓MySQL可以為他們新增索引。

        實際做法是在AppServiceProvider.php裡面加兩行程式碼:

<?php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;

// 1
use Illuminate\Support\Facades\Schema;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        // 2
        Schema::defaultStringLength(191);
    }

    /**     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //    
    }
}

        引入Schema之後再去呼叫defaultStringLength去更改預設字串長度就行了。


參考資料:


2017年2月1日 星期三

PHP else if 和 elseif 的研究

        開門見山的說,用 {} 的寫法運行起來是完全一樣的,舉例:

$a = 2;

if ($a == 1) {

} elseif ($a == 2) {

}

vs

$a = 2;

if ($a == 1) {

} else if ($a == 2) {

}

        會顯示出一樣的結果,而php在解析語法的時候,會將第二種寫法,也就是else if剖析成:

if ($a == 1) {

} else {
    if ($a == 2) {

    }   
}

        不過如果用colon的寫法則會有所不同,以php官方文件的程式碼為例:

/* Incorrect Method: */
if($a > $b):    
    echo $a." is greater than ".$b;
else if($a == $b): // Will not compile.    
    echo "The above line causes a parse error.";
endif;

/* Correct Method: */
if($a > $b):    
    echo $a." is greater than ".$b;
elseif($a == $b): // Note the combination of the words.    
    echo $a." equals ".$b;
else:    
    echo $a." is neither greater than or equal to ".$b;
endif;

         可以看到上方寫成else if分開,運行會parse error,下方連在一起的則不會。      

         psr-2的規範也說了必須連在一起:

     
        綜此上述,elseif目前是php裡判斷是的最佳選擇。

        參考資料:      
        http://www.php-fig.org/psr/psr-2/#if-elseif-else      
        http://www.php.net/manual/en/control-structures.elseif.php
        http://stackoverflow.com/questions/3662412/are-elseif-and-else-if-completely-synonymous

2016年11月29日 星期二

var、let 的scope介紹

        以往Javascript的變數宣告都用「 var 」,「 var 」屬於比較鬆散的變數宣告方式,即使在不同的地方宣告一樣的變數名稱,在瀏覽器上執行一樣不會出錯,而這個特性同時也很容易造成一些Bug,ES6出現的「 let 」就很好的補足了var的不足。

        回顧var的特性,var屬於function scope,意思就是在function裡面宣告的變數只有在function裡面才有用,不會影響到外面,同樣的,也不能從外頭取得function裡的變數。

var i = 0;

function varTest() {
    var i = 100;
}

varTest();

console.log(i);

結果:0


function varTest() {
    var i = 100;
}

varTest();

console.log(i);

∆ 想直接取得宣告變數,結果就會是:


     
        而function scope也代表只有在function裡面才算有自己的地盤,一旦沒有function包住var,那幾乎等於跟全域變數一樣了,會直接影響到外面宣告的變數。

var i = 0;

if (true) {
    var i = 50;
}

console.log(i);

        結果:50

        同樣包在大括號之間,但是像這樣的if statement沒有包覆住裡頭的var,連帶地影響到外面宣告的變數。



        而let在一開始宣告就比var嚴謹了。

let i = 0;
let i = 50;

        在這一步,瀏覽器會直接報錯:


        而相較於function scope的var,let是block scope的,意思是在任何的{大括弧}裡面,let都會被緊緊包住,不會leak到外面去。

let i = 0;

if (true) {
    let i = 50;
}

console.log(i);

        結果:0

   
        在看歐萊禮的繁體中文書的時候,javascript的宣告變數scope會翻譯成「範疇」,不過如果用更白話文的方式來表達的話就是:

        「只要宣告在xxx裡,就不會影響到別人」。

        function scope:只要宣告在function裡,就不會影響到別人。

        block scope:只要宣告在任何一個{區塊}裡,就不會影響到別人。

     







2016年10月30日 星期日

PHPConf 2016 Day1 主議程心得 people is your assets 篇 + QA心得

        give praise

        不只Josh Lockhart在topic上提到,在QA的時候Sebastian Bergmann也完全同意這個觀點,有時候工程師在忙碌中,聽到一句「 good job!」、「 nice work」的時候,其實就也夠了,在Josh寫slim的時候,其實也有很多負評,但當一些使用者不管是用email或twitter之類的跟Josh表達感謝的時候,Josh覺得完全可以取代千千萬萬的負評,從而有動力的繼續維護。

        Josh Lockhart維護的slim framework、Sebastian Bergmann維護的PHPUnit,是完全沒有得到任何薪水的,支持他們繼續維護的最大動力,就是來自人們的感謝。

        Do not punish mistake 

        犯錯時不要責備。

        Josh提到,即使是他,在NMC的時候也犯了一堆錯誤,工程師們都會犯錯,但重要的是了解犯錯的原因,在下一次的時候避免掉,而不是一昧的責備,犯錯了,針對問題修復,學起來,別再犯,繼續往前邁進。

        Don't use obviously 

        沒有「 很明顯地」這種事情,每個人都會有思考盲點,所以這才是團隊合作的價值,大家能彼此用不同的角度去解決問題,共同激發出彼此想不到的角度去切入,也許你看到另外一位工程師卡在一個地方很久,然後你一過去就看到並解決了,但這時候但這時候千萬不能說「這地方出錯的很明顯啊,你怎麼解不出來?」、「很明顯的,你似乎走神囉」。

        或許你真的比這位工程師厲害,但或許也是因為運氣好,或是思考角度不一樣,但無論如何,在這個時候用obviously會達到負面的效果。

        welcome feedback

        永遠歡迎回饋。

        無論你接到語氣多差的負評,只要裡面提供的feedback是有價值的,就要接受,認為自己的專案已經很好了是不可行的,永遠都還有更好的空間,必須要接納各種可以讓專案變得更好的意見。

        這也跟上一段一樣,如果真的有個語氣不好的工程師指出你的錯誤,也要虛心接受,畢竟我們從這位工程師身上學到了新東西,幫助我們的技術更上一層樓,所以應該要心懷感激,當然,自己除了學到新東西之外,也記得教別人的時候,態度要好一點。



        兩位大神在QA的時候著墨在上面幾項很多,而對於open source的看法卻有點不太一樣。

        Josh Lockhart說open source不是一個人可以做得起來的,slim也是信任了幾位好朋友,把一些核心開發權交給他們一起維護,所以Josh說信任非常重要,如果一直巴著不放的話,slim不會像現在一樣這麼受到歡迎,運行的這麼好。

        而Sebastian Bergmann剛好相反,如果給他重新選擇的話,可能不會這麼快交給其他人共同維護,到了後期,Sebastian在PHPUnit上維護的工作幾乎都是翻修code,讓可讀性變得更好,而這個工作非常無聊,佔用了非常多的時間而且無法全心全意開發新功能,PHPUnit內部的程式碼品質參差不齊。

        Sebastian最後說了一句:「 Could have been better. 」